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