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

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

[复制链接]
STMCU小助手 发布时间:2023-11-30 17:05
引  言3 I+ ~. c* F) I9 p  L" \
在 STM32 TrustZone 开发调试技巧的前两篇中,我们介绍了内核的 SAU/IDAU,地址的安全属性配置,资源的安全属性配置,内核访问资源的安全规则,以及 TrustZone 环境下外设使用的常见问题等内容。TrustZone 环境开发中还可能经常遇到的一个问题就是软件触发的故障错误。ARM CM33内核 TrustZone 环境下的异常模型以及 Fault 的处理与不带安全扩展的情况有着很多变化,一旦出现 HardFault,经验不足的开发者可能往会找不到头绪,不知道从哪里着手寻找问题所在。因此,在这一篇的重点将围绕 CM33 TrustZone 环境下的异常模型以及 HardFault 的调试与处理展开,供开发者参考。
3 F' t  ]/ n" f6 V* W* G: S# p9 }& U& h9 X
一、CM33 TrustZone 架构下的异常模型6 c2 M4 D) f, v, e
在 STM32 TrustZone 开发调试技巧的第二篇中我们介绍过 CM33 带安全扩展的 S 和 NS 侧的中断以及中断向量表,这里不再赘述。表 1 总结了其中的 Fault 异常。
  f0 I  f6 L/ O9 ]7 f9 g- {/ s9 U+ D+ N7 [5 B; f) R$ d+ [" I
微信图片_20231130170530.png
- p$ ?, q1 _9 r$ I! D
6 }: g: Z7 k; e7 M7 X: S$ a0 g, g: v
1.1. Fault 异常类型(带安全扩展)
: `3 E# v. I  W) z, h! o$ D7 _5 ^1.1.1. Hard Fault
& V& ?" w! ~2 h8 o& c* AHardFault 是默认的 Fault 异常,总是使能。触发的原因可能是由于异常处理本身触发了错误,或者某个异常无法被其他机制处理而上升到 HardFault。它的优先级高于所有其他可配置优先级的异常。8 S0 Q6 y" [9 V1 W; e
- d0 R& J* s/ j& h: S* n, `
在 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 触发一般情形。
# K$ h" R' \7 b# u' j3 F8 I1 Q; q! y/ o3 ]* q1 e" }
7 y% z: D3 c( Q$ w& y
微信图片_20231130170527.png
' D  B0 @3 p2 \1 ?5 m4 J

8 |5 h+ L% h, {需要注意的是,即使 AIRCR.BFHFNMINS=1,原本 target 到 S 侧并且上升为 HardFault 的异常,将依旧触发 S 侧的 HardFault,他们并不受到 AIRCR.BFHFNMINS 位的影响,例如当安全代码违反 MPU 保护规则,产生 MemManage 错误的时候,即使 AIRCR.BFHFNMINS=1,故障还是会进入 Secure HardFault Handler。而 NS 侧的 HardFault,只有当AIRCR.BFHFNMINS=1 时才有可能会被触发。7 w3 U/ W. G/ y# i5 M8 u" \

9 _) l! n6 Z/ x5 u另外还要注意一点,AIRCR 寄存器不能直接修改,需要先写 Key 值才能更改寄存器内容。置位或清除 AIRCR.BFHFNMINS bit 的示例代码如下(只能在安全代码中使用):
& O) d9 ^7 g# @
  1. void SECURE_SetNMIHFBFTarget(int NS)6 T$ `5 A& Z8 x
  2. {
    ' Z, C# N5 `( }8 h
  3. uint32_t reg_value;# l7 j# Z( V! o
  4. uint32_t target = (NS==1)?1:0;
    & o! r8 G- A8 _0 _) {
  5. /* read old register configuration */- B) A6 _' C6 E+ W
  6. reg_value = SCB->AIRCR;) _% w! i7 C' |! ]3 P
  7. /* clear bits to change */9 r! N2 L5 I. d. I: G- v
  8. reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_BFHFNMINS_Msk));
    9 K8 \3 M8 |3 S0 A+ \- A' C" n/ T% f' J
  9. /* insert write key and target bit */" q+ d! V) p: N3 b( P. I8 F
  10. reg_value = (reg_value |
    ( k( G. k/ k5 O/ I
  11. ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |) ^3 b5 e3 I) Y. j! V7 p
  12. (target << SCB_AIRCR_BFHFNMINS_Pos) );
    % o1 g8 b8 R# U# s& E
  13. SCB->AIRCR = reg_value;
    9 {, Q% P, \# A" Z
  14. }
复制代码

: c9 S. o8 r0 R. @, o" e注意:有的时候,软件可能需要设置 AIRCR.PRIS 位,来整体降低 NS 中断的优先级(例如在 TF-M 的实现中就使用这个机制)。这时候,如果同时设置 AIRCR.PRIS=1,AIRCR.BFHFNMINS=1,内核的行为将不可预测。因此如果需要设置 AIRCR.PRIS=1,则建议保持 AIRCR.BFHFNMINS=0。
0 Z. E7 [0 H' w, n
. ^  d) c  U5 @3 K& G6 x

4 z1 C5 t% n1 j/ y2 ^* N2 \9 L1.1.2. Bus Fault
6 C, l  O/ L, w, RBus Fault 通常发生在指令或数据访问时候,可能由于检测到 memory 系统的总线错误而导致。Bus Fault 默认不使能,就是说总线故障默认将触发 HardFault Handler。如果需要单独使能 Bus Fault,可以将 SCB 的 SHCSR.BUSFAULTENA 位设 1。
$ y& o& _/ n. y3 }

8 M/ q0 O/ u" g6 `- F) M4 K在 TrustZone 环境中,Bus Fault 也不是 Bank 的。触发 S 还是 NS 侧的 BusFault Handler与SCB 的AIRCR.BFHFNMINS 有关。如果 AIRCR.BFHFNMINS=0,BusFault 总是 target 到S 安全状态;反之如果 AIRCR.BFHFNMINS=1,则 target 到 NS 非安全状态。
1 I: s( X1 j6 D2 U

1 {/ l+ b, {/ i产生 Bus 错误时,实际会触发哪个 Fault Handler,将取决于 AIRCR.BFHFNMINS 和SCB_S/NS 的 SHCSR.BUSFAULTENA 的设置。图 2 给出了 Bus 错误触发 Fault Handler 的一般情况(例如这里不考虑安全侧 Vector 错误依旧上升到 Secure HardFault 的情况)。
3 k* h) G8 \7 V: u" M  {5 d% _% f7 e/ o' j
微信图片_20231130170523.png

1 u1 f7 m& J% U* z; s" L
" h% G+ S6 I2 ]- s通常情况下,SCB 的 CFSR/BFSR 和 BFAR 寄存器中会标记总线故障信息。在 TrustZone环境中,SCB 的某些寄存器以及寄存器的某些比特位是 Bank 的。从安全侧和非安全侧都能够看到各自的 SCB 寄存器,但是 CFSR 寄存器的 BFSR 域以及 BFAR 寄存器并不是 Bank 的。而 Bus 故障可能 target 到 S 安全侧也可能 target 到 NS 非安全侧,当发生总线错误的时候,如果分别从 SCB_S、SCB_NS 的相关寄存器中读取 Bus Fault 的信息,可以看到不同的结果。
) ^3 M9 `" U! N) Z" j/ w) V$ c0 Y8 e! w" P9 h( E) j7 M/ b
如果 AIRCR.BFHFNMINS=0,只有安全侧可以看到 BFSR 和 BFAR 的真实数据,非安全侧读取 BFSR、BFAR,或者从安全侧读取 BFSR_NS,BFAR_NS 都只能读到全 0 的值。  H7 f4 C3 P0 P0 d8 o
4 E& a2 i6 N( e) |; Q
如果 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 寄存器获取故障信息。) d4 b& O- R* w5 p# B
1 \- o/ g6 k1 z* O
BusFault 默认没有单独使能,如果需要使能 BusFault,可以将 SHCSR 寄存器的BUSFAULTENA 位置位。使能或禁止 BusFault 的示例代码如下:2 w) l4 S: R% N0 v4 @9 U: Q
  1. void EnableBusFault(int enable)
    4 B# `4 X( w: A
  2. {
    7 A* \% K4 ?8 ?) U
  3. if( enable == 1)
    2 L% r  b/ s0 Z" c
  4. SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
    4 g8 |6 ^2 |0 v1 I+ k: E
  5. else% [& n3 ~, d0 b/ a6 D! }
  6. SCB->SHCSR &= (~SCB_SHCSR_BUSFAULTENA_Msk);
    ) N' [9 k* I, p! e0 ~
  7. }
复制代码

' [, Y  A- P5 Q8 b8 p这段代码对安全和非安全侧都是一样的,但是要注意,由于 BusFault 不是 Bank 的,当AIRCR.BFHFNMINS=0 时,这段代码只能在安全侧使用,也就是修改的是 S 安全侧 SCB SHCSR 的 BusFault,此时写 SCB_NS 的 SHCSR.BUSFAULTENA 位无效。8 q7 Q6 j* l6 }4 C9 _6 ^; M4 A

# ?+ x( K  T' P+ x如果非安全侧应用使用这段代码使能 BusFault,那么前提是安全侧已经设置了AIRCR.BFHFNMINS=1。& M/ b/ c, C- |: G/ K  e' C2 C, E

2 |9 }3 U3 M  I. W& k4 ]3 `% a# w1.1.3. Usage Fault
, v% }8 a% Q. y; N1 d; }! ]UsageFault 与指令执行时候的错误有关,包括未定义的指令、非对齐访问、执行指令时的无效状态、中断返回时的错误、除 0 等。) H% J. c: O5 [0 [9 L

/ C) ?1 {' H8 w; O! `) c# h* x% V在 TrustZone 环境中,UsageFault 是 Bank 的,因此在 S 和 NS 状态可能产生各自的UsageFault,并且可能触发各自的 S UsageFault Handler 和 NS UsageFault Handler。UsageFault 默认不使能,因而缺省会上升到 HardFault,是否触发 S 还是 NS 的 HardFault Handler 还要取决于 AIRCR.BFHFNMINS 的值是 0 还是 1。4 }7 b  ^, m5 }3 V4 B+ q% B4 Z

% u, @* g$ _8 J2 \; N使能UsageFault 需要分别设置 SCB_S 和 SCB_NS 的 SHCSR.USGFAULTENA。SCB_S的 SHCSR.USGFAULTENA=1 用于使能 S 安全侧的 Usage Fault;SCB_NS 的SHCSR.USGFAULTENA=1 用于使能 NS 非安全侧的 Usage Fault。
& Z( M. N6 R1 l9 ?  g$ y% V# R( x, t. K8 b
4 @/ u8 m& e* X
另外,通常除 0 操作不会触发 UsageFault,如果希望除 0 操作触发 UsageFault,需要将SCB_S/NS 对应的 CCR.DIV_0_TRP 比特置 1。
5 {( T: \3 _5 c
+ t" N2 u+ c' F图 3 总结了 Usage 错误触发 Fault Handler 的一般情况。$ k% Y& x  M8 p' V; M
# ], V9 m& f5 i& F2 @) A9 \
微信图片_20231130170520.png

- y5 A7 `5 ^1 T( Z  C+ ^3 N7 j$ \- k! f+ |( w; Q2 {# Z
只要 SHCSR.USGFAULTENA=1,UsageFault 总是触发软件对应安全状态的 UsageFault Handler,否则上升到 HardFault,安全侧的 UsageFault 总是上升到 Secure HardFault。对于非安全侧的 UsageFault,如果 AIRCR.BFHFNMINS=0,则上升到 Secure HardFault,否则上升到 Non-Secure HardFault。$ G" d( l; M: z) @5 m( R* h' C

- t$ k3 w- N( [) a" N, e& `7 c, Z使能或禁止 UsageFault 的示例代码如下:, l. K; Q& N0 H
  1. void EnableUsageFault(int enable)2 C9 B- n1 Q9 [3 o$ `" U. f4 G( f- }$ a
  2. {
    ! {  c  ]% Q2 F! L6 |
  3. if( enable == 1)7 S4 d# l$ ]8 x( v
  4. {% c1 ^( w9 B! z9 g( d! j5 o
  5. SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    $ P& Y; s3 C* b# W- y
  6. /* Enable divide by 0 trap to trigger usage fault (if necessary) */4 ?" O8 h) C$ K' A& Y
  7. SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
    . f, k/ T; X) e; f
  8. }
    & k- v- J8 Q# |6 q
  9. else3 G5 B' b. m/ j5 g
  10. SCB->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);) q7 _" a2 L' ?5 G8 M+ `
  11. }
复制代码

* o  O  G0 |- l" w如果安全和非安全侧都需要使能 UsageFault,则 S、NS 代码可以分别调用这段代码使能各自的 UsageFault,或者 S 安全侧代码也可以直接控制 NS 非安全侧 UsageFault 的使能,例如可以在 S 安全侧增加下面这段代码来决定 NS 侧的 UsageFault 是否使能。
1 `% z- g0 X  i, E( s+ R7 G
  1. void EnableNSUsageFault(int enable)* O4 L$ E8 C- A
  2. {
    7 ^% q3 `/ [4 L. |" h3 E
  3. if( enable == 1)
    % B* H' Q" @. u# X
  4. SCB_NS->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
    5 ~3 e  a% `( J" N$ R# x
  5. else3 w+ E) d# m9 |, {& e
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_USGFAULTENA_Msk);
    / p4 b9 ~( a. r' d
  7. }
复制代码
- s. v! [8 _1 z- L7 X3 W- d. r+ t
1.1.4. MemManage Fault3 a7 \+ @, o/ a! v7 R5 h9 {+ X8 H  M
MemManage Fault 是由于 Memory 保护产生的故障异常,例如在取指令或进行数据访问时违反了 MPU region 定义的访问规则,或者违反了默认地址保护规则。0 z* X1 }, N( _$ E+ G

" b( W5 e' b& Q$ [0 P+ MMemManageFault 与 UsageFault 类似,也是默认不使能,如果希望使能 S 或者 NS 侧的MemManageFault,需要相应将 SCB_S 或者 SCB_NS 的 SHCSR.MEMFAULTENA 比特置位。
; V9 T& D$ t6 ]) K4 ?
' w! J# Y+ P5 L5 Q% d
另外也与 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 处于非安全状态时候的访问,二者互不影响。3 F; K, T7 |( q( g

2 J3 `7 {: c: B2 @: D' h图 4 给出了 MemManage 故障触发 Fault Handler 的一般情况。如果 S 安全代码违反memory 访问规则,可能会触发安全侧的 MemManageFault,或者 Secure HardFault。非安全代码违反 memory 访问规则,可能会触发非安全侧的 MemManageFault,或者上升到HardFault,如果 AIRCR.BFHFNMINS=0 上升到 Secure HardFault,否则上升到 Non-Secure HardFault。4 S) }7 }) T% ]% n: d
微信图片_20231130170516.png
8 B0 R' i  \& T( \
微信图片_20231130170512.png

- U7 a" ]3 N, |) i  P2 d
7 x. C# O0 v" U8 b6 k3 N使能或禁止 MemManage Fault 的示例代码如下:; Q+ `$ z+ d1 H
  1. void EnableMemoryFault(int enable)5 Z% n' [) w* u% s* T* t
  2. {; r8 U0 P& U5 B8 M
  3. if( enable == 1)4 _( o8 ^6 q( n8 r# |# G7 I
  4. SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    ) i3 A/ I2 @2 `4 h4 a/ a
  5. else
    ; p$ U5 b0 ]  O) ^2 x
  6. SCB->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    ; G9 L8 t% V9 e5 T- e5 ?
  7. }
复制代码

* @! O6 c6 H9 s& i1 t如果安全和非安全侧都需要使能 MemManage Fault,则 S、NS 应用可以分别调用这段代码使能各自的 MemManage Fault,或者 S 安全侧代码也可以直接使能 NS 非安全侧的MemManage Fault,例如可以在 S 安全侧增加下面这段代码来控制 NS 侧的 MemManageFault 使能。. ]- r. N& R4 J" k& O' l
  1. void EnableNSMemoryFault (int enable)
      P/ o5 \7 g) ~
  2. {: _8 A" n5 m" e! [4 k1 d5 Z
  3. if( enable == 1)9 n# K( `& V/ d" `+ P
  4. SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    ( s  [! R$ ]! K" n: E$ V, h
  5. else* g3 ?  n0 j: r+ L  E* }
  6. SCB_NS->SHCSR &= (~SCB_SHCSR_MEMFAULTENA_Msk);
    ; k! i4 e8 B* t# }  H, {
  7. }
复制代码
* p$ i( s; {6 L( f! }6 w
另外,如果代码使用 HAL API 使能 MPU,即调用 HAL_MPU_Enable(),那么MemManage Fault 在 MPU 使能的函数中会自动被使能,这时候无需额外调用前面提到的代码去单独使能 MemManage Fault。' Q2 u% C2 M* G$ d, j: ?( l8 K% M" F
& v: u2 z$ w3 _5 y
1.1.5. Secure Fault1 [$ e4 Z9 n% p6 q" d
Secure Fault 只有在 TrustZone 使能的环境下才存在。SecureFault 可能由于内核中各种各样的安全检查而触发,例如从 NS 跳转至 S 代码时没有从 SG 入口指令进入,或者非安全代码试图访问 SAU/IDAU 规定的安全地址范围等。通常当出现 SecureFault 时,软件的处理可以是直接停止或者复位系统,这样做可以尽可能地避免引入安全漏洞。9 \$ j. T1 W& j9 O6 B" y' w

. B; w" ?) X2 aSecureFault 不是 Bank 的,总是 target 到 S 侧,因此只有安全代码能够处理SecureFault。SecureFault 缺省也没有使能,出现 Secure 错误时,默认触发 SecureHardFault。软件可以通过置位 SHCSR.SECUREFAULTENA 来单独使能 SecureFault,使能后Secure 错误将触发 SecureFault Handler。图 5 给出了 Secure 错误触发 Fault Handler 的一般情况。
) {9 y* F3 z9 [# n5 j' K
! d9 Y; E# R7 {( `2 B
微信图片_20231130170508.png
5 X! ?; s/ z" ?' b+ b4 ~  q
微信图片_20231130170459.png

; _7 ~* H! t+ b: i) z4 \; C5 q2 r  j9 C' J* y! l# s
使能或禁止 SecureFault 的示例代码如下:9 V) `- T- A5 w4 d
  1. void EnableSecureFault(int enable)
    2 e4 A% l( T, }7 @3 [
  2. {
    6 K: b7 ~1 {) }' L
  3. if( enable == 1)
    6 g' U: B! y* H; J/ y/ V* o! `
  4. SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;% K$ b0 q" i# w- M
  5. else/ q" U/ K/ I0 c- P5 r0 r
  6. SCB->SHCSR &= (~SCB_SHCSR_SECUREFAULTENA_Msk);
    + p$ r) f# [6 Q& S. _2 P! K9 I
  7. }
复制代码

" l$ Y) l! v* }$ E1.2. 故障升级与 HardFault: Y# I/ \- f% V. Y
除了 HardFault 以外,其他故障类型都具有可配置的优先级。软件可以禁止某个可配优先级的故障异常,但是不能禁止 HardFault。故障异常的优先级和对应的 mask bit 决定了内核是否会进入某个故障的处理程序,以及某个故障是否可以抢占另一个故障。
# U* P4 @6 S0 j. g- W, D9 V
' r$ X# S- v* p: d0 Z( O; Q
某些情况下,可配置优先级的故障可能会被当成 HardFault 处理,也就是故障升级或称中断上访,此时,这个具体的 Fault 会升级为 HardFault 故障。
8 G7 u& v  N/ C7 Z/ h6 V  X某个 Fault 升级成 HardFault 可能有多种原因,例如:& ^/ ?. `" |7 r7 R2 Y* w+ Y, i
该故障 Fault 没有使能;
! k; s5 ?8 \8 X1 `4 ~& C0 d' D8 ?8 ]: M! T! {& K2 f
例如,代码由于执行未定义的指令产生了 UsageFault,但是 UsageFault 没有被使能.) L1 X# k* R4 J: h/ m' z) W
该故障的 FaultHandler 优先级不够高无法运行;
! W0 n  d6 b& w! u/ I+ l: e9 z5 S+ `
% d# ^$ b+ [& l0 s  s; |
例如,系统配置并使能了 MPU,CPU 正在执行某个中断操作,该操作试图进行地址访问时违反了 MPU 定义的访问规则,进而触发了故障,但是当前执行的中断的优先级高于 MemManage 故障的优先级。
% i5 `5 A) P0 R" H* Z1 p在故障的 FaultHandler 中产生了同样的故障;
" h. S% y; r  l0 _5 n  p8 T9 L$ A" F# r7 v
例如,在处理 UsageFault 的 handler 中又发生了未定义指令的情况。
$ M( ]( @8 i2 ~6 `" A9 v' o如果在进入 BusFault Handler 的时候,压栈操作又导致了 BusFault,这种情况下 BusFault 不会升级到 HardFault。这意味着,如果损坏的堆栈导致故障,即使 Fault Handler 压栈失败,故障处理程序还是会执行,但堆栈内容已损坏。) b* t1 R) m  ?: }  E" o
只有 NMI 可以抢占 HardFault,HardFault 可以抢占任何除 Reset、NMI 或者另一个HardFault 以外的异常。当 BFHFNMINS=1 时,如果 NS 侧的 NMI Handler 产生了安全违规错误,那么它将触发 Secure HardFault,并被其抢占。
" g9 I$ ]* E+ w在获取异常向量的时候发生的 Bus 错误,总是升级到 HardFault,由 HardFault 处理,而非 BusFault。
0 Z2 G0 T1 W& X
$ L, h, S: i. ^- C1.3. Fault 异常的安全状态5 m1 ?, _9 g; B- h3 x" W( s
在 TrustZone 使能的环境中,故障异常可能 target 到 S 安全状态或 NS 非安全状态,这会导致 ARMv8-M 内核的行为与以往 ARMv6-M 及 ARMv7-M 内核有很大不同,TrustZone 环境软件开发中对 Fault 的处理要特别注意到这一点。
% q, A3 J9 P" d关于 Fault 异常 target 到 S、NS 的情况在前文中介绍几个 Fault 类型的时候已经有提到,这里在表 2 中再稍加总结。2 ~0 D4 a  X0 U; u- E  E+ ~

/ m# s3 s' i% f8 x6 ?
微信图片_20231130170455.png

2 y* v8 J* u* |2 I- \$ j$ p: p& T6 y0 g  K5 J  R
1.4. 异常的进入与返回
# J9 v  w. Z5 G& c# h( G1.4.1. 异常的进入与 stack frame* I- L5 ]6 Z8 P  Z6 C# W8 b
当处理器处于线程模式且系统存在具有足够优先级的 pending 异常时则会进入异常,或者新异常的优先级高于正在处理的异常,这时候新异常将抢占原始异常,即出现异常嵌套。# v, U3 ?3 d. i. F2 W
当处理器发生异常时,除非该异常是尾链异常或延迟到达的异常,否则处理器会将上下文信息压入堆栈,压栈的数据结构即 stack frame。
5 ^6 q" y& Q- ?6 F& m通常 stack frame 的内容如图 6 (a) 所示,包含了 R0 到 R3、R12、LR、PC 和 xPSR 的内容。在 TrustZone 使能的环境中,如果 S 安全代码执行被 NS 非安全异常抢占,那么进入非安全异常前会有更多的信息压栈,如图 6 (b)所示,并且硬件会自动将压栈的寄存器清零,防止任何安全状态下的数据暴露给非安全代码。5 \! T2 q2 R2 a" s/ T, A
如果使用了浮点功能,存在浮点上下文,那么内核也会自动将浮点相关的上下文内容压栈。由于浮点部分数据内容对我们通常的 Fault 调试没有太多帮助,这里不做赘述。
4 `/ W6 }9 ~3 k3 b进入异常前的 stack frame 压栈操作使用 MSP 还是 PSP,取决于当时内核的运行状态及其使用的堆栈。如果当时 CPU 运行于 Handler 模式,则使用 MSP 压栈 stack frame;如果 CPU运行于 Thread 模式,由当时的 CPU CONTROL.SPSEL 位来标记使用的堆栈。
/ G2 I3 B% _1 Y* e, T) K0 d; R+ q
. F. Y& S) g) \! b9 i  C; B5 c
3 A; v8 D+ N% q0 t. e% P
转载自: STM32# }9 \( ~# A/ C* i$ A
如有侵权请联系删除, F  w8 o/ m  x) J- \( P/ t
9 k/ U% U! A5 M' t6 t
9 f. i# X% H0 j( ]
. j5 X0 Y/ R8 D3 |
赞 收藏 评论0 发布时间:2023-11-30 17:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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