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

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

[复制链接]
STMCU小助手 发布时间:2023-11-30 17:05
引  言
0 h- A3 r0 h% M% A+ j在 STM32 TrustZone 开发调试技巧的前两篇中,我们介绍了内核的 SAU/IDAU,地址的安全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障错误。ARM CM33内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及 HardFault 的调试与处理展开,供开发者参考。
& D( z" Y3 n4 G5 O
  t0 Y( p$ U, P$ b7 {一、CM33 TrustZone 架构下的异常模型3 @3 F5 D- C* l2 I
在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。
0 B9 h" R1 p( Z, M6 Q6 v: j7 A
% a, Y/ X! `: E, Y3 V
微信图片_20231130170530.png

5 }7 z; @7 c/ ~8 {3 J* q2 L
& L4 E2 }* G+ H4 |- S1.1. Fault 异常类型(带安全扩展)
. ]( ^3 j6 {. |, i; n1.1.1. Hard Fault
+ T; p) v/ r; u8 n* H! \HardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。
* x8 O8 X- ^4 ~1 ]! u2 J6 }: s+ L: 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 触发一般情形。
3 ~  m# n: g$ l( Q/ n6 w/ c% b) ~; f

- E7 ]$ Z0 k4 ~1 t
微信图片_20231130170527.png

% V; ]  O% q! `3 U+ r* f
4 B6 `% I8 P0 T6 s需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。
- a* W% C# y1 s2 B8 i# T# U% W! D, @' U' |& ]; F% }
另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):
/ v. ^( q, j+ K# ~0 v3 A3 p# R7 `7 Z
  1. void SECURE_SetNMIHFBFTarget(int NS)/ h7 e! S# k8 f  p
  2. {
    ( ?9 E7 c, [0 r" |9 L
  3. uint32_t reg_value;; E) M1 N7 n) Z, m3 X. e
  4. uint32_t target = (NS==1)?1:0;# G: n" v% t6 Z8 v$ {, G6 L1 m
  5. /* read old register configuration */" R9 g# U1 U) i8 e4 J7 U% A2 c
  6. reg_value = SCB->AIRCR;2 x- t- L3 ]  @5 t/ x, W9 M" t
  7. /* clear bits to change */8 j; C/ r$ o4 L8 w) v
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));
    3 D6 F! e/ L  {# w; a
  9. /* insert write key and target bit */; j* Z$ z6 v& ~- v5 D6 c0 U' x
  10. reg_value = (reg_value |
    , \4 v+ Q& p2 @* n
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
    ; S) E& N0 W  A2 G& z
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );$ j) ?- Q, c; U- W) @  p3 B
  13. SCB->AIRCR = reg_value;  z1 w* d0 a3 g4 e
  14. }
复制代码

& |: ^& R- X2 ?2 J! v0 e/ z* L3 ?* m注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。
: E% d% T* ?$ U4 S
/ r3 `7 r  j' r3 S" M
' y4 q* Y& P  y+ D# o
1.1.2. Bus Fault8 P6 d' H& o. Y9 v* z1 c+ F
Bus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。8 [' S' u4 |6 P9 @+ V. a9 N$ Y
2 n4 v& E  E9 q
在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。: s3 |: `& k2 k- V- Z. \. q# l
) E* C0 r& `. }1 B
产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。) n- ?$ V6 f6 U9 O3 [
$ ^1 `1 W* T& e' `6 H
微信图片_20231130170523.png

8 s) M$ U* {; {; k5 X
6 W! T" N, q* e3 I0 i6 j- P通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。
+ x! y- t+ R8 ?5 y1 I; m2 _3 ~9 s8 G
$ i+ V$ R$ Z  H如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。+ C" Q% @* T* Y' I& M, C

5 y; t* r; m# T: A/ z5 j9 f如果 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 寄存器获取故障信息。
0 I. b/ y( T& k" `8 T2 R

8 R6 i" g2 V. i9 SBusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:
/ x9 j/ p) S6 b. C' j5 _; ^
  1. void EnableBusFault(int enable)
    - h, [9 A) k: q9 Q& j& a5 ]
  2. {
    3 ~/ T9 W$ U6 L* [' m2 Q6 Y2 M  b
  3. if( enable == 1)7 y% V# J/ k  H6 D
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;4 d. J; J3 H! B
  5. else
    8 M0 x7 b) Y8 M- z: z3 ^
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);
    0 B/ M$ Y; H/ E: l7 d7 d
  7. }
复制代码
  j* L& G8 M2 ^2 o; V) x
这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。
& n2 w. [2 a. W2 a, E. k! q7 C
% S" Z% T  S' d  K4 d2 M9 y如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。; D" X9 V7 e2 Q5 n

. d" G! u2 c- e6 a( m: x: V, [" B1.1.3. Usage Fault
: W6 S: ]9 g9 x$ V8 CUsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。
& n; e9 p0 j$ `+ e% n7 s7 n* w/ \7 |  P# `) @3 b9 m/ [; r
在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。
2 r3 ?( ]7 u; Y9 O. I2 l6 a
1 g" p/ p" x( g! ~
使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。
1 d$ A0 G: r$ K8 T
# V" ?9 \: F# s  _2 k
另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
9 S) V+ f" Q/ s: @/ w! u9 P$ i$ f: t, R2 o9 l/ p- O
图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。
3 w( h! ?1 E1 Y
6 _* j# k/ H* K5 G* Z
微信图片_20231130170520.png
! U" o8 e$ C( o: e9 U

3 K3 n5 b( i2 L& K, H0 b& M* Q" ?8 P只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
$ Z; v3 C5 z8 L; ]. z, X) g% |
; c, ^% S* M, Y& V, S使能或禁止 UsageFault 的示例代码如下:; ~. l5 ?% h) ]; ]* H1 g% v
  1. void EnableUsageFault(int enable)
    5 i3 ^) h* d5 f6 r
  2. {
    + Q* S5 P! |6 O8 S+ _
  3. if( enable == 1)+ h$ E" q) r' A, e8 \- m6 ]% l- ^
  4. {
    # L, o5 W7 r3 o1 r3 C* N8 C- F
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;. m4 O9 h, P% H# j. s
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */8 R7 r) G4 L5 Y6 U+ d" ^
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;; ]4 s- E& f$ c: l/ ?2 }
  8. }0 Z+ q  Z0 Z8 M2 Q' j6 ]
  9. else
    9 C1 q4 m/ T$ B/ b7 R
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    * ~& n7 Y2 s( k0 y
  11. }
复制代码
1 D4 J5 Z  h' J6 H: a
如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。# b7 F6 u0 Y0 r
  1. void EnableNSUsageFault(int enable)- J" n2 L9 |# r# d6 D  O
  2. {8 e- _- p- l$ X
  3. if( enable == 1)7 j" p2 O5 Z1 W  r* n! V
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;" |% v$ ~7 E9 U$ s: A5 y
  5. else+ _! G% @, T- ^" ?
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    " j. \: A# _1 w) m  x
  7. }
复制代码

9 @% v, W  k" w) O3 M/ z1.1.4. MemManage Fault
* j1 O$ r9 p; w7 _* e  [MemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。* R4 g5 q3 k$ n( O; P8 X
/ d4 a* [- F8 r0 ?) C2 e& r, {4 r
MemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。  T. s6 |  M7 }. K
$ ?5 ~( v* l+ f% g# t& p4 |
另外也与 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 处于非安全状态时候的访问,二者互不影响。
# z6 N) s( j% }5 b' l! h
6 J& m: w8 U6 S4 s- @# O6 m) o2 T图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。8 S4 ^7 g0 k- {( S- @: _
微信图片_20231130170516.png

  O3 K7 b1 J9 g- B- t
微信图片_20231130170512.png

+ w& ?5 _4 i4 }$ a
% T5 M' w- m# t8 W+ S+ H使能或禁止 MemManage Fault 的示例代码如下:- M% |! J  U9 P" U) s) H+ z
  1. void EnableMemoryFault(int enable)
    6 j% m9 E9 M1 H( s
  2. {
    ; \" C; ~, N9 @8 ?
  3. if( enable == 1)
    6 M/ z* D' U$ E0 b7 O
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    0 b/ a/ _# U8 w$ i, n% e
  5. else& W5 X& Z6 C! {# V
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);8 H" X9 Z& k4 h/ T; [9 p* o7 A0 s
  7. }
复制代码

/ j% W4 t, p9 `: a8 ^; p如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。% Y1 c! L! i' Z* Z" H9 e6 V
  1. void EnableNSMemoryFault (int enable)
    , M: h4 I; [5 F6 n1 E$ r4 i. G
  2. {/ T( r' }& g# k  s5 r
  3. if( enable == 1)! _9 I* |8 k# k+ P! X
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;/ T9 K( H9 ]( c
  5. else" U4 K" @6 l+ x9 U/ ^, Q" E  g
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    ) a0 p7 y; d5 \! b2 |4 X
  7. }
复制代码

, u) p7 t3 V% h$ R" e5 \另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。
; T+ U2 F& q* r" a2 S6 K# q) A- n
8 r9 K4 m8 M" \8 S1.1.5. Secure Fault
) N/ [' [% \! E. K6 w( v+ DSecure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。
$ w6 A( F+ B/ n0 _; J$ j' p2 n7 E2 o+ T: I) g& `# P+ j  X
SecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。
$ b; e* I$ y# [; c7 d- u% G3 h; L( z, }- k' O" u. {& p
微信图片_20231130170508.png
+ s9 X! f$ x1 I1 Q
微信图片_20231130170459.png

! g) i4 a2 h0 N8 Q2 C5 s7 M( g. U/ V+ }4 Y& ]
使能或禁止 SecureFault 的示例代码如下:
8 W% u& I1 v7 Z: W3 z( Q& b/ u4 m$ n
  1. void EnableSecureFault(int enable)
    ' W: i9 ~- M$ Z; a- ?$ f# W
  2. {
    ' m  ^; k+ G5 H' l2 L7 \
  3. if( enable == 1)3 m+ j  w3 ?' G5 u( l) u* S* m; e
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;9 I0 a9 ]: \7 P. J4 s& K
  5. else
    7 ~$ h% }( M7 T7 U  L' P9 |9 F7 k# M2 [
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);% L6 \- H, L" \( v  ^; j: I
  7. }
复制代码

3 u7 n4 k% q' I) w: `" i1.2. 故障升级与 HardFault
6 K* s3 g% ~' O7 i除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。- z$ i* }9 I8 t5 I+ P- l9 g

# R6 l% M3 y( H! H& X+ H/ V4 g某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。4 f9 [9 X( L3 i
某个 Fault 升级成 HardFault 可能有多种原因,例如:4 i5 V8 M, s! w# g4 [# P3 g
该故障 Fault 没有使能;: r/ Z' ^1 T" A" |( f4 \

% l3 r) V# b& W" r, X' ^) f例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.
3 P) A/ p: ^# S+ A7 f* e0 p1 Y8 H该故障的 FaultHandler 优先级不够高无法运行;* {: o! M* K8 \" I6 y* H# C6 R

( N  k  f; N9 T& J例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。
* A/ N  G+ a% L3 e0 W在故障的 FaultHandler 中产生了同样的故障;
: Y; B- J- ^$ c4 d7 q- X/ a" e9 G% {/ Q$ t4 B8 q
例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。
6 L( K9 w2 s# D4 ~$ n6 c+ K如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。4 @. I8 r2 {4 k" b0 D6 Z. b+ x! Z
只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。
& L9 N2 z7 _' m! R在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。
! V. a- r* D2 M7 P
( U& P1 V1 {( _! T+ m1.3. Fault 异常的安全状态
4 ?- x5 j9 Y# x# R1 m3 I! P: L在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。! M% ~# i# g2 ]$ |8 Z/ X" r
关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。6 K/ ~4 a4 _5 i* d! @7 x7 j; s
" m# k' B; p7 ~, s1 q' B; a" }
微信图片_20231130170455.png

: U$ h; Z0 ]4 f" G# A* r5 j. H! J' g$ n( S! @9 J
1.4. 异常的进入与返回
1 C! M" x  T5 G( n* \, d  }- t6 I1.4.1. 异常的进入与 stack frame
2 \' z* f; j9 Q+ l9 j当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。
% }# r. P" i  g% X当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
- k4 D7 f% T! O: v通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。7 l+ F, Q) D2 O1 P% t1 i; s
如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。, v' N( I: ~# D
进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。
: x% {4 {2 f8 o' h( G6 R. E% C* T; i& p$ q7 z& _7 J; G7 D8 K+ e

6 F7 G3 d- \( `# `' G( c9 I: _; G; ~转载自: STM32
6 w; `& B! b2 _% E0 U# }  Q如有侵权请联系删除4 g0 Q8 G1 s$ r6 T
. m& a- q8 q% s! h# G
- c6 t7 D: ^$ Q+ l3 J' ^9 B
; }* W2 J* h9 l2 R. W7 @
赞 收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版