diff options
Diffstat (limited to 'applications/trustzone_inference/secure/main_secure.cpp')
-rw-r--r-- | applications/trustzone_inference/secure/main_secure.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/applications/trustzone_inference/secure/main_secure.cpp b/applications/trustzone_inference/secure/main_secure.cpp new file mode 100644 index 0000000..4c1b164 --- /dev/null +++ b/applications/trustzone_inference/secure/main_secure.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/**************************************************************************** + * Includes + ****************************************************************************/ + +// Ethos-U +#include "ethosu_driver.h" + +// Trustzone defines and MPC driver +#include "trustzone.h" +#include "mpc_sie_drv.h" +#include "../common/secure_entries.hpp" + +#include "inference_process.hpp" + +// System includes +#include <arm_cmse.h> +#include <inttypes.h> +#include <stdio.h> + +using namespace std; + +funcptr_ns nonsecure_result_checker = 0; + +/**************************************************************************** + * InferenceJob + ****************************************************************************/ + +#define TENSOR_ARENA_SIZE 0xa0000 +__attribute__((section(".bss.NoInit"), aligned(16))) uint8_t TFLuTensorArena[TENSOR_ARENA_SIZE]; + +InferenceProcess::InferenceProcess inferenceProcess(TFLuTensorArena, TENSOR_ARENA_SIZE); + +/**************************************************************************** + * Functions + ****************************************************************************/ + +namespace { + +#include "model.h" +#include "input.h" +#include "output.h" + +} // namespace + +#define N_MEM_RANGES (2) +static int setup_sram0_mpc(const uint32_t baseaddr_s, /* Secure base address */ + const uint32_t len_s, /* Length (in bytes) of secure region */ + const uint32_t baseaddr_ns, /* Non-secure base address */ + const uint32_t len_ns) /* Length (in bytes) of non-secure region */ +{ + const char *mem_name = "SRAM0"; + + /* Secure range */ + const struct mpc_sie_memory_range_t mpc_range_s = {.base = SRAM0_BASE_S, + .limit = SRAM0_BASE_S + SRAM0_SIZE - 1, + .range_offset = 0, + .attr = MPC_SIE_SEC_ATTR_SECURE}; + + /* Non secure range */ + const struct mpc_sie_memory_range_t mpc_range_ns = {.base = SRAM0_BASE_NS, + .limit = SRAM0_BASE_NS + SRAM0_SIZE - 1, + .range_offset = 0, + .attr = MPC_SIE_SEC_ATTR_NONSECURE}; + + /* Consolidated ranges */ + const struct mpc_sie_memory_range_t *mpc_range_list[N_MEM_RANGES] = {&mpc_range_s, &mpc_range_ns}; + + /* MPC device configuration controller */ + const struct mpc_sie_dev_cfg_t mpc_dev_cfg = {.base = SRAM0_MPC}; + + /* MPC device data */ + struct mpc_sie_dev_data_t mpc_dev_data = {0}; + + /* MPC device itself */ + struct mpc_sie_dev_t mpc_dev = {&mpc_dev_cfg, &mpc_dev_data}; + + enum mpc_sie_error_t ret = MPC_SIE_ERR_NONE; + + printf("Configuring MPC for %s\n", mem_name); + + /* Initialise this MPC device */ + ret = mpc_sie_init(&mpc_dev, mpc_range_list, N_MEM_RANGES); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error initialising MPC for %s\n", mem_name); + return 1; + } + + /* Configure the non secure region */ + ret = mpc_sie_config_region(&mpc_dev, baseaddr_ns, baseaddr_ns + len_ns - 1, MPC_SIE_SEC_ATTR_NONSECURE); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error configuring non-secure region for %s (%d)\n", mem_name, ret); + return 1; + } + + /* Configure the secure region */ + ret = mpc_sie_config_region(&mpc_dev, baseaddr_s, baseaddr_s + len_s - 1, MPC_SIE_SEC_ATTR_SECURE); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error configuring secure region for %s\n", mem_name); + return 1; + } + + /* Lock down the configuration */ + ret = mpc_sie_lock_down(&mpc_dev); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error locking down MPC for %s\n", mem_name); + return 1; + } + + return 0; +} + +#define N_MEM_RANGES (2) +static int setup_bram_mpc(const uint32_t baseaddr_s, /* Secure base address */ + const uint32_t len_s, /* Length (in bytes) of secure region */ + const uint32_t baseaddr_ns, /* Non-secure base address */ + const uint32_t len_ns) /* Length (in bytes) of non-secure region */ +{ + const char *mem_name = "BRAM"; + + /* Secure range */ + const struct mpc_sie_memory_range_t mpc_range_s = { + .base = BRAM_BASE_S, + .limit = BRAM_BASE_S + BRAM_TOTAL_SIZE - 1, + .range_offset = 0, + .attr = MPC_SIE_SEC_ATTR_SECURE + }; + + /* Non secure range */ + const struct mpc_sie_memory_range_t mpc_range_ns = { + .base = BRAM_BASE_NS, + .limit = BRAM_BASE_NS + BRAM_TOTAL_SIZE - 1, + .range_offset = 0, + .attr = MPC_SIE_SEC_ATTR_NONSECURE + }; + + /* Consolidated ranges */ + const struct mpc_sie_memory_range_t *mpc_range_list[N_MEM_RANGES] = {&mpc_range_s, &mpc_range_ns}; + + /* MPC device configuration controller */ + const struct mpc_sie_dev_cfg_t mpc_dev_cfg = {.base = BRAM_MPC}; + + /* MPC device data */ + struct mpc_sie_dev_data_t mpc_dev_data = {0}; + + /* MPC device itself */ + struct mpc_sie_dev_t mpc_dev = {&mpc_dev_cfg, &mpc_dev_data}; + + enum mpc_sie_error_t ret = MPC_SIE_ERR_NONE; + + printf("Configuring MPC for %s\n", mem_name); + + /* Initialise this MPC device */ + ret = mpc_sie_init(&mpc_dev, mpc_range_list, N_MEM_RANGES); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error initialising MPC for %s\n", mem_name); + return 1; + } + + /* Configure the non secure region */ + ret = mpc_sie_config_region(&mpc_dev, baseaddr_ns, baseaddr_ns + len_ns - 1, MPC_SIE_SEC_ATTR_NONSECURE); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error configuring non-secure region for %s (%d)\n", mem_name, ret); + return 1; + } + + /* Configure the secure region */ + ret = mpc_sie_config_region(&mpc_dev, baseaddr_s, baseaddr_s + len_s - 1, MPC_SIE_SEC_ATTR_SECURE); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error configuring secure region for %s (%d)\n", mem_name, ret); + return 1; + } + + /* Lock down the configuration */ + ret = mpc_sie_lock_down(&mpc_dev); + if (MPC_SIE_ERR_NONE != ret) { + printf("Error locking down MPC for %s (%d)\n", mem_name, ret); + return 1; + } + + return 0; +} + +/* Depending on the Cortex-M configuration the LUT for the xTGU has + * different size, set a maximum value to target all cases + */ +#define MAX_BLK_NBR (32) +void setup_xtgu_ns(uint32_t xtgu_base, uint32_t xtcm_start, uint32_t xtcm_size) { + struct xtgu { + uint32_t ctrl; + uint32_t cfg; + uint32_t reserved[2]; + uint32_t lut[]; + } *xtgu = (struct xtgu *)xtgu_base; + uint32_t lut_bit_mask[MAX_BLK_NBR] = {0}; + + /* Mask of the base offset of the I-/DTCM memory */ + xtcm_start &= 0x00ffffff; + + /* Read out xTGU configuration */ + uint32_t BLKSZ = 1 << (((xtgu->cfg) & 0xf) + 5); + + if (xtcm_start % BLKSZ != 0) + printf("XTCM: start address %08x not on block size boundary\n", xtcm_start); + + if ((xtcm_start + xtcm_size) % BLKSZ != 0) + printf("XTCM: limit address %08x not on block size boundary\n", xtcm_start + xtcm_size); + + printf("setting up xTGU LUT for mem@%08x(%08x)\n", xtcm_start, xtcm_size); + + uint32_t xtcm_end = xtcm_start + xtcm_size - 1; + uint32_t xtcm_address = xtcm_start; + uint32_t block_idx_start = (xtcm_address / BLKSZ) / 32; + uint32_t block_idx_end; + + while (xtcm_address < xtcm_end) { + uint32_t block_nbr = xtcm_address / BLKSZ; + uint32_t block_idx = block_nbr / 32; + uint32_t block_bit = 1 << (block_nbr % 32); + + if (block_idx >= MAX_BLK_NBR) { + printf("lut bit mask too small, aborting!\n"); + exit(1); + } + lut_bit_mask[block_idx] |= block_bit; + + xtcm_address += BLKSZ; + if (block_idx != block_idx_end) + block_idx_end = block_idx; + } + + /* Commit the LUT to the xTGU */ + for (uint32_t i = block_idx_start; i <= block_idx_end; i++) { + xtgu->lut[i] = lut_bit_mask[i]; + } +} + +int setup_secure_attributes(void) { + int res; + /* Setup ITGU and DTGU to give non-secure state access to ITCM and DTCM memory. */ + /* NS Code */ + setup_xtgu_ns(ITCM_ITGU, TZ_NS_ITCM_START, TZ_NS_ITCM_SIZE); + + /* NS stack location in DTCM */ + setup_xtgu_ns(DTCM_DTGU, TZ_NS_DTCM_START, TZ_NS_DTCM_SIZE); + + res = setup_bram_mpc(TZ_S_BRAM_START, TZ_S_BRAM_SIZE, TZ_NS_BRAM_START, TZ_NS_BRAM_SIZE); + printf("BRAM MPC %s\n", res ? "Failed" : "OK"); + + /* The SRAM has an MPC for each SRAM bank. Configure the first one for non-secure accesses here. */ + res = setup_sram0_mpc(TZ_S_SRAM_START, TZ_S_SRAM_SIZE, TZ_NS_SRAM_START, TZ_NS_SRAM_SIZE); + printf("SRAM MPC %s\n", res ? "Failed" : "OK"); + + /* + * The IDAU is default not non-secure callable. In order for the code ram and data ram to be + * non-secure callable the NSCCFG (at 0x50080014) has to be configured. + * The register description can be found here: + * https://developer.arm.com/documentation/101773/0000 + * bit 0 : Sets NSC for 0x10000000-0x1fffffff + * bit 1 : Sets NSC for 0x30000000-0x3fffffff + */ + uint32_t *NSCCFG = (uint32_t *)(0x50080014); + *NSCCFG = 0x1; + printf("NSCCFG set NSC for CODE SRAM 0x10000000-0x1fffffff\n"); + + return 0; +} + +void boot_non_secure() { + /* Boot the non-secure world */ + typedef void (*ns_func)(void) __attribute__((cmse_nonsecure_call)); + ns_func NS_ResetHandler; + + printf("Setting NS MSP : 0x%x\n", *(uint32_t *)TZ_NS_START_VECTOR); + /* Setup non-secure stack */ + __TZ_set_MSP_NS(*(uint32_t *)TZ_NS_START_VECTOR); + + /* Setup non-secure reset vector */ + printf("Setting NS VTOR : 0x%x\n", TZ_NS_START_VECTOR); + SCB_NS->VTOR = TZ_NS_START_VECTOR; + + /* Enable features */ +#if (defined(__FPU_USED) && (__FPU_USED == 1U)) || (defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE > 0U)) + SCB_NS->CPACR |= ((3U << 10U * 2U) | /* enable CP10 Full Access */ + (3U << 11U * 2U)); /* enable CP11 Full Access */ +#endif + +#ifdef UNALIGNED_SUPPORT_DISABLE + SCB_NS->CCR |= SCB_CCR_UNALIGN_TRP_Msk; +#endif + + // Enable Loop and branch info cache + SCB_NS->CCR |= SCB_CCR_LOB_Msk; + __ISB(); + + /* Call cmse_ function to mark function as transition to non-secure state. */ + NS_ResetHandler = (ns_func)cmse_nsfptr_create(*(ns_func *)(TZ_NS_START_VECTOR + 4U)); + printf("Setting NS_ResetHandler to: %p\n", NS_ResetHandler); + + /* Now we've read the NS memory, setup our secure world compartment. */ + setup_secure_attributes(); + + /* Enable SAU, we are ready to jump to non-secure. */ + SAU->CTRL = 1; + + printf("Leaving secure world.\n"); + /* Leave secure state. */ + NS_ResetHandler(); +} + +int main() { + int ret = -1; + printf("Secure main starting up.\n"); + SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk; + + SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | + SCB_SHCSR_SECUREFAULTENA_Msk; // enable Usage-/Bus-/MPU-/Secure Fault + + boot_non_secure(); + + printf("We're back in secure world!\n"); + + if (nonsecure_result_checker != 0) { + ret = nonsecure_result_checker(); + } + + return ret; +} + +/**************************************************************************** + * Secure gateway functions to be callable from non-secure world + ****************************************************************************/ + +uint8_t outputData[1001] __attribute__((aligned(4), section("output_data_sec"))); + +int run_inference(void) { + vector<InferenceProcess::DataPtr> input; + input.push_back(InferenceProcess::DataPtr(inputData, sizeof(inputData))); + + vector<InferenceProcess::DataPtr> output; + output.push_back(InferenceProcess::DataPtr(outputData, sizeof(outputData))); + + vector<InferenceProcess::DataPtr> expected; + expected.push_back(InferenceProcess::DataPtr(expectedData, sizeof(expectedData))); + + InferenceProcess::InferenceJob job( + "secure", InferenceProcess::DataPtr(networkModelData, sizeof(networkModelData)), input, output, expected, 512, std::vector<uint8_t>(4), false); + + bool failed = inferenceProcess.runJob(job); + printf("Status of executing the job: "); + printf(failed ? "failed\n" : "success\n"); + + return failed; +} + +extern "C" int __attribute__((cmse_nonsecure_entry)) run_secure_inference(void) { + return run_inference(); +} + +extern "C" void __attribute__((cmse_nonsecure_entry)) nonsecure_print(const char *p) { + // Printing from non-secure, create RED ouput + printf("\033[31;1m"); + printf("NS: %s\n", p); + printf("\033[0m"); +} + +extern "C" void __attribute__((cmse_nonsecure_entry)) set_result_function(funcptr_ns callback_fn) { + nonsecure_result_checker = callback_fn; +} |