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

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

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

6 ?3 a& i0 c) B1 r一、CM33 TrustZone 架构下的异常模型! X0 n8 g9 I1 f
在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。0 M# ~( w- L5 f7 b$ U8 Y, E
! v0 l; a$ D& j
微信图片_20231130170530.png
9 U6 B4 N6 c' x5 a. e/ E

. K8 B8 ?& o2 I. L3 K; Q- ~1.1. Fault 异常类型(带安全扩展)
2 ?# X! X( O, A; [1.1.1. Hard Fault! U& u7 V- C9 g5 k4 b' a4 r" ^
HardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。
1 ]2 j% A7 A, X1 D7 P
5 B: ^( S9 J0 v3 A( _/ }# m在 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 触发一般情形。
# p& u' R/ \* X9 Q, ?4 j& R
/ U* c/ G' s) z; d, S2 Z. M0 c( p9 i9 _$ x6 S: ?3 U) ~- X8 p1 o  u
微信图片_20231130170527.png
+ j6 |5 x& \* q% p
- r, W" W- S1 r
需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。
5 s4 d$ j6 r' J$ H- C% |/ G; m# M
2 ]# K: v9 [. G% ]另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):0 \( h- m5 b9 O
  1. void SECURE_SetNMIHFBFTarget(int NS)
    , U  V" N/ A- r0 I4 C8 I
  2. {; A1 ]- g6 G( Y1 u# z4 g9 E
  3. uint32_t reg_value;
    # w: `/ W* Y$ g3 B2 B# Q* E
  4. uint32_t target = (NS==1)?1:0;
    4 c2 z, E" U) w  {
  5. /* read old register configuration */
    3 t+ c9 f# s" h0 {1 e7 o8 R
  6. reg_value = SCB->AIRCR;' K7 R4 e' c, h
  7. /* clear bits to change */
    # o5 I) d# \! @/ @2 \, `$ u6 N
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));& t; V" v7 {/ D
  9. /* insert write key and target bit */2 x7 r1 M/ U# M1 _  ?. `9 {4 {
  10. reg_value = (reg_value |
    % m$ W; s/ G3 V  R) _) r
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
    8 ?$ S9 [2 J6 i2 u" D% G" I- s
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );
    " A' e- U/ u# j8 g1 }" W9 v& q2 t9 ^
  13. SCB->AIRCR = reg_value;
    , a! s, k* H1 W+ v3 u5 b% s0 ^' T
  14. }
复制代码

* U! r# ?' u9 G3 C( d" C9 h注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。6 `& J. G8 R8 l  t- p+ Q' N* {

$ S4 I8 O- D. \/ p4 e2 X$ }
4 P5 E8 h: E- y1 O
1.1.2. Bus Fault
: y* u& }$ O4 A, e0 x0 `Bus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。# q$ j* [6 n' n* z) D1 B$ ~8 B& H
* c  P" z( Z) ~) w3 s4 q# \, L/ z
在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。
* n% m  |+ @& P8 I
" j$ v) b8 g$ E- o! p& X( @
产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。
( Y" n4 O' Y- ]$ W& [9 m- O% x+ E
微信图片_20231130170523.png

* g6 `+ \3 ^# {; R) b' e: B. [) p1 O7 a9 }
通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。) C4 _+ e( x# r! n

5 [% `8 Z9 L; L4 G4 ^2 {( {如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。- K4 o1 p7 d5 O

# `+ p) Z! U6 Y( }( ?' K如果 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 寄存器获取故障信息。( h- ~# i! ]$ u) h8 z6 k4 H
( Z4 Z' R( A5 w+ x" t8 B0 S
BusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:
2 M- [+ _$ \4 x5 O
  1. void EnableBusFault(int enable)# Q6 j" V1 P& v4 o
  2. {( q1 Y/ `! X: a5 v: k& e+ p
  3. if( enable == 1)5 y: \5 X' g+ m7 V6 E, J+ o
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
    # P/ F/ p: E. t% X. ]
  5. else1 L2 D# @; a" e5 C( I: \4 Z
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);' C  U5 g# N6 ?" e- Y+ S$ v
  7. }
复制代码

' q6 k0 P! \6 X3 f2 T$ V. T这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。$ [- o9 P0 [1 g7 s3 {
6 H& ?# c9 J' ^) e
如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。
4 _0 \9 n- g- m& W1 _: K, |. C
7 S7 d8 c* o& w1.1.3. Usage Fault) W, _' s4 r4 [! e$ z
UsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。
! C# n6 Y0 o# E: Q( a6 r2 X2 E" ?* x( b  h8 m( H) t3 M9 T
在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。
# [4 }6 c" A$ S5 w* I

) ~) v/ b$ s; i* ~使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。% S# Y+ B" |2 R5 B2 u

, D* C0 h& n: C* q: g7 M) R/ S% Q- q% _另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
) g6 g1 @( k/ \" O3 J  Q1 |, P1 r
- T, I& R* N6 a- S6 C9 T1 y3 Y图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。: b- O8 r9 C, Y1 q# O
  o, l% K# b2 i$ E9 S+ ?' F
微信图片_20231130170520.png

5 V/ O. S6 R' Q4 \5 O3 z/ d
8 t2 {% c. W6 H  v只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
! z8 U! c, R4 P$ n7 W) Q/ F+ H* n" R( b0 M/ Y1 D
使能或禁止 UsageFault 的示例代码如下:
& R6 M. i' u+ w& ?. U0 A
  1. void EnableUsageFault(int enable)1 O) {/ r/ ]1 j! X! S
  2. {7 K( M1 _  ^' q& x$ ]1 `. \3 P
  3. if( enable == 1)5 n0 g7 i% J2 l$ u% s( B
  4. {
    ; n& X" J5 Z, q9 {6 u
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    ; L( \* W/ Z- {7 c' j3 `
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */
    ; x' u7 x9 ^. t3 N
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;4 n: ~: l1 _( U- a6 S
  8. }. P9 R) [4 I+ Y0 e$ v6 J
  9. else1 Z* X4 V9 v  x8 d
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);" J8 u6 K/ |( m9 b  B
  11. }
复制代码
% M) J/ ]2 g# D8 s: o4 E! T6 g6 M2 k
如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。: U7 C2 ~; e  g% t. M# J" Z) L' V
  1. void EnableNSUsageFault(int enable)
    ! S; z  A  \0 X  u% _, Y
  2. {
    * t+ N4 z& R* n" r+ s. ^1 o
  3. if( enable == 1)9 ^% A2 k1 P9 i
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;" P! T8 {! J  v% h5 w
  5. else
    - m2 {1 z# V% V: |5 @
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    8 q. q$ F! P* q
  7. }
复制代码
! K! k( T+ Q1 X, s4 \) ^& k% x
1.1.4. MemManage Fault
" N  f' y& f, a6 n: QMemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。
  p) G% d% z' W2 |/ q
/ z# R: p5 y6 R& d4 ?. kMemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。
5 J3 P! K( I1 ?  |. ?, k# D3 e/ G
. f! e# x0 v% A: _
另外也与 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 处于非安全状态时候的访问,二者互不影响。
: R* }7 @- A, d3 k/ Y5 L) ?0 T9 Z! |3 x- o( P) [* V6 E1 w4 T7 B
图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
$ ?% _* J/ Z* p0 l/ g# Q
微信图片_20231130170516.png
. t, z# I6 r/ ~# B1 l4 w- q4 h
微信图片_20231130170512.png
% _! X4 Y; @" N8 N, `0 I! b0 L

* y8 [9 A1 j! a$ U1 k使能或禁止 MemManage Fault 的示例代码如下:; d' [8 b8 F3 j" i7 e* Y! d* M3 t
  1. void EnableMemoryFault(int enable)
    ( J% H3 J1 t; A1 Y- }' M: ]
  2. {
    ' y8 U8 M$ h! W
  3. if( enable == 1)
    $ X% S1 @7 W8 O8 a! _0 z
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;* k5 n, G, g  U. J) u. H
  5. else
    9 h# l6 ^$ L, L+ o0 Q+ I) d
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    5 o3 m* v+ G: ]1 G/ `* x- M
  7. }
复制代码
2 X/ Q( m% R; v1 d' x' k4 ?% ~9 c) R
如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。4 ]& T  `2 v8 l
  1. void EnableNSMemoryFault (int enable)
    1 N2 N4 ?6 d9 ?7 v% G" ]. S' i
  2. {
    ) R! i' n% L3 z- ]3 C. O
  3. if( enable == 1)/ n0 t# T# m9 w5 E" L& R: D
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;( p$ \+ K/ Y7 o
  5. else
    / v6 W" F" C5 u
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    $ S; A; G, |/ u9 q) B8 o3 d9 F8 g
  7. }
复制代码

! r; Z1 E& N: }: d; o& m2 u, b另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。
; _1 @0 u5 m! Y  F, l1 ~! b0 O- x  G$ A& Y7 g
1.1.5. Secure Fault
; R% v1 i1 J% E9 ~5 ~, L. [% BSecure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。" d6 c" T9 d9 \# X

2 A( C' g  H' L% LSecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。8 x& j: |3 E6 c$ }

& f) G" O4 c# F6 H# f0 `
微信图片_20231130170508.png
, e7 p3 o. c. y  C0 x" x
微信图片_20231130170459.png

# f8 M- o9 @8 t* E. ~
+ G) q+ }* H% M) V0 }  i% a使能或禁止 SecureFault 的示例代码如下:1 i' J( C' v, f- l. w
  1. void EnableSecureFault(int enable)5 y* b1 u; ]" }" `1 }5 E
  2. {
    7 P: N3 O. N: T7 t5 H! t
  3. if( enable == 1)  G9 Q; Y9 w/ X" U9 ?! \, X9 p4 \6 S
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;8 m9 A- v- L2 `* T+ d1 N
  5. else
    / C% d# t. |" s2 V0 B( {) e
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);
    . t8 q4 T! N( S3 X
  7. }
复制代码
9 B# ^+ I& {: B' F. K
1.2. 故障升级与 HardFault
# p* y: L! H/ F9 p! j1 ~  s除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。+ C' x4 n$ t- @2 x- a# X

7 [& Y  K# v& K( [" u- ^某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。4 |5 G. S4 @3 b) X5 C5 f
某个 Fault 升级成 HardFault 可能有多种原因,例如:5 _& A- z$ Y  g+ B6 w
该故障 Fault 没有使能;1 l8 `5 Q+ @1 b4 s/ k  }
0 C3 ^. V5 J& Y, l: X
例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.
0 R$ c0 K4 g# K4 x$ C7 l8 D该故障的 FaultHandler 优先级不够高无法运行;! V, \! p+ l, x+ ~  T4 m

( K, g/ F* ^  E* B0 P' ^( [例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。
% e$ z0 ^6 b$ O7 I- Z. G  B/ v在故障的 FaultHandler 中产生了同样的故障;
8 s( P% c. o: w% I4 ?
  j8 k7 s! O: t" H例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。4 x) Q# x" d+ B. G6 {
如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。
+ c: [7 Z5 `1 A4 Y0 K) j2 a0 u只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。" Y  D7 ?- P1 M6 j0 \) [& Q
在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。0 H$ b" v5 n/ z& ~+ {+ T: |
& B% ~& {1 [* P% A7 L
1.3. Fault 异常的安全状态5 V$ }" X8 A& K& I4 ?4 R
在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。
! N6 j) G3 m6 M+ b" J关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。+ F( n( G7 q9 H6 A, Z1 p3 h1 o3 f
- y; x! G) b  P$ o! l
微信图片_20231130170455.png
- `$ \4 F- z! [6 M
+ w" P1 I; S# `  i( |- O' x
1.4. 异常的进入与返回
  u5 @$ l6 d) M, R- P1.4.1. 异常的进入与 stack frame
9 x* l" R) C/ H5 @* Y当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。
' F- C6 x: A( S  A当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
& `0 X. A+ w. ?1 C通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。
. r& c# ]3 k. m/ P6 g0 x0 ?如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。( t. P# x/ W  C) d: N. |% y
进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。) \4 c8 Z; J% N$ R: B* M4 v: y. O

/ r8 n, B; K+ d# T

5 R3 x' \& O4 a6 p4 s) R7 Q9 o1 j转载自: STM32$ A) k* [5 ]; L' [8 p# ^
如有侵权请联系删除
7 V* M! C+ O. z; o% d; i1 z: _. R% o& H6 A' [! V
6 i* a- j' [7 g

& f( _" e7 i  u
收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版