• 正文
  • 相关推荐
申请入驻 产业图谱

TrustZone工程全部中断在Non-Secure侧响应的实现示例

7小时前
130
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、背景

本文基于STM32H563 TrustZone应用工程,工程分为Secure工程和Non-Secure工程。所用系统资源的安全属性划分如下表所示:

功能需求:在TIM1更新中断中,翻转 PF4,实现LED闪烁,并通过 UART3输出相应提示字符。在TIM3更新中断中,翻PG4,实现LED闪烁,并通过 UART3输出输出相应提示字符。

将 PD1、PG0配置为外部输入中断,并在各自中断中通过UART3输出字符串。这里将要实现的就是,在不改变外设自身安全属性的前提下,如何实现全部中断在Non-Secure侧响应。

下表罗列了目前所用到的外设安全属性、各中断响应入口、实际中断服务代码所在区域以及各中断服务程序要实现的简单功能。【注:PF4 PG4分别属于Secure和NonSecure属性】

二、中断响应与中断服务程序

在TrustZone工程中,关于中断可以区分为两个层面:

2.1    中断响应

指的是中断被触发后进入哪一侧的中断向量表寻求响应,具体就是获取中断程序入口地址。例如,现在将这些TIM1_UP_IRQn、TIM3_IRQn、EXTI0_IRQn、EXTI1_IRQn 的中断响应都定位【或说路由】到Non-Secure,那么中断被触发后,CPU就进入Non-Secure 侧的中断向量表里相应IRQ Handler入口地址。

2.2    中断服务程序ISR的执行

真正完成中断服务逻辑的代码在哪一侧执行,这要看与中断程序关联的资源属于哪一侧。以本示例来看:若中断ISR关联的是Non-Secure资源,直接在Non-Secure侧执行处理即可。若中断ISR关联的是Secure资源,先通过Non-Secure的中断入口程序做转发,真正的中断处理通过NSC调用Secure侧的功能代码完成。

三、中断服务程序的处理

让所有中断都在Non-Secure响应, 并不意味着把所有中断服务代码(ISR)都写在Non-Secure工程里。下面结合本示例的具体情况来看看。

3.1    对于Non-Secure外设的中断

例如TIM3、PG0,其ISR都放在NonSecure侧处理是没有问题的。

void TIM3_IRQHandler(void){HAL_TIM_IRQHandler(&htim3);}void EXTI0_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);}

因为这些中断处理函数访问的都是Non-Secure资源。

3.2    对于Secure外设的中断

例如TIM1、PD1/EXTI1,如果在Non-Secure中做中断服务处理,比如:

void TIM1_UP_IRQHandler(void){HAL_TIM_IRQHandler(&htim1);}void EXTI1_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);}

这时就会出问题。原因是:HAL_TIM_IRQHandler(&htim1)内部还会访问TIM1的寄存器;HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1)也会访问EXTI _1寄存器等。这些都涉及Secure资源。如果在Non-Secure侧直接执行,就是从NS侧访问S侧资源,这是不允许的。

四、参考实现

4.1     Non-Secure侧负责响应全部中断

先在Secure侧运行下面代码,将所有中断响应定位到NonSecure侧。【其它写法也行】

  NVIC_SetTargetState(TIM1_UP_IRQn);  //target TIM1 to non-secure zone  NVIC_SetTargetState(EXTI0_IRQn);    //target EXTI0 (PG0) to non-secure zone  NVIC_SetTargetState(TIM3_IRQn);     //target TIM3 to non-secure zone  NVIC_SetTargetState(EXTI1_IRQn);    //target EXTI1 (PD1) to non-secure zone

将以下中断的响应入口统一放在Non-Secure侧:TIM1_UP_IRQHandler();TIM3_IRQHandler();EXTI0_IRQHandler();EXTI1_IRQHandler();另外,在S侧需要针对NS侧的UART3写几行代码:huart3.Instance = USART3;huart3.gState = HAL_UART_STATE_READY;huart3.RxState = HAL_UART_STATE_READY;huart3.Lock = HAL_UNLOCKED;目的是为了初始化 UART3 的HAL库软件状态机,让 Secure 侧能正常调用UART3相关API函数。当然,如果你直接操作寄存器应该是不用这几行的。

4.2     只涉及Non-Secure资源的中断处理

在Non-Secure侧直接处理相关中断:TIM3_IRQHandler()调用HAL_TIM_IRQHandler(&htim3)EXTI0_IRQHandler()调用HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0)

4.3     涉及Secure资源的中断处理

在Non-Secure的IRQ入口里,并不直接操作Secure外设,而是调用NSC函数,转发给Secure侧,在Secure侧执行真正的中断处理。即:TIM1_UP_IRQHandler()调用NSC函数SECURE_TIM1_UP_IrqService();EXTI1_IRQHandler()调用NSC函数SECURE_EXTI1_IrqService();这些NSC函数内部可以再调用:HAL_TIM_IRQHandler(&htim1);HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);然后可进一步触发Secure侧callback函数。

五、主要参考代码

5.1    Non-Secure侧:统一中断响应入口

在Non-Secure的stm32h5xx_it.c中,编写所有中断IRQ handler及必要代码。

void TIM3_IRQHandler(void){HAL_TIM_IRQHandler(&htim3);}void EXTI0_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);}
void TIM1_UP_IRQHandler(void){ SECURE_TIM1_UP_IrqService();}void EXTI1_IRQHandler(void){ SECURE_EXTI1_IrqService();}

5.2    Secure侧:通过NSC提供中断服务函数Secure侧不再于it.c文件中保留或编写硬件IRQ入口函数,只须在Secure侧的任一源文件中编写相应NSC服务函数,例如:

extern TIM_HandleTypeDef htim1;CMSE_NS_ENTRY void SECURE_TIM1_UP_IrqService(void){HAL_TIM_IRQHandler(&htim1);}CMSE_NS_ENTRY void SECURE_EXTI1_IrqService(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);}

注:这些CMSE_NS_ENTRY函数不是中断向量入口,只是可被Non-Secure 侧调用的Secure服务函数,最终还可以触发Secure侧HAL callback 处理。

5.3     Secure侧的callback函数

TIM1更新回调函数和EXTI1中断回调函数:


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){  if (htim->Instance == TIM1)  {    /* toggle PF4 output */    HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_4);
    uart_sync_lock();    HAL_UART_Transmit(&huart3, (uint8_t *)"TIM1 event from Securernrn", sizeof("TIM1 event from Securernrn") - 1, TimeOut);    uart_sync_unlock();  }}
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin){  if (GPIO_Pin == GPIO_PIN_1)  {      uart_sync_lock();    HAL_UART_Transmit(&huart3, (uint8_t *)"EXTI from PD1 Securernrn", sizeof("EXTI from PD1 Securernrn") - 1, TimeOut);    uart_sync_unlock();  }}

5.4     Non-Secure侧callback函数

TIM3更新回调函数和EXTI0中断回调函数:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){  if (htim->Instance == TIM3)  {    /* toggle PG4 output */    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_4);
    uart_sync_lock();    HAL_UART_Transmit(&huart3, (uint8_t *)"TIM3 event from NSrnrn", sizeof("TIM3 event from NSrnrn") - 1, TimeOut);    uart_sync_unlock();  }}
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin){  if (GPIO_Pin == GPIO_PIN_0)  {
    uart_sync_lock();    HAL_UART_Transmit(&huart3, (uint8_t *)"EXTI from PG0_NSrnrn", sizeof("EXTI from PG0_NSrnrn") - 1, TimeOut);    uart_sync_unlock();  }}

六、小结

本示例虽然实现了中断响应统一在Non-Secure侧,即所有中断请求进入Non-Secure的向量表寻求响应,但并未把所有中断的完整处理都强行塞到Non-Secure侧。

对于只需访问Nonsecure侧的中断处理,直接在NonSecure侧完成;对于Nonsecure侧需要访问Secure资源的中断服务,通过NSC转到Secure执行。

最终形成了一套既满足功能需求、又符合TrustZone安全边界的实现方案。下面截图是最终的实现输出结果,至于闪灯就无视吧,搬不过来效果。

结尾前,顺便申明下,这里所说的全部中断特指可以定位到NS的中断,并不包括那些根本不可能定位到NS侧的中断。OK,今天的分享就聊到这里,供君参考,也算是抛砖引玉,下次再聊~!

相关推荐