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

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

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

+ c( t9 G, |0 p/ A一、CM33 TrustZone 架构下的异常模型
. z+ z; [7 @7 p# J, I0 w在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。3 P3 c# R) \2 O4 n& ~! @$ ]
* ^  V( O% b# P$ M9 U) {
微信图片_20231130170530.png
0 E2 Q2 X% v2 `! a7 S

2 u9 }# `0 }, n$ q% `7 p1.1. Fault 异常类型(带安全扩展). d' C: |$ z- A4 m
1.1.1. Hard Fault
5 N. w( }) [0 e9 h5 uHardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。' I4 V4 J* a, q- F& C
: f: S6 e+ h1 B" ]+ K
在 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 触发一般情形。
/ u9 r$ z4 F7 m: H% S$ B& s5 H. O9 s

8 Z# y% q0 X4 k% w
微信图片_20231130170527.png

. R+ O# R' l1 ~; ?6 [
3 Y/ L0 N% w# k0 s$ f需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。
4 ?* p( D3 C0 l1 H9 ^3 Q8 t
9 I- [0 j# }5 P3 [另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):
/ x9 U: s; b' Z+ ~1 U3 G/ P  }
  1. void SECURE_SetNMIHFBFTarget(int NS)' b. _4 V) a, m, k. A
  2. {5 f' m. L* _( J
  3. uint32_t reg_value;& y  [7 O% I: e, ~: q' Q
  4. uint32_t target = (NS==1)?1:0;9 V/ T  d8 {( ^& j
  5. /* read old register configuration */' a% I, F( P. Q4 R! Y
  6. reg_value = SCB->AIRCR;& e7 [  B5 r0 a! C& i/ T
  7. /* clear bits to change */9 N8 W6 r0 K  ]# t" ~8 v
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));" w) o5 i) T' Y: w( d
  9. /* insert write key and target bit */
    ) Q4 T: J5 l1 k7 n) B
  10. reg_value = (reg_value |, I5 q1 @  q: j# j, Z; K
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
    : \: f. o5 V  \$ f: k, z4 J, H% I! Q
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );; Q& X3 e; v1 m* ]. ?+ ]
  13. SCB->AIRCR = reg_value;- G5 o) x- _) e  _& X
  14. }
复制代码

' h1 ?) e" i. [) [% u) L注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。1 ~5 q/ O. i- H- |  a9 f

& p/ Z, p9 ]0 N; N

! e- ?% F3 w/ V( h$ E1.1.2. Bus Fault
% D8 I# {9 R/ M* fBus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。
  Q& `2 r- u" P  S# ?- I
9 N- \2 i$ [- X( j
在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。
& D4 y6 S. {0 }0 V& a8 @! H5 Z8 f
0 k' b" s4 E+ |& m* w
产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。2 ^8 D% ?9 N8 q3 m' U5 l0 M' m

. |6 e! [# `0 [1 ^/ H- X
微信图片_20231130170523.png
( T  U  i% Z) @5 I

5 B, S) w, o6 ?通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。7 l) ]. O* T  {1 C8 S1 w  Z

; Q" @# [0 P' ?  q) Q( F7 v" @如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。
5 `4 X0 v: h  u# F, o- n1 _; D# L* Z
" u/ w, M& n; ^! z7 g
如果 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 寄存器获取故障信息。
. X+ y$ I6 U/ M8 k, I2 e& O

9 s3 o" u0 K5 uBusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:
7 P- n1 K7 {0 p
  1. void EnableBusFault(int enable)
    8 ]/ ]5 Z6 G. f! l
  2. {6 j  \5 g4 D- w
  3. if( enable == 1)
    1 J0 n! Z3 U7 U6 b
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;! V0 c$ j1 D" [5 e* k# {
  5. else
    3 Y7 o( c! z2 O* n2 e
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);. ~' n. a! g9 d9 |
  7. }
复制代码

, C; U0 X7 E# U+ M& Y这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。  j2 G2 E6 m( n# ~
' r+ |: t# e1 P( e! j; Z8 A
如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。. h9 q4 `+ R8 [8 Q1 u2 ]( S3 f" p

1 ~9 h* U4 ^) x1.1.3. Usage Fault, D* b0 m/ A. o% a7 I
UsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。
( F4 D7 m/ U8 c
9 O3 C% d0 Y# P' e" J- x, o在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。
* G1 e) g, |4 }' ?3 |/ Z

4 Z5 o" P% |& P5 x使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。
$ w! e, B: F: r1 j- X1 _. w2 Z

7 n3 ]/ M5 G9 M5 L& R另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
% u% ^! R+ |- G9 M* O6 {+ [* t) x/ T( @* C
图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。3 W* B4 x7 d5 _# d* r: [
: M. U. G8 i! v1 Y. l5 A
微信图片_20231130170520.png

" k3 X" ^! |7 g& H7 N$ j  b6 w7 S3 U+ `
只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。
/ B# P/ v, s9 f
2 c' I  ]3 |. L; I+ |) K3 U使能或禁止 UsageFault 的示例代码如下:
) z/ }5 [+ }0 S
  1. void EnableUsageFault(int enable)
    ' U) c/ V% l) a. y5 Z
  2. {
    ( @6 V1 x/ ?; W' T
  3. if( enable == 1)* `1 K8 C9 P; P4 @7 K5 _
  4. {
    ) q7 i, K' U0 U. q: ~3 j
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    0 F; Y+ w, V. n! v
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */
    % S: T2 M& @& D8 \/ b1 G8 n
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
    / R8 a( n. q, K5 v$ h
  8. }
    ; x' i& a( g5 d1 a0 Q, R1 c
  9. else
    . V* X, ~! t3 y6 k
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);: c0 D1 m6 g# v* v/ S
  11. }
复制代码

6 r' |  g$ O1 s1 n% \. s如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。8 a# s7 x0 e/ A4 c* {  k  n
  1. void EnableNSUsageFault(int enable)
    8 Z2 l4 H% b3 r3 V
  2. {
    7 p3 v6 s, v* c4 o8 O
  3. if( enable == 1)2 a. w' `/ _! p1 N8 d
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;# m9 I- K7 g6 `% K
  5. else0 J1 U6 |- {! p1 ~3 V/ K4 V4 P" Z$ [
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);6 h) A! ^- c3 ?& h& b6 @
  7. }
复制代码
$ z. U4 ~0 O1 w, g3 X3 Y
1.1.4. MemManage Fault. Q; E- O" `* N. Z  ~& A" A
MemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。3 q  n9 m8 ~# h/ H  a

+ E1 d' L) U! V8 z# V* h8 fMemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。
. i2 ?# Z0 o( F% A
1 J; _' N: a& @+ `/ i
另外也与 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 处于非安全状态时候的访问,二者互不影响。* F& `2 u  g5 }1 f

6 ]. U6 g0 o" ?& w# w: u图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。. w) G3 V/ J# M% `9 e' J' d% `
微信图片_20231130170516.png

8 e' r. t- h" r8 E
微信图片_20231130170512.png

2 p' q; m* b( ~* A0 I
% w! l4 D7 I7 N; \; Q$ b4 A使能或禁止 MemManage Fault 的示例代码如下:
( [* ]' ~" _: V5 N9 S" y! a
  1. void EnableMemoryFault(int enable)3 N2 W5 _9 @: k7 L8 y+ ]
  2. {
    - @8 f! S4 \* C% n
  3. if( enable == 1)
    : u' S; R9 d% c- T, w2 Z0 L/ ^- s
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    ! f/ E8 ^. h8 ^% t% F- g9 z
  5. else
    / Z+ ~! P( Y1 T. ?. ?5 G
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    , L% o4 M1 i" j5 f: S$ ?0 ^' A1 @5 L
  7. }
复制代码
7 x( G5 I# K* r( N9 s; X$ V, G7 D/ W
如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。0 f2 N7 h! q' h+ `
  1. void EnableNSMemoryFault (int enable)
    * N" `7 C8 m- m% h' |2 M5 h  J* M
  2. {" a, C6 v3 @9 H% q* e$ F4 T
  3. if( enable == 1)
      a3 _) U! L% E: }7 A1 Q
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    5 Q. s. n, D+ ~: h
  5. else
    3 B. [; Q# A4 f+ K  @( c4 }
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);( J8 D2 X, R/ j+ q! [, a- Q5 h, v4 I, Y: c
  7. }
复制代码

* ?5 |, h) p3 K, z+ Q另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。
: P. K1 u% g/ j, d, J
& N4 g" T+ U& W2 i7 t* ^1.1.5. Secure Fault& q, B* N5 d8 T/ g
Secure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。
6 u4 x* B+ o' T: Z: M
, R* o( A* t' `' G! a: pSecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。5 Y9 M  n7 J. u; }

, o3 c& H" B' T8 z3 }* M* H" o
微信图片_20231130170508.png
5 o- ^5 q/ F+ f) ^, P
微信图片_20231130170459.png

& Z( C) f9 B  v, [% g
) V) m5 O$ q- K' ?0 t使能或禁止 SecureFault 的示例代码如下:2 p  K+ e9 }& i6 ^
  1. void EnableSecureFault(int enable); T) t5 I/ [7 I* S
  2. {3 ~3 W# O$ H- ^" D; l
  3. if( enable == 1). N% m2 ~, t/ V* T- i, i
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;( l1 i2 ~. ]- p7 I% R: T, W
  5. else
    1 _( A+ k- k4 L+ d6 o
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);* E) I% M" {+ H2 Q
  7. }
复制代码
0 m5 f( W; E8 ^$ \
1.2. 故障升级与 HardFault7 t6 {; e: n0 V3 m  k4 n% @
除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。' r" W4 B. p. m) O8 ~

2 c6 S2 E. n; _8 R& x某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。9 g) A% Z# t0 f: }
某个 Fault 升级成 HardFault 可能有多种原因,例如:- G' L8 P5 z6 H6 z, _, i
该故障 Fault 没有使能;% O3 a2 G) t0 c) P; ~. r

/ M! u! F% ~% s, [& L7 U3 ~% \例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.
; O) E* W, H; F* W该故障的 FaultHandler 优先级不够高无法运行;
  e7 U0 n# r. f# P0 r& j

) z  _9 i5 f  v' h, n例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。
, R! H1 Q0 G* ~7 b8 k. f9 B在故障的 FaultHandler 中产生了同样的故障;
: w0 H( A4 {) `
  @7 K" D. b7 V- n7 O: N例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。, [, R+ y. r8 D$ u! M& k
如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。" }: Y2 P1 o0 R* O0 a6 C
只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。# v( T. N( U6 t) f, p8 J
在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。& R+ b1 w. w' l
% b0 a: ?# y* q7 g
1.3. Fault 异常的安全状态
! ^5 p4 O2 K. A- p在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。/ ?3 s! D" I3 x0 n  E6 B9 Y. z
关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。
( Q  g( y4 r9 h
; E) }0 U- i% S: z
微信图片_20231130170455.png

5 @3 l4 k7 I- N7 f8 |
& I9 d+ Z5 O: ?( @# `9 x7 G: P1.4. 异常的进入与返回
5 k, ~" e' M  `! M1 ]) ^1.4.1. 异常的进入与 stack frame
# z7 T6 E4 ^" ~当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。0 u8 S/ E  d1 T& ]
当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
4 H2 n! |7 \! @# o0 F: f/ {通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。
- E6 |+ n$ }7 w  C+ Y- B$ e, A如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。
$ b8 D" T4 R0 c/ s6 j) Z/ Y$ ]- y进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。
; B9 Q3 Z5 j1 D0 T+ U7 g* A& m. w
/ S; }, t) F7 p4 ?+ N
. T6 h' q( ?( R
转载自: STM328 [* g! @; y9 K# j
如有侵权请联系删除
9 P! v& {: K: A/ d: t" b% F) O+ w( E6 N/ Q
8 d+ M! z& S- r: b& W

8 Y1 w6 Z4 e- n' f+ J
收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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