Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 1 | /* |
Mikael Olsson | b96537f | 2024-05-21 09:39:47 +0200 | [diff] [blame] | 2 | * SPDX-FileCopyrightText: Copyright 2021-2022, 2024 Arm Limited and/or its affiliates <open-source-office@arm.com> |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 3 | * SPDX-License-Identifier: Apache-2.0 |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the License); you may |
| 6 | * not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
| 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | /**************************************************************************** |
| 19 | * Includes |
| 20 | ****************************************************************************/ |
| 21 | |
| 22 | // Ethos-U |
| 23 | #include "ethosu_driver.h" |
| 24 | |
| 25 | // Trustzone defines and MPC driver |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 26 | #include "../common/secure_entries.hpp" |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame] | 27 | #include "mpc_sie_drv.h" |
| 28 | #include "trustzone.h" |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 29 | |
| 30 | #include "inference_process.hpp" |
| 31 | |
| 32 | // System includes |
| 33 | #include <arm_cmse.h> |
| 34 | #include <inttypes.h> |
| 35 | #include <stdio.h> |
| 36 | |
| 37 | using namespace std; |
| 38 | |
| 39 | funcptr_ns nonsecure_result_checker = 0; |
| 40 | |
| 41 | /**************************************************************************** |
| 42 | * InferenceJob |
| 43 | ****************************************************************************/ |
| 44 | |
| 45 | #define TENSOR_ARENA_SIZE 0xa0000 |
Jonny Svärd | f521be9 | 2021-03-01 14:35:49 +0100 | [diff] [blame] | 46 | __attribute__((section(".bss.tensor_arena"), aligned(16))) uint8_t TFLuTensorArena[TENSOR_ARENA_SIZE]; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 47 | |
| 48 | InferenceProcess::InferenceProcess inferenceProcess(TFLuTensorArena, TENSOR_ARENA_SIZE); |
| 49 | |
| 50 | /**************************************************************************** |
| 51 | * Functions |
| 52 | ****************************************************************************/ |
| 53 | |
| 54 | namespace { |
| 55 | |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 56 | #include "input.h" |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame] | 57 | #include "model.h" |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 58 | #include "output.h" |
| 59 | |
| 60 | } // namespace |
| 61 | |
| 62 | #define N_MEM_RANGES (2) |
| 63 | static int setup_sram0_mpc(const uint32_t baseaddr_s, /* Secure base address */ |
| 64 | const uint32_t len_s, /* Length (in bytes) of secure region */ |
| 65 | const uint32_t baseaddr_ns, /* Non-secure base address */ |
| 66 | const uint32_t len_ns) /* Length (in bytes) of non-secure region */ |
| 67 | { |
| 68 | const char *mem_name = "SRAM0"; |
| 69 | |
| 70 | /* Secure range */ |
Jonny Svärd | ce05c41 | 2021-08-27 17:54:54 +0200 | [diff] [blame] | 71 | const struct mpc_sie_memory_range_t mpc_range_s = {/* base */ SRAM0_BASE_S, |
| 72 | /* limit */ SRAM0_BASE_S + SRAM0_SIZE - 1, |
| 73 | /* range_offset */ 0, |
| 74 | /* attr */ MPC_SIE_SEC_ATTR_SECURE}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 75 | |
| 76 | /* Non secure range */ |
Jonny Svärd | ce05c41 | 2021-08-27 17:54:54 +0200 | [diff] [blame] | 77 | const struct mpc_sie_memory_range_t mpc_range_ns = {/* base */ SRAM0_BASE_NS, |
| 78 | /* limit */ SRAM0_BASE_NS + SRAM0_SIZE - 1, |
| 79 | /* range_offset */ 0, |
| 80 | /* attr */ MPC_SIE_SEC_ATTR_NONSECURE}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 81 | |
| 82 | /* Consolidated ranges */ |
| 83 | const struct mpc_sie_memory_range_t *mpc_range_list[N_MEM_RANGES] = {&mpc_range_s, &mpc_range_ns}; |
| 84 | |
| 85 | /* MPC device configuration controller */ |
Jonny Svärd | ce05c41 | 2021-08-27 17:54:54 +0200 | [diff] [blame] | 86 | const struct mpc_sie_dev_cfg_t mpc_dev_cfg = {SRAM0_MPC}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 87 | |
| 88 | /* MPC device data */ |
Kristofer Jonsson | 29467e0 | 2021-11-26 16:10:43 +0100 | [diff] [blame] | 89 | struct mpc_sie_dev_data_t mpc_dev_data = {}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 90 | |
| 91 | /* MPC device itself */ |
| 92 | struct mpc_sie_dev_t mpc_dev = {&mpc_dev_cfg, &mpc_dev_data}; |
| 93 | |
| 94 | enum mpc_sie_error_t ret = MPC_SIE_ERR_NONE; |
| 95 | |
| 96 | printf("Configuring MPC for %s\n", mem_name); |
| 97 | |
| 98 | /* Initialise this MPC device */ |
| 99 | ret = mpc_sie_init(&mpc_dev, mpc_range_list, N_MEM_RANGES); |
| 100 | if (MPC_SIE_ERR_NONE != ret) { |
| 101 | printf("Error initialising MPC for %s\n", mem_name); |
| 102 | return 1; |
| 103 | } |
| 104 | |
| 105 | /* Configure the non secure region */ |
| 106 | ret = mpc_sie_config_region(&mpc_dev, baseaddr_ns, baseaddr_ns + len_ns - 1, MPC_SIE_SEC_ATTR_NONSECURE); |
| 107 | if (MPC_SIE_ERR_NONE != ret) { |
| 108 | printf("Error configuring non-secure region for %s (%d)\n", mem_name, ret); |
| 109 | return 1; |
| 110 | } |
| 111 | |
| 112 | /* Configure the secure region */ |
| 113 | ret = mpc_sie_config_region(&mpc_dev, baseaddr_s, baseaddr_s + len_s - 1, MPC_SIE_SEC_ATTR_SECURE); |
| 114 | if (MPC_SIE_ERR_NONE != ret) { |
| 115 | printf("Error configuring secure region for %s\n", mem_name); |
| 116 | return 1; |
| 117 | } |
| 118 | |
| 119 | /* Lock down the configuration */ |
| 120 | ret = mpc_sie_lock_down(&mpc_dev); |
| 121 | if (MPC_SIE_ERR_NONE != ret) { |
| 122 | printf("Error locking down MPC for %s\n", mem_name); |
| 123 | return 1; |
| 124 | } |
| 125 | |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | #define N_MEM_RANGES (2) |
| 130 | static int setup_bram_mpc(const uint32_t baseaddr_s, /* Secure base address */ |
| 131 | const uint32_t len_s, /* Length (in bytes) of secure region */ |
| 132 | const uint32_t baseaddr_ns, /* Non-secure base address */ |
| 133 | const uint32_t len_ns) /* Length (in bytes) of non-secure region */ |
| 134 | { |
| 135 | const char *mem_name = "BRAM"; |
| 136 | |
| 137 | /* Secure range */ |
Jonny Svärd | ce05c41 | 2021-08-27 17:54:54 +0200 | [diff] [blame] | 138 | const struct mpc_sie_memory_range_t mpc_range_s = {/* base */ BRAM_BASE_S, |
| 139 | /* limit */ BRAM_BASE_S + BRAM_TOTAL_SIZE - 1, |
| 140 | /* range_offset */ 0, |
| 141 | /* attr */ MPC_SIE_SEC_ATTR_SECURE}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 142 | |
| 143 | /* Non secure range */ |
Jonny Svärd | ce05c41 | 2021-08-27 17:54:54 +0200 | [diff] [blame] | 144 | const struct mpc_sie_memory_range_t mpc_range_ns = {/* base */ BRAM_BASE_NS, |
| 145 | /* limit */ BRAM_BASE_NS + BRAM_TOTAL_SIZE - 1, |
| 146 | /* range_offset */ 0, |
| 147 | /* attr */ MPC_SIE_SEC_ATTR_NONSECURE}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 148 | |
| 149 | /* Consolidated ranges */ |
| 150 | const struct mpc_sie_memory_range_t *mpc_range_list[N_MEM_RANGES] = {&mpc_range_s, &mpc_range_ns}; |
| 151 | |
| 152 | /* MPC device configuration controller */ |
Jonny Svärd | ce05c41 | 2021-08-27 17:54:54 +0200 | [diff] [blame] | 153 | const struct mpc_sie_dev_cfg_t mpc_dev_cfg = {BRAM_MPC}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 154 | |
| 155 | /* MPC device data */ |
Kristofer Jonsson | 29467e0 | 2021-11-26 16:10:43 +0100 | [diff] [blame] | 156 | struct mpc_sie_dev_data_t mpc_dev_data = {}; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 157 | |
| 158 | /* MPC device itself */ |
| 159 | struct mpc_sie_dev_t mpc_dev = {&mpc_dev_cfg, &mpc_dev_data}; |
| 160 | |
| 161 | enum mpc_sie_error_t ret = MPC_SIE_ERR_NONE; |
| 162 | |
| 163 | printf("Configuring MPC for %s\n", mem_name); |
| 164 | |
| 165 | /* Initialise this MPC device */ |
| 166 | ret = mpc_sie_init(&mpc_dev, mpc_range_list, N_MEM_RANGES); |
| 167 | if (MPC_SIE_ERR_NONE != ret) { |
| 168 | printf("Error initialising MPC for %s\n", mem_name); |
| 169 | return 1; |
| 170 | } |
| 171 | |
| 172 | /* Configure the non secure region */ |
| 173 | ret = mpc_sie_config_region(&mpc_dev, baseaddr_ns, baseaddr_ns + len_ns - 1, MPC_SIE_SEC_ATTR_NONSECURE); |
| 174 | if (MPC_SIE_ERR_NONE != ret) { |
| 175 | printf("Error configuring non-secure region for %s (%d)\n", mem_name, ret); |
| 176 | return 1; |
| 177 | } |
| 178 | |
| 179 | /* Configure the secure region */ |
| 180 | ret = mpc_sie_config_region(&mpc_dev, baseaddr_s, baseaddr_s + len_s - 1, MPC_SIE_SEC_ATTR_SECURE); |
| 181 | if (MPC_SIE_ERR_NONE != ret) { |
| 182 | printf("Error configuring secure region for %s (%d)\n", mem_name, ret); |
| 183 | return 1; |
| 184 | } |
| 185 | |
| 186 | /* Lock down the configuration */ |
| 187 | ret = mpc_sie_lock_down(&mpc_dev); |
| 188 | if (MPC_SIE_ERR_NONE != ret) { |
| 189 | printf("Error locking down MPC for %s (%d)\n", mem_name, ret); |
| 190 | return 1; |
| 191 | } |
| 192 | |
| 193 | return 0; |
| 194 | } |
| 195 | |
| 196 | /* Depending on the Cortex-M configuration the LUT for the xTGU has |
| 197 | * different size, set a maximum value to target all cases |
| 198 | */ |
| 199 | #define MAX_BLK_NBR (32) |
| 200 | void setup_xtgu_ns(uint32_t xtgu_base, uint32_t xtcm_start, uint32_t xtcm_size) { |
| 201 | struct xtgu { |
| 202 | uint32_t ctrl; |
| 203 | uint32_t cfg; |
| 204 | uint32_t reserved[2]; |
| 205 | uint32_t lut[]; |
| 206 | } *xtgu = (struct xtgu *)xtgu_base; |
| 207 | uint32_t lut_bit_mask[MAX_BLK_NBR] = {0}; |
| 208 | |
| 209 | /* Mask of the base offset of the I-/DTCM memory */ |
| 210 | xtcm_start &= 0x00ffffff; |
| 211 | |
| 212 | /* Read out xTGU configuration */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame] | 213 | uint32_t BLKSZ = 1 << (((xtgu->cfg) & 0xf) + 5); |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 214 | |
| 215 | if (xtcm_start % BLKSZ != 0) |
| 216 | printf("XTCM: start address %08x not on block size boundary\n", xtcm_start); |
| 217 | |
| 218 | if ((xtcm_start + xtcm_size) % BLKSZ != 0) |
| 219 | printf("XTCM: limit address %08x not on block size boundary\n", xtcm_start + xtcm_size); |
| 220 | |
| 221 | printf("setting up xTGU LUT for mem@%08x(%08x)\n", xtcm_start, xtcm_size); |
| 222 | |
| 223 | uint32_t xtcm_end = xtcm_start + xtcm_size - 1; |
| 224 | uint32_t xtcm_address = xtcm_start; |
| 225 | uint32_t block_idx_start = (xtcm_address / BLKSZ) / 32; |
Mikael Olsson | b96537f | 2024-05-21 09:39:47 +0200 | [diff] [blame] | 226 | uint32_t block_idx_end = 0; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 227 | |
| 228 | while (xtcm_address < xtcm_end) { |
| 229 | uint32_t block_nbr = xtcm_address / BLKSZ; |
| 230 | uint32_t block_idx = block_nbr / 32; |
| 231 | uint32_t block_bit = 1 << (block_nbr % 32); |
| 232 | |
| 233 | if (block_idx >= MAX_BLK_NBR) { |
| 234 | printf("lut bit mask too small, aborting!\n"); |
| 235 | exit(1); |
| 236 | } |
| 237 | lut_bit_mask[block_idx] |= block_bit; |
| 238 | |
| 239 | xtcm_address += BLKSZ; |
| 240 | if (block_idx != block_idx_end) |
| 241 | block_idx_end = block_idx; |
| 242 | } |
| 243 | |
| 244 | /* Commit the LUT to the xTGU */ |
| 245 | for (uint32_t i = block_idx_start; i <= block_idx_end; i++) { |
| 246 | xtgu->lut[i] = lut_bit_mask[i]; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | int setup_secure_attributes(void) { |
| 251 | int res; |
| 252 | /* Setup ITGU and DTGU to give non-secure state access to ITCM and DTCM memory. */ |
| 253 | /* NS Code */ |
| 254 | setup_xtgu_ns(ITCM_ITGU, TZ_NS_ITCM_START, TZ_NS_ITCM_SIZE); |
| 255 | |
| 256 | /* NS stack location in DTCM */ |
| 257 | setup_xtgu_ns(DTCM_DTGU, TZ_NS_DTCM_START, TZ_NS_DTCM_SIZE); |
| 258 | |
| 259 | res = setup_bram_mpc(TZ_S_BRAM_START, TZ_S_BRAM_SIZE, TZ_NS_BRAM_START, TZ_NS_BRAM_SIZE); |
| 260 | printf("BRAM MPC %s\n", res ? "Failed" : "OK"); |
| 261 | |
| 262 | /* The SRAM has an MPC for each SRAM bank. Configure the first one for non-secure accesses here. */ |
| 263 | res = setup_sram0_mpc(TZ_S_SRAM_START, TZ_S_SRAM_SIZE, TZ_NS_SRAM_START, TZ_NS_SRAM_SIZE); |
| 264 | printf("SRAM MPC %s\n", res ? "Failed" : "OK"); |
| 265 | |
| 266 | /* |
| 267 | * The IDAU is default not non-secure callable. In order for the code ram and data ram to be |
| 268 | * non-secure callable the NSCCFG (at 0x50080014) has to be configured. |
| 269 | * The register description can be found here: |
| 270 | * https://developer.arm.com/documentation/101773/0000 |
| 271 | * bit 0 : Sets NSC for 0x10000000-0x1fffffff |
| 272 | * bit 1 : Sets NSC for 0x30000000-0x3fffffff |
| 273 | */ |
| 274 | uint32_t *NSCCFG = (uint32_t *)(0x50080014); |
| 275 | *NSCCFG = 0x1; |
| 276 | printf("NSCCFG set NSC for CODE SRAM 0x10000000-0x1fffffff\n"); |
| 277 | |
| 278 | return 0; |
| 279 | } |
| 280 | |
| 281 | void boot_non_secure() { |
| 282 | /* Boot the non-secure world */ |
| 283 | typedef void (*ns_func)(void) __attribute__((cmse_nonsecure_call)); |
| 284 | ns_func NS_ResetHandler; |
| 285 | |
| 286 | printf("Setting NS MSP : 0x%x\n", *(uint32_t *)TZ_NS_START_VECTOR); |
| 287 | /* Setup non-secure stack */ |
| 288 | __TZ_set_MSP_NS(*(uint32_t *)TZ_NS_START_VECTOR); |
| 289 | |
| 290 | /* Setup non-secure reset vector */ |
| 291 | printf("Setting NS VTOR : 0x%x\n", TZ_NS_START_VECTOR); |
| 292 | SCB_NS->VTOR = TZ_NS_START_VECTOR; |
| 293 | |
| 294 | /* Enable features */ |
| 295 | #if (defined(__FPU_USED) && (__FPU_USED == 1U)) || (defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE > 0U)) |
| 296 | SCB_NS->CPACR |= ((3U << 10U * 2U) | /* enable CP10 Full Access */ |
| 297 | (3U << 11U * 2U)); /* enable CP11 Full Access */ |
| 298 | #endif |
| 299 | |
| 300 | #ifdef UNALIGNED_SUPPORT_DISABLE |
| 301 | SCB_NS->CCR |= SCB_CCR_UNALIGN_TRP_Msk; |
| 302 | #endif |
| 303 | |
| 304 | // Enable Loop and branch info cache |
| 305 | SCB_NS->CCR |= SCB_CCR_LOB_Msk; |
| 306 | __ISB(); |
| 307 | |
| 308 | /* Call cmse_ function to mark function as transition to non-secure state. */ |
| 309 | NS_ResetHandler = (ns_func)cmse_nsfptr_create(*(ns_func *)(TZ_NS_START_VECTOR + 4U)); |
| 310 | printf("Setting NS_ResetHandler to: %p\n", NS_ResetHandler); |
| 311 | |
| 312 | /* Now we've read the NS memory, setup our secure world compartment. */ |
| 313 | setup_secure_attributes(); |
| 314 | |
| 315 | /* Enable SAU, we are ready to jump to non-secure. */ |
| 316 | SAU->CTRL = 1; |
| 317 | |
| 318 | printf("Leaving secure world.\n"); |
| 319 | /* Leave secure state. */ |
| 320 | NS_ResetHandler(); |
| 321 | } |
| 322 | |
| 323 | int main() { |
| 324 | int ret = -1; |
| 325 | printf("Secure main starting up.\n"); |
| 326 | SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk; |
| 327 | |
| 328 | SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | |
| 329 | SCB_SHCSR_SECUREFAULTENA_Msk; // enable Usage-/Bus-/MPU-/Secure Fault |
| 330 | |
| 331 | boot_non_secure(); |
| 332 | |
| 333 | printf("We're back in secure world!\n"); |
| 334 | |
| 335 | if (nonsecure_result_checker != 0) { |
| 336 | ret = nonsecure_result_checker(); |
| 337 | } |
| 338 | |
| 339 | return ret; |
| 340 | } |
| 341 | |
| 342 | /**************************************************************************** |
| 343 | * Secure gateway functions to be callable from non-secure world |
| 344 | ****************************************************************************/ |
| 345 | |
| 346 | uint8_t outputData[1001] __attribute__((aligned(4), section("output_data_sec"))); |
| 347 | |
| 348 | int run_inference(void) { |
| 349 | vector<InferenceProcess::DataPtr> input; |
| 350 | input.push_back(InferenceProcess::DataPtr(inputData, sizeof(inputData))); |
| 351 | |
| 352 | vector<InferenceProcess::DataPtr> output; |
| 353 | output.push_back(InferenceProcess::DataPtr(outputData, sizeof(outputData))); |
| 354 | |
| 355 | vector<InferenceProcess::DataPtr> expected; |
| 356 | expected.push_back(InferenceProcess::DataPtr(expectedData, sizeof(expectedData))); |
| 357 | |
Kristofer Jonsson | 5410db1 | 2022-01-27 17:39:06 +0100 | [diff] [blame] | 358 | InferenceProcess::InferenceJob job( |
| 359 | "secure", InferenceProcess::DataPtr(networkModelData, sizeof(networkModelData)), input, output, expected, 512); |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 360 | |
| 361 | bool failed = inferenceProcess.runJob(job); |
| 362 | printf("Status of executing the job: "); |
| 363 | printf(failed ? "failed\n" : "success\n"); |
| 364 | |
| 365 | return failed; |
| 366 | } |
| 367 | |
| 368 | extern "C" int __attribute__((cmse_nonsecure_entry)) run_secure_inference(void) { |
| 369 | return run_inference(); |
| 370 | } |
| 371 | |
| 372 | extern "C" void __attribute__((cmse_nonsecure_entry)) nonsecure_print(const char *p) { |
| 373 | // Printing from non-secure, create RED ouput |
| 374 | printf("\033[31;1m"); |
| 375 | printf("NS: %s\n", p); |
| 376 | printf("\033[0m"); |
| 377 | } |
| 378 | |
| 379 | extern "C" void __attribute__((cmse_nonsecure_entry)) set_result_function(funcptr_ns callback_fn) { |
| 380 | nonsecure_result_checker = callback_fn; |
| 381 | } |