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

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

[复制链接]
STMCU小助手 发布时间:2023-11-30 17:05
引  言& G% B: E- n7 {3 P8 E
在 STM32 TrustZone 开发调试技巧的前两篇中,我们介绍了内核的 SAU/IDAU,地址的安全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障错误。ARM CM33内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及 HardFault 的调试与处理展开,供开发者参考。5 I7 l- @: D- _! N

4 H- c4 q5 }0 Y0 u' L. H一、CM33 TrustZone 架构下的异常模型1 B/ G1 x+ s. W4 e, l! b
在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。3 F2 \6 n& a8 ?1 m9 {8 w
/ g4 `% @/ b* X& `
微信图片_20231130170530.png

! V  ~& ^8 ~1 @/ c8 E2 ]- E
5 Z/ i% h8 M4 t9 L; B  I1.1. Fault 异常类型(带安全扩展)
$ f+ }4 {  D  ?& D4 @$ U+ b7 t1.1.1. Hard Fault$ l4 h6 G: d' x& Q+ k
HardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。7 Y2 A& F5 b) o9 t; {5 P

% }% J& a& C  _' I4 c在 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 触发一般情形。
( X& l$ n( u: e4 w$ A8 o+ C% M; z0 @9 E$ O
5 C! v- ?; [3 R
微信图片_20231130170527.png

( y- T, w) ?( ~: @' |
; ]: f6 L2 l* k4 |$ ?. ]. y3 l需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。4 t5 D0 K  q- e8 |' \6 r3 I
+ T$ L6 I" Y' K3 c4 k6 U+ V$ a9 R
另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):! M" T+ I' A- C, n9 x, i
  1. void SECURE_SetNMIHFBFTarget(int NS)$ l; X( ]" f) S
  2. {1 r, M3 B7 M* z# p
  3. uint32_t reg_value;
    - b* ?, t+ y1 K0 B* f3 _
  4. uint32_t target = (NS==1)?1:0;# N; ~0 q1 H! O9 `. n+ W
  5. /* read old register configuration */
    / o7 _* Q! G- c, K4 P' V
  6. reg_value = SCB->AIRCR;  W, s3 G+ q' r7 L' s# j
  7. /* clear bits to change */8 m$ r+ [" b- f& c' T2 H
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));
    ! n" X2 g7 B( e; R* n4 w- F
  9. /* insert write key and target bit */6 K/ `2 Y+ r9 i* D: U( V- f9 W
  10. reg_value = (reg_value |' K5 O" t& h& |) q7 ^& q1 i/ t4 j
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
    0 K( A; V7 E+ }, O4 X( X
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );
    8 H8 ~% @) R2 o$ M# Q  T
  13. SCB->AIRCR = reg_value;- W! Y: ]- S/ r+ @, m
  14. }
复制代码
1 L, M3 P( F: j9 |& [% ^) M
注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。0 x! r- `& \( x9 V6 ~( u" e
' w  T0 g# G* Y* k: _# g

( o9 @" O: f9 b8 R! j1 W! u! l1.1.2. Bus Fault4 ^* _4 O% g0 H1 a
Bus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。
/ p* \' A  ?- ~& e* [
+ B- ?" O) r  i, t
在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。) J0 h) @5 Z0 m: N, }

. D4 g8 L0 X- N4 p产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。6 o/ ]6 V+ u6 f8 W
" X$ j) |# }) S" O  B  Y, [- n
微信图片_20231130170523.png
: F3 p5 ~. y% ^8 Z, `( w8 Q5 F

% _8 z8 _. ?6 q通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。# w4 g! {  i! w3 p" W
3 b1 W  |2 n% \5 d1 i5 K+ W
如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。5 w3 f% Z7 n% o( z

7 T7 _6 }% M& {- A/ R/ Q+ u! ]如果 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 寄存器获取故障信息。
& s1 x5 A. ~0 x4 N1 F
  |0 c6 `7 A+ g5 l, h- C6 Y: o2 B
BusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:
' |, o  C; k3 H  m- ]" ?- _% ~
  1. void EnableBusFault(int enable)
    ' ?- F: G* H4 }; E7 h, }5 f
  2. {9 M9 A9 I, L  h- m% j
  3. if( enable == 1), y3 f( u7 ]! Y; b, u) q* r  _1 i5 y
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
    8 O: g- p" E, }, y
  5. else" {3 O" p2 M3 w; z
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);
    ( s! x  B5 J8 t& h; l
  7. }
复制代码
! R& V# s) t* s7 _) X
这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。
$ `/ b) p$ d* v$ B) r- ^. g4 {9 `$ H
如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。  @5 q$ `  ?, h' N+ P
* D2 S" i& K" x& q; G2 M3 |0 C: }
1.1.3. Usage Fault
% q; r7 A6 C4 g% fUsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。+ _2 e3 z7 \6 q

: W8 e, Y  L- p7 J# Q在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。
# ~- @* `* r( r' V+ p2 j! i

, N3 a; E! |; s/ ?4 D5 Z使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。0 P0 a$ m0 O0 j, d2 R0 n
, f& S9 n9 }0 N
另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。4 O4 y+ R9 r$ S. w
- i) T. V) t+ ~
图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。( K/ j' N9 X/ c& W
9 k6 N1 b# N# I5 D; B! x' Z
微信图片_20231130170520.png

% @3 {0 g. d! ^# @1 e
( k' M* I, P4 m# o. K/ e9 _只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
# L3 T; O: Q0 G) w+ S9 Y& F/ W+ f3 F7 t; n
使能或禁止 UsageFault 的示例代码如下:' v) C6 U% Y; E. J) `8 J6 e2 {% B
  1. void EnableUsageFault(int enable)+ @2 J& F$ ^' |* {+ H5 p
  2. {
    & `0 g8 J& n4 M! z# I8 ?! i
  3. if( enable == 1)
    ( X- Q% B: S4 V, S
  4. {+ C- D: a4 B0 G- k
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    9 Q1 q& C) {: [- H: q+ n+ m
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */
    6 V" i* }$ x% x& t
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
    & x, W' v! p# D7 U9 H
  8. }
    4 f' J- F7 A- A7 ]  ^
  9. else' I+ l  I- f6 b& X( E
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    ) t0 `9 \* x1 g/ y% o( X
  11. }
复制代码
* I4 q# z8 Q8 Y$ y8 U
如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。
" [0 t/ @4 K5 a
  1. void EnableNSUsageFault(int enable)/ z) e9 U7 y- T
  2. {9 B- {, A) X0 `6 N2 R  o0 ]5 l
  3. if( enable == 1)
    $ p$ ^8 Q! z& Y7 j; Z
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;2 X% N8 X2 u9 R3 t# R) Q
  5. else
    : n5 \5 N) r" a* m* _0 U7 [
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
      w/ S; T3 n6 g* o) i
  7. }
复制代码
; X: a2 o, _- y
1.1.4. MemManage Fault
6 e4 y3 s" F4 oMemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。
7 }' Y/ F+ H6 c: B* W( l. s
) Z' v" m# |3 s) u3 OMemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。6 V" R/ j* ?& f" S8 [0 W
, e$ ^  e- ]+ [
另外也与 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 处于非安全状态时候的访问,二者互不影响。1 g" M6 D& v' K* c; z

, E) G1 R8 @  L- c9 l( v' O图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
0 A0 g" V5 o: j' C2 n
微信图片_20231130170516.png
+ b9 h( K: f; T% O. X. r; v  G% `
微信图片_20231130170512.png
, C0 u" v0 Y% c

  Z5 b# `3 g* b' o; f! `, M使能或禁止 MemManage Fault 的示例代码如下:
& l, e" r( T  ]5 [* F
  1. void EnableMemoryFault(int enable)
    ) T; o; K, n, [; A. S
  2. {
    ; W+ a- u% `# v9 R
  3. if( enable == 1)
    ; _8 @8 a) c3 O7 k3 t' g2 m
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;# d) N/ T1 v9 Z  [+ c4 N
  5. else: E5 T+ h$ w) v1 U
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    9 Y' T- d6 S6 B, h1 Y- z
  7. }
复制代码
, l. l+ ?% w+ S$ A& d3 t8 o
如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。
2 J% d3 U; t& t# G5 y
  1. void EnableNSMemoryFault (int enable)
    ; Z* \# v% u: E) }& i5 G
  2. {
    . I3 U3 a. M4 ?( P; w6 o
  3. if( enable == 1)$ e/ f6 U) B0 k- @' O
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    . I+ j* [6 j7 l) P/ S% X; r
  5. else2 Y! @, f: M) W/ s& t0 K  a4 g
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);% d9 }: n5 o9 t( I# y" N8 ^7 K
  7. }
复制代码
1 g; f. _) v. }
另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。
" ^5 o$ z- B0 x- |8 K3 r. o  X
$ t1 Y) e( M7 u& n& n1.1.5. Secure Fault3 s6 w5 [8 b1 L  Z- G) {$ ?
Secure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。
( s: u" b. O8 V" _: K; y5 w% |/ n5 ^- x/ d2 Y  W6 C3 W
SecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。
1 K! L  J' ~. E2 k6 H( O( B6 W. G; F6 b: I" ~
微信图片_20231130170508.png

4 a( w" [$ P! s  ?* Z3 I/ Q# Q
微信图片_20231130170459.png

3 P3 `7 M9 W" R! O0 W' j) e8 M+ Y( B$ w8 r
使能或禁止 SecureFault 的示例代码如下:" P0 m+ V+ V5 b# `# z
  1. void EnableSecureFault(int enable)
    8 l$ i$ I* p% ?' }+ D. Y
  2. {
    0 `  G% W0 y; ~4 O% _+ W& p
  3. if( enable == 1)
    3 G" M  }% i$ M- a' s' [! b, i
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;0 Q5 l" \4 C# d1 `9 U( I9 {) f
  5. else
    2 O- U, A) r2 g& z" o4 g
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);4 J9 a9 a0 H/ A
  7. }
复制代码
* e" b6 I2 w5 q1 K
1.2. 故障升级与 HardFault" X, B! F7 z# A# ]2 c* P1 B
除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。, H9 O( H' i, o0 g* r6 n
2 |- \3 ^  B4 Q% k' W. ~! |
某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。9 p- l& \! {5 a# g8 D$ V2 d4 m
某个 Fault 升级成 HardFault 可能有多种原因,例如:
5 h0 ^: |  X# F' t4 _  u( L6 E+ d该故障 Fault 没有使能;
; B& |4 V4 S' n7 C2 _% z+ n2 D9 c
  I' w1 w/ @2 u5 y例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.6 h4 a$ M. p/ i4 t' W, {, q
该故障的 FaultHandler 优先级不够高无法运行;7 q, P. A2 T- x1 J$ d
; u( @( Q: w8 @
例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。: G4 G& U! I) q( [8 }9 C" g4 F4 Z1 ^
在故障的 FaultHandler 中产生了同样的故障;  i) N: m8 }$ k# y- p
# n8 ~, r& H- A) o9 i
例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。
3 k  |. b5 E+ |如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。4 h5 h( j; g  l1 s  v7 @+ @
只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。
5 H9 f# N3 l- g$ _1 L2 a- I( J: c在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。% c/ T, I7 [; _% G

4 H( D$ t$ P5 }. y5 a, d: X1.3. Fault 异常的安全状态
8 h: M# n' }4 z在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。; d( f6 |5 t$ a- ?
关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。
5 n% y! E0 y9 Q: W$ [7 ~/ l5 H" j
, O- j  V* A8 b4 m9 J, W  ]4 w7 D
微信图片_20231130170455.png
( q. ~, n0 ^; C; E$ J
* I( Q8 p/ }3 Y; _
1.4. 异常的进入与返回
# ?3 _9 M2 i' U4 n& F! R6 a8 l. ^1.4.1. 异常的进入与 stack frame8 b* Y# J+ ?2 F+ @3 z* e- j7 F7 q
当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。
% d3 `$ C2 L# [' C0 Y' X2 G当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
* ^# h/ K3 j7 P5 Y! W, D- b通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。
; m& L# e. X. p3 w0 F如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。
9 P" D+ e; h. @& V  O% ~进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。/ C6 H1 A4 P% C, o
) e* M( y* P2 c: R  I# Y$ {
+ M' n' E  V5 [
转载自: STM32
" O  t0 ~8 u' X如有侵权请联系删除! s7 E3 P6 K* e1 ?' Q
4 X+ a" X# n' f% s2 V2 D
8 @9 p. {' x. g( j% z1 i5 t/ g
4 W' D4 Q' v0 Z7 a, _- {2 Q
收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答

所属标签

相似分享

官网相关资源

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