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

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

[复制链接]
STMCU小助手 发布时间:2023-11-30 17:05
引  言) P. A% Z* j' ^, l$ y: h$ W& V
在 STM32 TrustZone 开发调试技巧的前两篇中,我们介绍了内核的 SAU/IDAU,地址的安全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障错误。ARM CM33内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及 HardFault 的调试与处理展开,供开发者参考。
3 _% u* _/ d4 O2 E  U+ r: D
7 H( a4 V4 e* e1 [9 n) d一、CM33 TrustZone 架构下的异常模型( B1 Q* n& @* i( ~, A
在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。( Y6 \6 Q" z, n  D

. t7 e% l# [# p  a
微信图片_20231130170530.png

6 t5 L- K2 @2 H# T+ w  P
* k  z4 d9 L. [7 P$ ^% f6 t7 G1.1. Fault 异常类型(带安全扩展)
( T2 p# ]/ E2 U; [0 K* r1.1.1. Hard Fault
4 E* T' J( b% T7 F/ S) n) aHardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。
9 L% y! L. r8 d
4 x5 z/ }4 R$ P# l, m: L在 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 触发一般情形。# U1 w) l1 ?5 h- ~. o) C7 e
# G7 v: w* Q' _% G; ^

2 n3 \* u$ @' ?) X8 I
微信图片_20231130170527.png

. `8 B' I( ~! @! s8 r5 a* @' L) B& l% _$ l6 }: H
需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。) r: g5 l5 E% w8 C  c. k

# `! Z1 q) N: H3 G9 H. M9 E# b6 l! S另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):- V* h3 v2 C! F2 M) b2 g) C- \
  1. void SECURE_SetNMIHFBFTarget(int NS)
    $ }0 ?* V0 D$ t! W# Y7 o
  2. {8 j6 G+ J, f0 ~4 ~' y
  3. uint32_t reg_value;) E% V+ ^) q" @8 f! z& ]/ P
  4. uint32_t target = (NS==1)?1:0;
    6 k; _2 J% B+ ]$ E
  5. /* read old register configuration */
    * E, F) c/ i' f2 U! u" R
  6. reg_value = SCB->AIRCR;  Y6 t8 i2 K1 O4 p
  7. /* clear bits to change *// |3 o0 Y/ K+ h, G5 Y
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));+ Z& H5 L) |7 O" i$ C& [
  9. /* insert write key and target bit */
    4 P7 W/ W% T# s$ x& L/ U3 U
  10. reg_value = (reg_value |
    ' C5 ]: g/ Y3 }& G7 w& ~. M
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |0 n5 D$ q0 Y4 z1 e3 Q! J  |: I5 z
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );# I& b- m0 G' R: U+ y" d0 w- p
  13. SCB->AIRCR = reg_value;
    5 s9 p1 k$ U  F8 [4 x2 J
  14. }
复制代码
- h+ K4 @- f- |, L! F  P0 u
注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。
0 Q) z( A' M8 q$ Z8 B$ p7 g$ j  a4 i4 w. j3 p) o

  G3 K4 i9 P: N8 S- Q  a3 l1.1.2. Bus Fault: o2 x6 O# x* m# ^& z; V$ X
Bus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。* W, t% W" e9 b5 h( M
4 n7 D1 T' G# n) P, w- e# ~
在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。' B7 [; _) u5 Y- y. W! ^

9 }; J+ q/ @4 j2 {产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。
  j" w9 p) R8 f6 F8 m
2 D1 s" |5 k! M5 {9 Z- j
微信图片_20231130170523.png

4 x0 h+ }  W: c+ o( _5 X8 @" T( w4 B' U
通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。
) K2 d8 h( H+ W9 ], u
5 |  X" \8 w6 K) M" v# T. j如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。
) p4 ?  P" j, D& p

1 s+ u) C  l3 |- D% r/ K/ 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 寄存器获取故障信息。
/ ~2 r' ]8 n; W
( z6 K. u9 E' ?
BusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:
, @' e0 C7 S4 n  Z1 i6 \# a" k% |
  1. void EnableBusFault(int enable)3 Q, d7 J2 ~) s3 g' v
  2. {
    ; V$ M* N0 c: }' ~2 t0 r+ v
  3. if( enable == 1)
    / ]7 Q% J. e( m0 E; t; {
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;3 z! g4 v* @. f- t4 B
  5. else( E, h; D* V4 M
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);9 v; j' ^+ N$ n# A
  7. }
复制代码
- [: w0 E  E  m4 g7 C4 Y7 [, z
这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。: E( g6 F  \, P  U1 O4 Z- N

9 y5 @* ^3 M" i如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。
8 P' _" o6 A! V0 @5 }
% e' j8 x6 a8 I: o1.1.3. Usage Fault( @+ y# m0 k# f' h( A2 a9 [4 u
UsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。% j- M! `7 r! @% @+ P" C; ~# q
9 F; V% w! I6 q' ?
在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。
& U6 [5 q; r7 ]8 F2 E
  I" {, s; D  Z2 |0 s
使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。1 O9 _0 c! P% A

2 o: y: S, B$ D  S' ?% y- K另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
+ J% T% i8 d. T& h6 t1 X6 S% q2 U2 s( @" g3 m! o6 q
图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。
: I0 h* C, f& J" K! ?7 v9 t
/ P7 w6 B( L8 E$ M  D: [7 J
微信图片_20231130170520.png
7 U) P; E' B  y+ j
( W3 `/ u; f' z
只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。4 Z# j, {2 W/ {% P# t
# ^, }" \) j! H: r  s' y
使能或禁止 UsageFault 的示例代码如下:
' u* J0 W% f; s7 Q0 _) G0 ^
  1. void EnableUsageFault(int enable)" ?7 V, J( @7 E
  2. {, W' w' k& D- t+ \8 v& ?) k
  3. if( enable == 1)
    ( A: f" C  H; C+ z3 A1 |
  4. {; T- J7 {5 i, h+ _2 p% S2 g* O
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    $ R) [; F2 `$ p3 ]. c" e8 A
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */
    2 T& l" {+ b6 o) G% T
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;& }# d$ w8 r& X0 c) A2 F* M0 l
  8. }% P2 {4 Q9 a. ~, f4 i* K/ c% |% o
  9. else
    2 A% V6 a% e. _8 w
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    6 {# g: ~: t# E# S3 D
  11. }
复制代码
$ n  r  j1 j0 ~% ]3 U' [8 a
如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。
6 e; _" U  y8 K! d" {
  1. void EnableNSUsageFault(int enable)9 F% s' m/ T/ R: {' t" }+ k
  2. {6 o: y! A: X1 u1 }3 u$ y' s
  3. if( enable == 1)
    ) W0 ^: e6 p4 [0 }) F: u$ q
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    7 [$ m0 \5 ^- C- z% d
  5. else" N  Q5 P& t/ B
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    : Y* I# S/ D# g
  7. }
复制代码
/ m9 b, S; t; N2 a  i: O  u
1.1.4. MemManage Fault9 v# g' P, U& ]
MemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。# W1 s( n( v7 B. O8 [5 [& A+ ?6 u9 m6 g
+ k+ ~. }. c8 P0 e+ n
MemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。
& p& C9 I" |5 j' e: n  j
3 d8 O8 J. ]. i0 U( 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 处于非安全状态时候的访问,二者互不影响。2 @; f& A8 M5 ^3 Q

8 i6 ~, r2 o7 j6 u  l( f! L6 o0 V图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。( ~3 |% g, r/ O; ~7 H, R+ Q8 }
微信图片_20231130170516.png

. x6 h' y! ~0 b) m4 L% W9 O
微信图片_20231130170512.png

; z* c6 W6 y4 R% n6 f% E
: n# X" ~! d& t# F, y. c$ n# c" x使能或禁止 MemManage Fault 的示例代码如下:/ A! X4 @8 r# [, k
  1. void EnableMemoryFault(int enable)
    : ]5 m. C4 I. [2 T9 _7 L
  2. {
    ) |. W* w& Y# y& z1 q
  3. if( enable == 1); s, J5 i' ~# ^. H1 r' ^
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    7 O8 ~$ u4 h, x
  5. else
    ; I$ s: @4 g. K( ]
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);& A& i, ]( L4 d5 A( r6 ~
  7. }
复制代码

/ x1 ?2 ]" E% C3 M* _' f( e# z如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。+ p2 Y: o/ K1 o* g5 h+ L
  1. void EnableNSMemoryFault (int enable); S* d5 O: f( ^$ t  Y
  2. {
      m3 o* s" a3 g2 M; F: h
  3. if( enable == 1)
    ) j( x/ a; U& u; x# k
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;% }5 i. A1 Q) s$ u5 }& O
  5. else* O4 I" g! ]/ _, s* {
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);9 \( [( }3 j5 N4 @. t' k
  7. }
复制代码

5 Y' ?5 x7 |" k9 ?/ J' y  K/ F, Q另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。4 O; x: h3 S) |1 o7 B2 m
) V6 P! V! I. W# L1 j
1.1.5. Secure Fault0 T7 S9 m3 P( E9 s: S" A
Secure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。7 \- `6 x# ~, U9 s- w

. `( [9 M- L! }1 x( ?0 i: {SecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。
9 O' O' l2 W! H# r) n6 ?
4 L- l6 t9 m9 c% J
微信图片_20231130170508.png
* D* b" Q4 l) H' O5 l5 f1 l  o
微信图片_20231130170459.png

) \. Q6 `4 q0 y  O8 p/ ]. w3 ?$ }; n
) X# l8 T2 X& w8 M使能或禁止 SecureFault 的示例代码如下:/ ?; X' e6 }5 b- d3 W
  1. void EnableSecureFault(int enable)
    & A( C* G8 l2 y! r% x8 z+ P
  2. {" L5 o: x5 g& d  s% ^# C& u
  3. if( enable == 1)
    ; B: e7 Q8 O  B- C6 }
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;; ^/ S# [, ^3 \1 h+ N% @
  5. else$ t; F" l1 H: j3 P( q1 Y, I- `
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);/ l7 |8 W% m9 @" Q& R% l4 M
  7. }
复制代码
) W8 P( l1 O/ `& Y( `
1.2. 故障升级与 HardFault9 [; I- s0 [! d0 r% U" j2 B
除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。
+ m7 ?' G6 W* K+ ^+ ^' x
# c3 e3 Z0 Y5 _$ f5 R$ v* }
某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。4 a- p( Q. Z9 K" e1 K4 e8 e
某个 Fault 升级成 HardFault 可能有多种原因,例如:# Z8 B. b+ ^, Q  ?5 ]% ^
该故障 Fault 没有使能;
) d5 e' S% u! j4 {
0 g1 C+ w: G( V& D% `2 `0 \例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.
' K6 E& b4 j& M" c5 \; Y0 S& F4 }该故障的 FaultHandler 优先级不够高无法运行;
  d% }- p3 \, e: }7 N

$ O9 \/ u2 q/ Z  {- `/ L" P( c例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。# U; a3 `5 {3 \- c$ t$ j( w' m, B$ c/ t
在故障的 FaultHandler 中产生了同样的故障;
4 `5 N( C. X- u' D; S* l3 T$ Y: G
例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。
$ j' a# `# Q! r8 H9 i如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。
" i) E- i. L: e: ^只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。
3 I: F4 l/ W6 j7 F- L# |, ~在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。) j3 t% i: H1 u3 t3 K
% Q, C: R5 p- t
1.3. Fault 异常的安全状态# E  K* V8 S$ D5 x& f
在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。, f% K4 F( Y+ h9 {) l
关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。0 N8 G" C& Z9 X6 |* O  z

7 A. f+ J) Z9 U+ d! w
微信图片_20231130170455.png
! D0 y5 C2 c4 w5 t4 J
' R& |. O# v+ U: B6 T! T
1.4. 异常的进入与返回! z) `, `; o3 V7 G* A! J8 G
1.4.1. 异常的进入与 stack frame8 e: ?2 g1 J4 X, ^. ~0 \0 n
当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。
% A& d4 c2 Y, `5 p# P1 w当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
" [( V) \4 i% O/ ~# M/ @通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。3 O9 l& h+ ?% ~$ E4 k$ c( V
如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。! `3 u( r0 M" y/ ]# R5 n% m
进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。7 N, \3 _+ s6 P2 a; F

) J1 S$ d' R. H# c! r6 y: ~' d2 t7 d
" O- `* I7 r: L" k2 O5 `( n7 q
转载自: STM32/ x5 R! {+ {. m- P: Y" R% ^
如有侵权请联系删除
4 z+ S& U, d# o
  `; Q. J9 `% u$ s& d

' W# X' z$ t* L& y2 y) G* l  i$ U& M( u* f+ w8 G9 `" P/ r
收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答

所属标签

相似分享

官网相关资源

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