TrustZone的工程中是包含2个工程文件的,安全区的工程和非安全区的工程。这两个工程是下载到不同的flash地址的。
TrustZone的工程要求从安全区的工程启动,然后在跳转到非安全区执行的。
这是因为需要在启动的时候设置安全属性,比如SAU、GTZC之类的安全外设,这些安全属性只能在安全区进行设置。因此安全区的工程下载到Flash的起始地址,0x08000000,但因为这是安全区的代码,因此实际上用的是0x08000000的别名地址0x0C000000,这2个地址实际上是同一个地址。别名区的概念在STM32F1时就出现过,当时的位带区也是别名区的一种。当安全区的工程配置好安全属性之后,就要跳转到非安全区了。非安全区的代码下载到另一个地址,比如0x08100000。当然这个地址取决于用户是如何划分Flash的区域的,这个地址是可以更改的。
int main(void)
{
/* SAU/IDAU, FPU and interrupts secure/non-secure allocation setup done */
/* in SystemInit() based on partition_stm32u575xx.h file's definitions. */
/* USER CODE BEGIN 1 */
/* Enable SecureFault handler (HardFault is default) */
SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;
/* STM32U5xx **SECURE** HAL library initialization:
- Configure the Flash prefetch
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 3
- Low Level Initialization
*/
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the System Power */
SystemPower_Config();
/* GTZC initialisation */
MX_GTZC_S_Init();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ICACHE_Init();
/* All IOs are by default allocated to secure */
/* Release them all to non-secure except PC.07 (LED1) kept as secure */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
HAL_GPIO_ConfigPinAttributes(GPIOA, GPIO_PIN_ALL, GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOB, GPIO_PIN_ALL, GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOC, (GPIO_PIN_ALL & ~(GPIO_PIN_7)), GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOD, GPIO_PIN_ALL, GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOE, GPIO_PIN_ALL, GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOF, GPIO_PIN_ALL, GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOG, GPIO_PIN_ALL, GPIO_PIN_NSEC);
HAL_GPIO_ConfigPinAttributes(GPIOH, GPIO_PIN_ALL, GPIO_PIN_NSEC);
/* Secure SysTick should rather be suspended before calling non-secure */
/* in order to avoid wake-up from sleep mode entered by non-secure */
/* The Secure SysTick shall be resumed on non-secure callable functions */
/* For the purpose of this example, however the Secure SysTick is kept */
/* running to toggle the secure IO and the following is commented: */
/* HAL_SuspendTick(); */
/*************** Setup and jump to non-secure *******************************/
NonSecure_Init();
/* Non-secure software does not return, this code is not executed */
/* Infinite loop */
while (1);
}
上面的代码是位于安全区的工程main函数,从中可以看出其启动流程是:
- 设置安全属性,包括SAU、GTZC。在GTZC中要设置SRAM的安全区地址和非安全区地址,为外设分配安全属性。
- 为非安全区分配资源,包括GPIO、中断和DMA。从下图中,可以看出在复位之后,有的外设是安全区,有的外设是非安全的。如果要在非安全的工程中使用处于安全区的外设,就要进行配置,将其分配到非安全区。例如GPIO全部位于安全区,如果在非安全区要用到UART或者GPIO,那么就要将对应的引脚分配到非安全区。
- 安全区外设的初始化,初始化在安全区使用的外设。
- 跳转到非安全区,那么如何从安全区跳转到非安全区呢?跳转函数如下所示。
#define VTOR_TABLE_NS_START_ADDR 0x08100000UL
static void NonSecure_Init(void)
{
funcptr_NS NonSecure_ResetHandler;
SCB_NS->VTOR = VTOR_TABLE_NS_START_ADDR;
/* Set non-secure main stack (MSP_NS) */
__TZ_set_MSP_NS((*(uint32_t *)VTOR_TABLE_NS_START_ADDR));
/* Get non-secure reset handler */
NonSecure_ResetHandler = (funcptr_NS)(*((uint32_t *)((VTOR_TABLE_NS_START_ADDR) + 4U)));
/* Start non-secure state software application */
NonSecure_ResetHandler();
}
这个代码和IAP的代码挺像的,都是实现了程序区的跳转。步骤如下:
- 将非安全区的中断向量表赋值给程序控制块。
- 设置使用的栈顶地址,需要注意的是内核的SP寄存器(栈顶指针寄存器)是有2个的,分别用于安全区和非安全区,所以这个实际上设置的是非安全区的栈顶指针。
- 最后跳转到非安全区的重启函数出。
从上面的内容中,可以看出STM32启动的时候先运行安全区的代码,将安全属性、外设资源等分配好,就会跳转到非安全区的main函数执行。因此代码主要执行非安全区的代码,非安全区的代码可以通过NSC函数调用安全区的函数实现两个区域的交互。