你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32 TrustZone 开发HardFault调试与处理

[复制链接]
STMCU小助手 发布时间:2023-11-30 17:05
引  言1 J. }% Q1 u8 k' Q. X5 R- S
在 STM32 TrustZone 开发调试技巧的前两篇中,我们介绍了内核的 SAU/IDAU,地址的安全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障错误。ARM CM33内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及 HardFault 的调试与处理展开,供开发者参考。! x$ p, \0 `0 n6 ^
# `( B& o+ E8 [
一、CM33 TrustZone 架构下的异常模型
4 i% X3 B  O6 K5 Y. g# x' P在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。
; [/ G- X3 E& |; G% \
- B4 c! V8 T. _4 D# s
微信图片_20231130170530.png

5 I" S1 n! z) V( n) H) ^$ n9 O  q& X
1.1. Fault 异常类型(带安全扩展)5 S, x# q9 q: y5 ?( z- T% `
1.1.1. Hard Fault# D' z4 K! Q# p' t
HardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。
0 @6 X' ~0 U+ {# _3 c& o+ B8 |
0 L" F- B$ T  a3 A, f在 TrustZone 环境中,HardFault 不是 Bank 的。同一个异常,要么触发 S 侧的HardFault,要么触发 NS 侧的 HardFault。SCB 的 AIRCR.BFHFNMINS 决定了是否使能NS的BusFault,HardFault 和NMI。如果SCB 的 AIRCR.BFHFNMINS=0,HardFault 总是触发 S 侧的 HardFault Hanlder;如果 AIRCR.BFHFNMINS=1,则故障可能触发 NS 侧的 HardFaultHandler,也可能触发 S 侧的 HardFault Handler。图1 给出了在其他 Fault 未使能情况下,HardFault Handler 触发一般情形。
. S* R: [+ H7 n! a2 Y: I2 v( W2 c6 |* J' \% U: q  H

8 g0 `, `4 _7 G( d! z$ o
微信图片_20231130170527.png
% [/ w4 c4 P; t# |
' [5 T& }' o. x$ e' S' u
需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。
! j! T6 ~+ ^5 y& K* ^
1 o/ v. D8 v# L* N' b( X另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):
4 Y! z) \" U/ I3 M2 G
  1. void SECURE_SetNMIHFBFTarget(int NS)
    ( o3 o+ v1 V2 Q7 C
  2. {
      Z% [6 C% F) o* f
  3. uint32_t reg_value;# G5 C8 W5 y$ S/ M* r3 F
  4. uint32_t target = (NS==1)?1:0;
    6 G9 L: ?& @+ ^0 {4 L
  5. /* read old register configuration */
    5 s0 n' k" S& {$ o0 {) o2 a, G' S
  6. reg_value = SCB->AIRCR;
    ; ~3 ?3 q7 O5 @8 Z, c
  7. /* clear bits to change */( {! \3 h# ^) a7 w9 X8 ?7 W
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));" r$ D" c2 v7 a% c
  9. /* insert write key and target bit */) k) M- c3 {) C1 x$ ]: L* K. v" ]4 D% k
  10. reg_value = (reg_value |
    7 x7 O, Y' c& ^" q4 P
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |: e& q1 \6 u+ t7 n! V7 h
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );
    ' J5 \2 [* ]4 Q) X; i; J
  13. SCB->AIRCR = reg_value;& B" G. R* t0 `# ?  J0 g9 [
  14. }
复制代码

: D) E! C. G! `注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。9 |2 ~5 v3 Q: i
4 ^- y& t3 t1 ^, S$ ~& p

. P0 B5 g# o# H8 S  Q1.1.2. Bus Fault
( p% F3 R1 _8 k1 J/ w# R% U7 R0 z1 VBus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。
& ?+ S  X+ h, z4 `0 a
5 J$ c9 I9 M* ?: H) u# Y1 K' q
在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。
( I/ J; U7 d* r

# H) e- k1 v$ |" R9 t产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。! a# ]; K0 f4 E, k$ n

! E1 r( \  c$ p- N
微信图片_20231130170523.png
3 [7 N" t/ ^$ g6 N5 {
" o$ ?% w9 @0 ]: Q, f5 A
通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。
, i) P2 v4 r3 v! s# k: R, O) s% o5 C3 c
+ X/ {! g. [2 W; J如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。2 A; w$ w6 I2 x+ k
. q6 E: t0 X" H7 I6 B
如果 AIRCR.BFHFNMINS=1,BFAR_NS 和 BFAR_S 的值一般会读取到相同的值。通常,代码需要处理 BusFault 时,如果使用默认配置,即保持 BusFault target 到 S 侧,AIRCR.BFHFNMINS=0,则 Fault Handler 可以从 SCB_S 的 CFSR.BFSR 和 BFAR 寄存器获取总线故障信息;而如果设置了 AIRCR.BFHFNMINS=1,那么发生 Bus error 的时候,非安全侧的 Fault Handler 可以直接从 SCB_NS 的 CFSR.BFSR 和 BFAR 寄存器获取故障信息。
6 _9 f; L3 H! o2 w) j
1 c" ?$ l3 W0 q- @1 o9 ?
BusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:* Z2 z9 _  r4 [5 c; {9 L
  1. void EnableBusFault(int enable)
    0 m  K- a2 o  i, ^9 {5 Q
  2. {+ ^; ]3 o* {5 l! i6 _9 }
  3. if( enable == 1)
    9 C1 j: z9 i9 a# Z0 N" ^' P. f
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;; e3 P9 `, o; Y" ]+ ]( s8 Z
  5. else
    4 A$ T. t, F$ S( L
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);
    5 D2 t. X5 N& U
  7. }
复制代码

; |& a* a, F* `这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。8 e+ X/ N$ G4 ]3 L0 q6 r

/ i+ {. c9 J& Y% j6 H1 p6 Y* a如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。
/ A# j1 N2 A3 C( M/ l) o; L
) R! n% N. o7 i; B1.1.3. Usage Fault7 u( J4 M! @; e' U$ p$ x
UsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。
4 K. B3 }6 d! d- k" g4 y8 v+ `+ Y2 o- Z% S( a8 p2 _7 C" `
在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。
7 Q8 H' a1 l% o; {$ f5 K0 H

& L) {* Z1 R! C( I使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。
  g+ D- r& M$ t! T' ~

7 {& w9 i5 w" b另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
2 D. z4 ^# r& s4 k2 d' w" W; y/ F$ N  Q" d* E: x9 f
图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。
7 l; H% v& n4 n$ i, r% m7 \6 T* @: Z6 r. @' p7 G) ~$ u
微信图片_20231130170520.png

) J# k" t( W  l( a% L6 C: j5 I1 B
只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
( L/ _  o1 h: u) h4 H' \& K8 Q* A' w' J+ E/ t; _. j
使能或禁止 UsageFault 的示例代码如下:0 s. h9 y% p7 C4 _4 b
  1. void EnableUsageFault(int enable)
    ) i+ y1 e+ z+ v- l
  2. {: o" x  H( `1 J0 u8 `5 f
  3. if( enable == 1)# Z7 C  a$ a% d* C; D3 I5 P
  4. {: Y' \: z6 d% u. x& v7 r6 P
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;: P9 V. O& Y( j; l5 L" g1 s$ ^) R
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */
    2 f+ r8 j( D% T
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
    ; [, q4 f- |, z1 h
  8. }
    * h, Q& E1 W+ ^+ t2 B* y
  9. else& K/ Y& F8 M6 n0 j
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);" C% {) o8 H. F) ]
  11. }
复制代码
# Z# c8 u! L' n0 m; G+ _
如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。
  q' {. B# r! a9 P/ V( |/ p
  1. void EnableNSUsageFault(int enable)
    7 P/ j2 x6 s8 p+ U* B
  2. {- s2 i8 `6 ~' V5 N& ?% d
  3. if( enable == 1)
    * V( S4 w; K0 ?8 r0 p  q6 R
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;) F2 s9 }: i3 c6 Q# R. M5 K8 ^
  5. else
    $ E' `. y: y& ?
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    / C; ^2 `% J, R5 O) L) e6 R0 \
  7. }
复制代码

" B! `, P3 g+ P3 s4 u7 t$ L% y1 O1.1.4. MemManage Fault
, [0 z3 H) ]2 H3 R* D- BMemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。
! P# x( |4 B- q* G  R
2 I* O9 W$ u* p/ `MemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。
/ A3 X$ ~- z! ]8 S' L( X6 Z9 |

6 ?/ w. m, `8 c* }4 P0 |4 T) o3 N另外也与 UsageFault 类似,MemManageFault 在 S 和 NS 侧也是 Bank 的,也就是 S、NS 有各自的 MemManageFault。由于 MPU 单元本身是 Bank 的,系统中有两套 MPU 寄存器MPU_S 和 MPU_NS,因而代码在 S 和 NS 侧可以各自定义自己的 MPU region 并使用不同配置,也就是说即使对相同的地址,S/NS 两侧也可以通过各自的 MPU 单元定义不同的访问规则。MPU_S 配置的保护规则只应用于 S 安全侧代码,即控制 CPU 处于安全状态时候的访问,这与 CPU 访问的地址的在 SAU 中定义安全属性无关。而 MPU_NS 配置的保护规则只应用于NS 非安全侧代码,即 CPU 处于非安全状态时候的访问,二者互不影响。
# u% j0 ~) V% i9 Z6 V8 p' f
3 z# X* n9 A1 p图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。* a3 T* V  C5 E. M: X
微信图片_20231130170516.png

! @9 ]0 U( \+ X- z
微信图片_20231130170512.png

) p' I9 d. s# \9 o1 H  q- \* m! g, @2 x0 }6 H  x+ u* p8 Y
使能或禁止 MemManage Fault 的示例代码如下:
; y6 V$ n3 M1 q) j& R$ D6 z
  1. void EnableMemoryFault(int enable): [# m" {; |. w" G6 T, R
  2. {  ~9 s0 Z: Y1 Q
  3. if( enable == 1)( k* ?; P& z5 h$ j9 L$ A
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;4 `/ Z' z0 j8 q5 K# b
  5. else
    ' U- h( @5 V6 O7 }' ^, `6 y
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);+ m& N1 U) b* P1 ^: ^
  7. }
复制代码
7 _: I- W. O& }( O0 N
如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。
- I3 [7 h: K0 o& C! t* }
  1. void EnableNSMemoryFault (int enable)
    6 _* t/ P1 W0 ]  u% Q
  2. {
    6 n) o  X+ f7 p
  3. if( enable == 1)  r" O( M  A$ Y, ^
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
      m* F! o" A' C$ K4 I* j
  5. else% m+ O9 t' t& A: Y
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    , d7 X5 p" y0 W( \2 z7 Z
  7. }
复制代码

' P) E: d+ M+ O% i0 H- r另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。
% U4 F1 J) K! e" F/ ]% V2 v. P5 n5 C* [! X: @' n
1.1.5. Secure Fault! K3 U/ f, q* B- U3 r1 Y
Secure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。0 K# m3 l7 @& E

* t( G7 I3 {3 Y! f- d# wSecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。# Q* Z+ r7 ~) U  v
9 q' m9 J7 C, t4 B& I3 T" O7 ?& T
微信图片_20231130170508.png
2 C5 p3 F$ g3 ~1 _9 f; y. u5 Z! S+ J
微信图片_20231130170459.png

- D2 ^& L0 \) V% F# V8 @. u4 D! ~, [4 J6 V) b: a- }- ?) T7 B1 w
使能或禁止 SecureFault 的示例代码如下:
/ B" e+ ?* C' o6 u4 ?
  1. void EnableSecureFault(int enable)
    3 L8 P3 a7 m8 F" \
  2. {# E5 m+ ^" p3 t: T: G: n; h2 G1 X
  3. if( enable == 1)( q$ L3 L. ~$ ?3 I# t
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;
    . r6 p; W  x6 ]2 X
  5. else
    0 ^1 ]" o( g1 a9 l% o7 D  I# e
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);) @& \! d" S4 H3 Q- e
  7. }
复制代码
6 l3 p; B' f  `* Q$ `% z
1.2. 故障升级与 HardFault
: v; u1 u$ b6 i除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。: ^0 k0 |" S/ S# D( |' w7 j7 S) `
5 C  s. ?0 Z5 y
某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。
+ s6 M" K, e  Z  O8 l$ L( C某个 Fault 升级成 HardFault 可能有多种原因,例如:
6 @4 s# q2 Y5 s) X4 N该故障 Fault 没有使能;: q$ o7 d- v; a0 ?) Q

7 B; @7 C- Q3 M例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.3 x: q9 ]: ^6 o: _6 K0 Y
该故障的 FaultHandler 优先级不够高无法运行;: ?  j0 B4 m6 o9 \
* _2 b7 \- {7 m$ h# V
例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。
& s6 ~& l  x: ~在故障的 FaultHandler 中产生了同样的故障;2 n; @8 t. _0 c+ T* U; ]

) G8 Z3 |& W$ d- y例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。& a4 I% S( v+ A  z$ R
如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。
/ G$ W  W1 p7 d0 I5 C' n/ [/ k只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。  Q( p+ {% z% ]9 J% J) z. z
在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。9 w& e" @( Z0 R4 F0 B
" L3 l& y" Z/ i- C' a
1.3. Fault 异常的安全状态
* ^: f7 Y* B, M在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。
/ A3 i0 i5 C0 T, I3 N1 q  B关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。
9 I+ f" k9 v( B+ I  x3 `: }/ Q  _  ]/ X# Q: L' h
微信图片_20231130170455.png
4 h* S5 ]2 e8 J: v9 x

& {, A5 z7 M/ ]8 R" D1.4. 异常的进入与返回
( s- f) R( B  j1.4.1. 异常的进入与 stack frame
# X: K2 o- ^$ i$ o. ?" b9 `当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。
7 p" `5 y$ a1 i6 Q+ x/ Y1 ?当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。/ c% z6 \# Y7 I" u
通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。
) g' u, z/ g7 k1 f0 ~' `& k$ @9 C如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。/ s1 M& @) b: f$ v6 g
进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。5 k: x6 D9 z9 b+ \: ~9 D( f

4 s( \+ J, E+ p# \* x

* V6 f+ g: S# v- e# _" `. i$ M( N& R转载自: STM32
: `/ F* ^6 v, L4 M如有侵权请联系删除' ~' q9 p% H2 Y# F( ~7 k' Q

2 ?) ~7 D6 d% ]9 y1 C. v" J

+ Y+ P8 V  b' t" W2 v2 c- G0 Z. z0 X! f& h  V
收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版