CM33架构之异常

前言

最近在学习一些M33相关的体系结构,看文档过程中顺便做一下记录。
以下是查阅 Arm® Cortex®-M33 Devices Generic User Guide文档过程中的一些记录。

异常模型

异常

安全模式下的异常:

  1. Reset:
  2. NMI:
    1. If AIRCR.BFHFNMINS=0, then the NMI is Secure.
    2. If AIRCR.BFHFNMINS=1, then NMI is Non-secure.
  3. HardFault:
  4. MemManage:
  5. BusFault:
    1. If AIRCR.BFHFNMINS=0, BusFaults target the Secure state.
    2. If AIRCR.BFHFNMINS=1, BusFaults target the Non-secure state.
  6. UsageFault:通常由指令错误产生
    • 未定义指令,不对齐访问,非法指令执行状态,错误异常返回,除零
  7. SecureFault:执行各种安全检查触发的,多半用于转跳到安全模式
  8. SVCall:SVC指令触发
  9. DebugMonitor:
  10. PendSV:
  11. SysTick:
  12. IRQ:

总结如下表:
CM33架构之异常_第1张图片
CM33架构之异常_第2张图片

非安模式下异常和安全差不多,就是没有 SecureFault

优先级

除了 ResetNMIHardFault 外,所有异常均可配置优先级,所以 Reset、NMI、HardFault 被称为固定优先级异常

拓展的优先级如下:

CM33架构之异常_第3张图片

可以看到,AIRCR.PRIS 控制着 安全异常是否可抢占 非安全异常。

原因:AIRCR.PRIS = 1 时,非安全异常优先级 < 安全异常优先级 (数字越小,优先级越高)

栈帧

  1. 非安全模式下触发非安全异常或中断的栈帧:
    CM33架构之异常_第4张图片

  2. 安全模式下触发非安全异常或中断时,会额外保存一些寄存器,如下:
    CM33架构之异常_第5张图片

  3. 安全模式下触发安全异常,分2种情况,FPCCR.TS=1或0
    CM33架构之异常_第6张图片

  4. 非安全异常不能触发安全异常

异常返回

进入异常的时候会保存一个 EXEC_RETURN 到 LR寄存器。EXEC_RETURN的低6bit用于表示一些属性,如处理器模式,安全状态等。

安全模式下的EXEC_RETURN如下图所示:
CM33架构之异常_第7张图片

非安全模式下的EXEC_RETURN如下图所示:
CM33架构之异常_第8张图片

状态转换如下图:
CM33架构之异常_第9张图片

  1. BLXNS:安全 -> 非安全(进入)
    • 调用非安全函数,名为FNC_RETURN的特殊值会保存到LR,并且 返回地址和 XPSR 会保存到安全堆栈
  2. BL:非安全 -> 安全(退出)
    • 下面的指令会将PC恢复成FNC_RETURN,触发从非安全返回安全,且自动从安全堆栈恢复返回地址和 XPSR
      • POP or LDM 指令来会恢复PC
      • LDR 指令来恢复PC
      • 使用任何寄存器的 BX 指令
  3. BX:非安全 -> 安全(进入)
  4. BXNS:安全 -> 非安全(退出)
  5. 除了上面标注列出的场景,其余状态转换都会触发SecureFault

故障类型

故障是异常的一个子集,产生故障的原因有:

  1. 总线错误
    1. 取址或数据访问
    2. 向量表加载
  2. 内部检测错误,如未定义指令
  3. 执行被标记为XN(Execute Never)区域的代码
  4. 违反特权或访问未管理区域而造成MPU fault
  5. 违反安全

故障类型有如下:

  1. HardFault
    1. VECTTBL:读取vector时发生总线错误
    2. FORCED:故障升级成硬件故障
  2. MemManage:MPU或默认映射不匹配引发,具体有以下情况
    1. IACCVIOL :在指令访问
    2. DACCVIOL:在数据访问
    3. MSTKERR:在异常入栈
    4. MUNSKERR:在异常出栈
    5. MLSPERR:在懒惰浮点保存
  3. BusFault:总线错误
    1. STKERR:在异常入栈
    2. UNSTKERR:在异常出栈
    3. IBUSERR:在指令预取
    4. LSPERR:在懒惰浮点保存
    5. PRECISERR:精确的数据总线错误
    6. IMPRECISERR:不精确的数据总线错误
  4. UsageFault
    1. NOCP:尝试访问协处理器
    2. UNDEFINSTR:未定义指令
    3. INVSTATE:试图进入无效的指令集状态
    4. INVPC:无效EXC_RETURN
    5. UNALIGNED:非法未对其访问
    6. STKOF:栈溢出
    7. DIVBYZERO:除零
  5. SecureFault
    1. LSERR:懒惰状态错误标志
    2. LSPERR:懒惰状态保存错误标志
    3. INVTRAN:无效转换标志
    4. AUVIOL:属性单元违反标志
    5. INVER:非法异常返回标志
    6. INVIS:无效完整性签名标志
    7. INVEP:非法入口

故障升级

除了HardFault之外,所有的异常都可以配置优先级。

某些情况下,可配置异常会升级到HardFault,这被称为优先级升级:

  1. 错误处理程序会导致发生与自己相同类型的错误,且他们具有相同优先级。这会被升级成HardFault,因为处理程序无法抢占自身。
  2. 错误处理程序会导致发生优先级小于等于自己的错误,这会被升级成HardFault,因为处理程序无法抢占当前正在执行的处理程序
  3. 异常触发,但是没有设置对应的处理程序

AIRCR.BFHFMNINS可以配置 BusFaults和固定优先级异常的安全属性:

  1. AIRCR.BFHFMNINS = 0:BusFaults和固定优先级异常是安全的,HardFault优先级=-1,NMI优先级=-2
  2. AIRCR.BFHFMNINS = 1:BusFaults和固定优先级异常是非安全的,且引入 Secure HardFault,优先级=-3

非安全状态下,不能影响以安全为目标的 BusFaults和固定优先级异常,所以 FAULTMASK_NS 只能影响到可配置异常。

非安全状态下,可配置优先级异常的优先级被映射到0-255,如果 AIRCR.PRIS =0,非安全可配置异常的优先级被映射到 128-255,如果 AIRCR.PRIS =1,非安全可配置异常的优先级被映射到 0 - 127。

当 BusFaults和固定优先级异常被配置为安全的,FAULTMASK_S 将设置为-1,来抑制包括 HardFault 在内的所有异常

当 BusFaults和固定优先级异常被配置为非安全的,FAULTMASK_NS 将设置为-1,来抑制包括 非安全HardFault 在内的所有异常,FAULTMASK_S 将设置为-3,来抑制包括 Secure HardFault 在内的所有异常。

Note

  1. AIRCR.BFHFNMINS = 1:只有Reset可以抢占 Secure HardFault,Secure HardFault可以抢占除Reset外所有异常
  2. AIRCR.BFHFNMINS = 0:Secure HardFault可以抢占除Reset,NMI,另一个HardFault外 所有异常

故障寄存器

  1. 故障状态寄存器:用于表示故障原因

  2. 故障地址寄存器:在 BusFaults 、 MemManage、 Security Extension表示发生故障的地址

  3. HardFault:状态寄存器名称 HFSR

  4. MemManage:状态寄存器名称 MMFSR,故障地址寄存器名称 MMFAR

  5. BusFault:状态寄存器名称 BFSR,故障地址寄存器名称 BFAR

  6. UsageFault:状态寄存器名称 UFSR

  7. SecureFault:状态寄存器名称 SFSR,故障地址寄存器名称 SFAR

PS:*FSR其实都对应一个故障状态物理寄存器,*FAR其实都对应一个故障地址物理寄存器

如果实现了安全拓展,会有2组4个寄存器,分别表示安全和非安全状态下故障的状态和地址信息

故障地址寄存器只有一个,需要清楚 *FARVALID 位,下一个故障才会更新该寄存器的值。

HFSR(HardFault)

故障寄存器

地址:0xE000ED2C

  1. bit[1] VECTTBL:故障发生在读取向量表
  2. bit[30] FORCED:指示一个强制的HardFault,由无法处理的具有可配置优先级的故障升级产生,原因可能是优先级或被禁用

CFSR(BusFault、UsageFault、MemManage)

可配置故障寄存器,表示 BusFaults 、 MemManage、 UsageFault 的故障原因

地址:0xE000ED28

bit分配如下图:
CM33架构之异常_第10张图片

下面所有位=1表示发生相应的故障

MMFSR具体位域分配:

  1. bit[0] IACCVIOL: 故障发生在 尝试去取不允许执行位置的指令
  2. bit[1] DACCVIOL: 故障发生在 尝试去访问不允许访问的位置
  3. bit[3] MUNSTKERR: 故障发生在 异常出栈
  4. bit[4] MSTKERRMSTKERR: 故障发生在 异常入栈
  5. bit[5] MLSPERR: 故障发生在 懒惰浮点保存
  6. bit[7] MMARVALID: MMFAR保存一个有效的故障地址

BFSR

地址:0xE000ED29

  1. bit[0] IBUSERR:指令总线错误,=1时,故障地址不会被写入到 BFAR
  2. bit[1] PRECISERR:已经发生数据总线错误并且异常返回的PC的值为发生故障的地址,=1时,故障地址会写入到 BFAR
  3. bit[3] UNSTKERR:异常出栈时候发生故障
  4. bit[4] STKERR:异常入栈时候发生故障
  5. bit[5] LSPERR:浮点惰性状态保存期间发生总线故障
  6. bit[7] BFARVALID:BFAR 保存一个有效的故障地址。

UFSR

地址:0xE000ED2A

  1. bit[0] UNDEFINSTR:未定义指令
  2. bit[1] INVSTATE:无效状态,表示 EPSR.T 或 EPSR.IT 合法错误发生
  3. bit[2] INVPC:非法PC
  4. bit[3] NOCP:无协处理器
  5. bit[4] STKOF:栈溢出
  6. bit[8] UNALIGNED:不对齐访问
  7. bit[9] DIVBYZERO:除零

MMFAR

地址:0xE000ED34

CFSR.MMARVALID = 1时,该寄存器保存一个有效的故障地址(bit[31:0])

BFAR

地址:0xE000ED38

CFSR.BFARVALID = 1时,该寄存器保存一个有效的故障地址(bit[31:0])

协处理器相关

CPACR

地址:0xE000ED88

  1. bit[2m+1:2m] m=0-7:控制 协处理器m 的状态
    1. 2b’00:拒绝访问,任何访问都会触发 NOCP UsageFault.
    2. 2b’01:允许特权访问,其余访问都会触发 NOCP UsageFault.
    3. 2b’11:所有均可访问
  2. bit[21:20]:控制CP10状态,控制浮点访问
    1. 2b’00:
    2. 2b’00:
    3. 2b’00:
  3. bit[23:22]:控制CP11状态
    1. 2b’00:不允许访问浮点拓展,任何访问都会触发 NOCP UsageFault.
    2. 2b’01:仅限特权使用浮现拓展,其余访问都会触发 NOCP UsageFault.
    3. 2b’11:所有均可访问

NSACR

地址:0xE000ED8C

主要控制NS对浮点拓展的访问,bit和CP编号一一对应,CP5对应bit5。

=1表示NS状态下能访问,=0 访问会触发 NOCP UsageFault.

SCB总览

里面列举了各个系统控制块寄存器的地址

CM33架构之异常_第11张图片

安全拓展

如果实现了安全拓展,处理器可以用安全属性单元(SAU)和内存保护单元(MPU)来管理敏感数据。

SAU

SAU用来检查地址或数据是否安全的。

寄存器

SAU相关的寄存器:
CM33架构之异常_第12张图片

SAU_CTRL

  1. bit[0] ENABLE:=1 使能SAU
  2. bit[1] ALLNS: 用来标记内存是否安全的,ENABLE=1时,这个Bit无效

SAU_TYPE

表示SAU实现的区域数

  1. bit[7:0] SREGION:SAU实现了多少个region

SAU_RNR

用于选择当前被 SAU_RBAR 和 SAU_RLAR 的region

  1. bit[7:0] SREGION:region号

SAU_RBAR

选择该region的基址。

  1. bit[31:5]:基地址,低5bit为0,意味着地址32字节对齐

SAU_RLAR

控制对应region是否是能,是否可被非安全调用(即非安全状态下在这个region执行SG指令)。

  1. bit[0]:=1 是能 SAU region
  2. bit[1]:=1 允许非安全呼叫

SFSR

提供和安全相关的故障信息,某bit=1均表示在该情况下发生故障(fault)

  1. bit[0] INVEP:无效入口,非安全或异常下调用安全状态下的目标(非SG指令)导致,如果调用目标是SG,该bit也会=1,但没有匹配的 SAU或IDAU 时,会设置 NSC 标志
  2. bit[1] INVIS:无效签名标志,出栈期间发现堆栈的完整性签名无效
  3. bit[2] INVER:无效返回标志,可能由 非安全状态返回时 EXC_RETURN.DCRS=0 或 异常返回时 EXC_RETURN.ES = 1 导致的
  4. bit[3] AUVIOL:属性单元违规标志,表示尝试去访问被标记为 使用Ns-Reg进行安全处理的地址空间
  5. bit[4] INVTRAN:非法转换标志,表示由于未标记分支指令导致从安全内存到安全内存而引发的异常
  6. bit[5] LSPERR:懒惰状态保存错误标志,表示在延迟保存浮点期间发现 SAU 或 IDAU 违规
  7. bit[6] SFARVALID:安全故障地址有效,表示 SFAR 保存一个有效故障地址。
  8. bit[7] LSERR:懒惰状态错误标志

SFAR

  1. bit[31:0]:保存引发SAU违规的地址

MPU

  • MPU定义了8个region。
  • 如果实现了安全拓展,可以由一个可选的安全MPU
  • 如果region重叠,访问重叠区域会引发一个fault
  • MPU内存映射是统一的,意味着指令和数据访问有相同的region设置
  • 如果程序访问MPU禁止的区域,会触发 MemManage 异常
  • MPU可以被动态配置

以下是MPU可能的region属性:

类型 共享 其余属性 描述
Device-nGnRnE 共享 - 用于访问内存映射的外设,所有访问顺序都是按照程序顺序进行的
Device-nGnRE 共享 - 用于访问内存映射的外设,比Device-nGnRnE更弱排序
Device-nGRE 共享 - 用于访问内存映射的外设,比Device-nGnRE更弱排序
Device-GRE 共享 - 用于访问内存映射的外设,比Device-nGRE更弱排序
Normal 共享 非cache的通写
可cache的回写
在几个处理器间共享的普通内存
Normal 不共享 非cache的通写
可cache的回写
仅供一个处理器使用的普通内存

寄存器

MPU相关寄存器:

CM33架构之异常_第13张图片

MPU_TYPE

记录是否支持MPU,由几个region

  1. bit[08]:
    1. 1b’0:统一的指令和数据区域,ARMv8-M只支持这个,固定=0
  2. bit[15:8]:ARMv8-M只支持8个,所以要么=8 要么=0

MPU_CTRL

控制MPU使能

  1. bit[0] ENABLE: =1 是能MPU
  2. bit[1] HFNMIENA:=1,允许在 HardFault 和 NMI 中操作MPU
  3. bit[2] PRIVDEFENA:=1 默认内存映射作为特权软件的后台映射,=0 然和 region之外的内存访问都会触发fault

Xn 和 Device-nGnRnE 规则始终应用在SCB空间,不受Enable位影响

PRIVDEFENA= 0,只有是能一个 region,ENABLE才能配置为1

PRIVDEFENA= 1,ENABLE = 1,且没有配置任何region,则只有特权软件能访问

ENABLE = 0,系统使用默认内存映射,行为跟没有MPU是一样的

HFNMIENA = 0,处理器处理优先级为 -1,-2,-3的异常时候,不启用MPU

MPU_RNR

bit[7:0]:配置 MPU_RBAR 和 MPU_RLAR 选择哪个region

MPU_RBAR

定义该region的基址

  1. bit[31:5] BASE:基址,低5位拓展为0
  2. bit[4:3] SH:共享属性
    1. 2b’00:不共享
    2. 2b’01:不可预测
    3. 2b’10:外部共享
    4. 2b’11:内部共享
  3. bit[2:1] AP:访问权限
    1. 2b’00:特权级别可读写
    2. 2b’01:任何级别可读写
    3. 2b’10:特权级别只读
    4. 2b’11:任何级别只读
  4. bit[0] XN:=1 该区域不可执行,=0允许读时,才可执行

MPU_RBAR_A

n = [1,3]

访问 MPU_RBAR_A = MPU_RNR[7:2]:n[1:0]

MPU_RLAR

MPU region的限制地址

  1. bit[31:5] LIMIT:限制地址,真实限制地址 = bit[31:5] + 0x1f
  2. bit[3:1] AttrIndx:属性所以,在 MPU_MAIR0 和 MPU_MAIR1 中关联一组属性
  3. bit[0] EN:=1 是能region

MPU_RLAR_A

n = [1,3]

访问 MPU_RLAR_A = MPU_RLAR[7:2]:n[1:0]

MPU_MAIR0/1

配置具体属性组。
CM33架构之异常_第14张图片

  1. MAIR_ATTR[7:4] = 4b’0000

  2. bit[7:4] = 4b’0000

  3. bit[3:2] = Device,格式如下

    1. 2b’00:Device-nGnRnE

    2. 2b’01:Device-nGnRE

    3. 2b’10:Device-nGRE.

    4. 2b’11:Device-GRE.

  4. bit[1:0] = 2b’00

  5. MAIR_ATTR[7:4] != 4b’0000

    1. bit[7:4] = Outer
      1. 4b’00RW:普通内存,外部直写瞬态(RW 不能是 00)。瞬态是啥意思?没看懂,猜测应该是写操作是否bufferable
      2. 4b’0100:普通内存,外部非cache
      3. 4b’01RW:普通内存,外部回写瞬态(RW 不能是 00)
      4. 4b’10RW:普通内存。外部直写非瞬态
      5. 4b’11RW:普通内存。外部回写非瞬态
    2. bit[3:0] = Inner
      1. 4b’00RW:普通内存,内部直写瞬态(RW 不能是 00)
      2. 4b’0100:普通内存,内部非cache
      3. 4b’01RW:普通内存,内部回写瞬态(RW 不能是 00)
      4. 4b’10RW:普通内存,内部直写非瞬态
      5. 4b’11RW:普通内存,内部回写非瞬态

更新 MPU region

实例:

; R1 = MPU region number
; R2 = base address, permissions and shareability
; R3 = limit address, attributes index and enable
LDR R0,=MPU_RNR
STR R1, [R0, #0x0] ; MPU_RNR
STR R2, [R0, #0x4] ; MPU_RBAR
STR R3, [R0, #0x8] ; MPU_RLAR

Note

  1. 软件必须在配置MPU前使用内存屏障指令
  2. 配置完MPU后,如果想立即生效,需要使用 DSP 和 ISB 指令

更新 SAU region

示例:

; R1 = SAU region number
; R2 = base address
; R3 = limit address, Non-secure callable attribute and enable
LDR R0,=SAU_RNR
STR R1, [R0, #0x0] ; SAU_RNR
STR R2, [R0, #0x4] ; SAU_RBAR
STR R3, [R0, #0x8] ; SAU_RLAR

Note

  1. 软件必须在配置MPU前使用内存屏障指令
  2. 配置完MPU后,如果想立即生效,需要使用 DSP 和 ISB 指令

MPU配置Tips

通常微处理器只有一个,且没cache的,MPU可以参考如下配置:

CM33架构之异常_第15张图片

你可能感兴趣的:(ARM,M33,架构)