LAT1285
Local Application Tips
LAT1285 Rev 1.0 Jun. 2023
STM32 TrustZone 开发调试技巧(3—— HardFault 调试与处理
关键字:TrustZoneHardFaultSCB, AIRCRSHCSR
引言
STM32 TrustZone 开发调试技巧前两篇中,我们介绍了内核的 SAU/IDAU,地址的安
全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使
用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障
错误。ARM CM33 内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况
有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着
手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及
HardFault 的调试与处理展开,供开发者参考。
1. CM33 TrustZone 架构下的异常模
STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S NS
的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。
1. CM33 TrustZone 架构下的 Fault 异常
Exception
Number
IRQ
Number
Exception Type
优先
是否
Bank
使能
3
-13
Secure HardFault
SCB AIRCR.BFHFNMINS = 1
-3
总是使能
(NS HardFault 是否使能
取决于 SCB
AIRCR.BFHFNMINS )
Secure HardFault
SCB AIRCR.BFHFNMINS = 0
-1
HardFault
SCB AIRCR.BFHFNMINS = 0
-1
4
-12
MemoryManage
可配
默认不使能
取决于 SCB_S / SCB_NS
SHCSR.MEMFAULTENA
5
-11
BusFault
可配
默认不使能
取决于 SCB_S / SCB_NS
SHCSR.BUSFAULTENA
6
-10
UsageFault
可配
默认不使能
取决于 SCB_S / SCB_NS
SHCSR.USGFAULTENA
7
-9
SecureFault
可配
默认不使能
取决于 SCB_S
SHCSR.SECUREFAULTENA
LAT1285
LAT1285 - Rev 1.0 page 2/24
1.1. Fault 异常类型(带安全扩展)
1.1.1. Hard Fault
HardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错
误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优
先级的异常。
TrustZone 环境中,HardFault 不是 Bank 的。同一个异常,要么触发 S 侧的
HardFault,要么触发 NS 侧的 HardFaultSCB AIRCR.BFHFNMINS 决定了是否使能 NS
BusFaultHardFault NMI。如果 SCB AIRCR.BFHFNMINS=0HardFault 总是触发 S
侧的 HardFault Hanlder;如果 AIRCR.BFHFNMINS=1,则故障可能触 NS 侧的 HardFault
Handler,也可能触发 S 侧的 HardFault Handler。图 1 给出了在其他 Fault 未使能情况下,
HardFault Handler 触发一般情形。
1. HardFault Handler 的触发
需要注意的是,即使 AIRCR.BFHFNMINS=1原本 target S 侧并且上升为 HardFault
异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安
全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故
障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当
AIRCR.BFHFNMINS=1 时才有可能会被触发。
另外还要注意一点,AIRCR 寄存器不能直接修改,需要先 Key 值才能更改寄存器内容。
置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):
void SECURE_SetNMIHFBFTarget(int NS)
{
uint32_t reg_value;
uint32_t target = (NS==1)?1:0;
/* read old register configuration */
reg_value = SCB->AIRCR;
/* clear bits to change */
reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));
/* insert write key and target bit */
reg_value = (reg_value |
((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
(target << SCB_AIRCR_BFHFNMINS_Pos) );
SCB->AIRCR = reg_value;
}
注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例
如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1