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

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

[复制链接]
STMCU小助手 发布时间:2023-11-30 17:05
引  言; y% c: ~! R1 f; v% Z3 h
在 STM32 TrustZone 开发调试技巧的前两篇中,我们介绍了内核的 SAU/IDAU,地址的安全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障错误。ARM CM33内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及 HardFault 的调试与处理展开,供开发者参考。: e6 W) r8 e) t/ \
8 O8 I" b. r7 T, O, a" N
一、CM33 TrustZone 架构下的异常模型$ S3 e- n; n3 d/ t* Y8 B) a  ~
在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。
3 I1 G" r/ _( N/ P2 i4 U) V; ~0 d( a( O. u+ M4 y, R
微信图片_20231130170530.png

  R2 ^0 q6 f/ D7 j# d
. Q& J1 ?( m& q7 q9 F+ q# a' S% w1.1. Fault 异常类型(带安全扩展)$ [$ ^; H/ \$ E0 U( L, E9 z
1.1.1. Hard Fault
8 C- D- K; t& `* |# W' PHardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。  e- Q0 F' ^# [4 k

  b: `/ Z  W1 G在 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 触发一般情形。, `9 G% R7 Y0 Y! [% X

  k* y( k0 [2 r) e& L# P0 X' r& e* Z- I/ d. |* P$ D  z
微信图片_20231130170527.png

* X! B3 s2 g; L
& f9 s" X7 H) i  o需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。
/ T# l- Q: J$ L: d6 u' L+ R4 M1 c1 r- [
另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):
, ?  t$ d% J1 J
  1. void SECURE_SetNMIHFBFTarget(int NS)
    2 k: C" B6 _  F9 G( ^
  2. {
    % d) A  K: m2 N. W: j0 D5 |7 K) i
  3. uint32_t reg_value;
    3 j2 \5 h" x; U* w8 H% {( G. y
  4. uint32_t target = (NS==1)?1:0;  D7 g+ O6 {& G2 g
  5. /* read old register configuration */" M7 \4 f  ^0 d! J; d1 k" p6 H
  6. reg_value = SCB->AIRCR;
    ' B) q& n( r" O! C
  7. /* clear bits to change */
    ; f+ W1 ^) T& \/ G- K
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));1 R" m* m* @; f: q
  9. /* insert write key and target bit */
    ! z1 d2 m' O$ m( p) E+ }
  10. reg_value = (reg_value |
    / D  A. r$ P1 @6 [6 m# d$ l$ E% C
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
    + P5 N7 m$ F& o- |" J& N/ |
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );# o2 P" Q! U1 i, z
  13. SCB->AIRCR = reg_value;, L; `; o7 X' {6 ^7 L- s
  14. }
复制代码

3 ^, j2 n4 G  c+ x, t& l4 ]- F注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。3 w; v' b+ C- V0 p

" Z% t) ?' N8 q& q9 H1 {/ U6 R
4 v$ R6 ?% T& Y
1.1.2. Bus Fault1 z4 `) ^" ^# `" q' W+ e
Bus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。; {7 T) w$ [/ f

1 M. k( y' p( V5 I# I8 e在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。
7 s9 D; Q% H; B% Y" W
0 @/ Q5 j2 e/ y/ T; y' a; a
产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。
1 [  M6 {" ]3 {# w: `
* W! k' ]" R1 ]' r( Z) `+ ]
微信图片_20231130170523.png
5 M( v7 |. d6 M5 g8 {

+ d$ ?, |( o( z% I9 N4 j通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。
8 `( ~# t, D3 |) {- n2 V8 Z6 {% }8 }1 h" e
如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。$ Y$ z* j: [" H9 Z, t- T) D: q# R
) m+ W5 t& l) k- ~+ B2 M2 s
如果 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 寄存器获取故障信息。  s5 t4 d/ n5 [, @
! h2 A+ }: Q; x2 I5 f
BusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:
8 L7 p7 T3 h2 e( h
  1. void EnableBusFault(int enable)7 J( n5 {4 r  a; ]2 w" U
  2. {
    + t% \8 E& L+ h5 d$ X
  3. if( enable == 1)$ M7 R* l5 }7 k
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
    5 Y$ m; o, {' w2 g. x( y  T
  5. else7 B8 v( p4 d# J, |
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);7 W. j0 T* s: S$ q$ F2 L1 u# {1 h2 {
  7. }
复制代码
1 N  q8 S$ T: L' U+ G" y
这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。
2 x  w" A$ u! ~0 v7 X' Q# Y! A: R% y/ f; ^* B  F* r/ n
如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。
. M' E3 L. h2 ]2 j) Q% v* t; D! B+ i! j& k2 n. e, _2 l
1.1.3. Usage Fault
2 c6 N4 p+ z+ @UsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。! b: }: I! R/ s3 m
' f  o% [* R/ G/ E& W
在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。0 d$ \. h7 s' N; Z

% n9 T" H& j3 F9 M6 t6 G/ W使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。  V! {7 p0 Q, b0 q! M. K
. O- L7 y( @+ q1 w: b0 R
另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
8 t% J' Z9 Z  |
' ~  f0 M& I! C# a1 H% D1 {4 g3 H图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。
4 t! \+ u5 j. z; j( ?# _5 ]
" G! T6 j& J9 T: |; {
微信图片_20231130170520.png
; U* r( j1 h. v; v; D

$ I; V6 x" I  g只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。# b2 K3 K) G7 W: A
) K% p' R5 D5 J/ ]& F
使能或禁止 UsageFault 的示例代码如下:' x0 ~3 W5 I. d$ _
  1. void EnableUsageFault(int enable)
    : _3 j6 B( K. n' V- @
  2. {8 \8 B$ p  `7 d, q* L! _
  3. if( enable == 1)
    ! c7 r7 S6 P) y; h& V) Y/ j
  4. {
    ) g7 P6 G$ K6 f% v5 q  ^. U3 k; ]8 \" o" o
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    ) [1 ?: G. T+ k: r4 E
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */
      V1 N4 u+ J" Q& _/ S$ q, z
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
    . Y5 p: X" V* s
  8. }5 o( e5 T+ N7 e/ P" G/ ?, F
  9. else# G' x$ z2 T$ j
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    . C, \( L( L5 j" M" L8 M
  11. }
复制代码
2 k! b& Y) k$ w4 c& W2 F
如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。4 l1 b* P% M, Q) u
  1. void EnableNSUsageFault(int enable)
    + w! Y* |8 Q. Y$ D! ^& a" a1 g- b
  2. {
    ) y( I2 ?  ?2 R) ?$ B( q  A
  3. if( enable == 1)0 g; J6 ?9 a* X
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    * _% t% Z5 c; n8 _$ W; h
  5. else
    0 e+ R0 ]5 q- J6 r6 Y1 P
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);9 m- k, ?3 C5 p
  7. }
复制代码

2 P4 [) I) Q* Q1.1.4. MemManage Fault7 ^: A5 A% o$ [; ?, A- ]5 g7 E9 q; X
MemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。
8 s1 e$ P7 [  \8 h$ {- a
6 y! S8 n' B6 b" ~+ ~, lMemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。% N9 H; n) a8 R1 ~
4 g& ]) v$ \& i) O6 ]
另外也与 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 处于非安全状态时候的访问,二者互不影响。3 `* A' R$ D0 c7 G3 Y

' i9 j4 g' t, ^图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。# q( ~9 O& W5 E9 O' \. X
微信图片_20231130170516.png

2 J& p$ _) w% [
微信图片_20231130170512.png
8 q2 M. `; I  w" H4 v3 j

6 P, s! Z* n3 K0 w0 ]( z( V: Q' e使能或禁止 MemManage Fault 的示例代码如下:( C9 H( V4 S8 R+ t, D
  1. void EnableMemoryFault(int enable)
    + ~  C7 P$ l" I% I) B& t
  2. {7 u6 a- D: Q, g2 m9 t' ~8 @) ^9 M! Z
  3. if( enable == 1)
    % I' W' T- N4 _# ~0 a
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    6 u) ~6 T% b' V9 j7 ^
  5. else( j1 P, r+ d1 o1 B
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    # }8 p( H. ]& ]" D' l# ^1 H$ S4 g2 z
  7. }
复制代码
  R+ ?! Q& a5 P; m
如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。
8 |( j7 b* }4 _! m; \
  1. void EnableNSMemoryFault (int enable)7 P5 `+ U) H& G( K! Y' Q5 l
  2. {5 |7 M& d: [# |* M3 ^
  3. if( enable == 1)
    ' W/ L+ G/ A% Y2 s5 u0 G2 k/ ~
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;( K4 P% U" H6 T/ R; X) E8 C8 C
  5. else
    4 ?( p! t4 t7 L& ^/ S7 N; |2 b
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);0 m; r. u. W0 R* s4 ?! ~
  7. }
复制代码

$ S% }. K" n  H* X8 R另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。$ m, A% `! ]2 q$ e& H: _
( P/ q7 e0 V7 O2 z* V$ }& f
1.1.5. Secure Fault" }) V$ D( j$ A% a. Y
Secure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。
4 m: o6 X; H" S9 l1 C7 E# A9 s  P6 c5 Q% a9 c* n
SecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。
, `9 x. o/ B2 ]* F" R2 M2 j
2 Q" w" c- o1 R; i2 T5 p
微信图片_20231130170508.png
+ G, u7 u* Z( q- H
微信图片_20231130170459.png
+ m- [! v5 ^% H
( w- l& X4 @- E8 b9 ?/ D* l
使能或禁止 SecureFault 的示例代码如下:
9 V# Y; t" T% [( \& r! Q- g
  1. void EnableSecureFault(int enable)
    7 I4 ]2 t- n; L; D( _6 H
  2. {+ @' l# O8 ^; B* k& R. b
  3. if( enable == 1)
    % Z7 s6 @" H( L/ Z7 |
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;/ U$ K2 H4 \: `
  5. else
    ! A9 Q9 Q) Q) q- q1 ~
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);
    ) N* v3 j" h2 E' g3 C& h# f( n
  7. }
复制代码

3 g/ |# i2 Q" \9 B; d7 X9 J. U1.2. 故障升级与 HardFault1 y/ v% N4 _# T: Y& [1 H
除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。3 Q% u1 J2 w- g% a% f2 \+ a5 {
- I3 y/ k( b# m) b
某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。+ S% b" d$ H7 u
某个 Fault 升级成 HardFault 可能有多种原因,例如:1 @/ i- g: R: c3 C
该故障 Fault 没有使能;2 \1 E7 O9 A7 e6 o7 b) Z
$ `8 g5 x3 M. L& Q2 }# V) R
例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.# p  |; R& ?8 p5 T- r
该故障的 FaultHandler 优先级不够高无法运行;) B! Q, f  i2 j- d
9 c& H5 Y8 ~, r0 C6 e0 n
例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。! }3 G& y# P# M8 c) l
在故障的 FaultHandler 中产生了同样的故障;4 }% j5 ]. Q5 q7 g8 j3 j$ [2 x
& @; s& G* q7 O) N, E5 ~  H% s
例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。
' N2 ?* g/ _5 D; b如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。: w3 H$ ~; U& t( a6 D. u- A" f( F" F4 I
只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。
" h, `% x" O2 _: c( Q2 R在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。# a# u0 S9 Y! U$ W* d
( c  n2 H/ N) j2 ]
1.3. Fault 异常的安全状态9 p0 T. e; K4 r4 _# }8 {( k
在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。
2 H5 V0 n8 j% K. `7 C关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。
# j# \* C% A+ {; @6 s. C- l: }4 D
微信图片_20231130170455.png
6 C+ J0 p* p7 n; s2 m2 U3 H
2 e: c1 I3 `, F& {1 b; [/ ?
1.4. 异常的进入与返回" S  t) E; P3 J1 L- I
1.4.1. 异常的进入与 stack frame
. N* t: W; s7 V  r- f当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。( q. j  u' f! p
当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
" [/ a; y. c' s8 M5 w& P# b1 R/ N通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。
( z0 v: R: i; o7 b6 g% v如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。
  f# \: f* @8 _5 n2 d进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。
( x0 L$ L. @  T: B( {4 p( f0 S* J. M* o& j' O

; m- k5 L8 ^0 R6 v/ b, M$ P转载自: STM32  A+ d. X9 F1 u8 T
如有侵权请联系删除; [" I1 ], j5 F/ k6 u. C7 q

3 J0 v; t5 Q$ j3 y: z) E! p; j

3 \- y4 m+ i* Q( e( J$ f
9 Z+ T1 l. P: y9 ^' ]; T
收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版