干货 | 关于Armv7m异常进入的经验分享

一、 概述

这里主要介绍异常的进入行为(不包括复位异常)。(这里主要参考 armv7m)。

二、异常进入

在发生抢占的时候(异常发生且开始执行),硬件将上下文状态保存到一个 SP 寄存器指向的栈中,使用的堆栈取决于异常发送时处理器的模式。

在 armv7m 中使用 全降序栈,也就是压栈的时候 SP 地址递减,出现的时候 SP 指针递增

        压栈的时候,硬件将保存 8 个 32bit 数据,包括 xPSR、ReturnAddress、LR、R12、R3、R2、R1、R0。如果存在浮点扩展,那么还会将 FP 状态压入栈或者仅为状态保留空间(状态指 S0~S15 和 FPSCR)

        异常进入行为如下:/*如果在压栈期间出现故障,PushStack 能放弃内存访问,然后会根据派生异常决定下一步行为*/

ExceptionEntry(integer ExceptionType):

PushStack(ExceptionType);

ExceptionTaken(ExceptionType);

2.1 压栈

(1)检查是否有 FP 扩展且是否 active FP扩展,如果有,压栈需要 104 字节且栈强制 8 字节对齐;如果没有,压栈 32字节,对齐根据 CCR.STKALIGN

(2)检查当时使用 SP 是 PSP 还是 MSP,当前使用那个就会在哪一个里面进行压栈,压栈值如下:
          如果没有 FP 状态需要压栈,那么就仅压栈 R0~R3、R12、LR、 ReturnAddress(也就是在异常返回时候要返回的地址) 和 ( XPSR<31:10>: frameptralign:XPSR<8:0>)
          如果有 FP 状态需要压栈,则 还需要 预留 S0~S15、FPSCR 的空间,根据  FPCCR.LSPEN 看是否要压栈还是仅仅是预留,等于 0 说明 FP 状态也要一起压栈,等于 1表示仅仅预留改空间,但不将数据写入

(3)对于 LR 寄存器,这里存的是 是否启用了 FP 扩展和 使用的是 MSP 亦或 PSP 信息,用于后续的返回,也就是  EXC_RETURN 值

注意:关于 ReturnAddress。如果是同步异常,那么会返回到未进入异常时候执行的地址,但如果是异步异常,那么就会返回到下一个地址

如下,是无 FP 扩展的压栈过程,这里上下文状态称为基本帧(这里以 8 字节对齐为例)

干货 | 关于Armv7m异常进入的经验分享_第1张图片

  (图片来着 ARM:《DDI0403E_d_armv7m_arm.pdf》)

以下是有 FP 扩展的压栈过程,这里上下文状态称为扩展帧(这里以 8 字节对齐为例)

干货 | 关于Armv7m异常进入的经验分享_第2张图片

(图片来着 ARM:《DDI0403E_d_armv7m_arm.pdf》)

        如上,是异常进入压栈的过程。

2.1.1 压栈对齐

        首先是栈指针是 4/8 字节对齐(如果没对齐会在压栈这里对齐),在将 PSR 压栈的时候,使用 PSR[9] 指示是否有重新对齐栈(正常情况下这个位是保留的,1表示栈有重新对齐过,后续会与 EXC_RETURN[4] 联合确定 SP 是否经过调整)。如果有 FP 扩展且使用了改扩展,强制使用 8 字节对齐。

        对于有 FP 扩展的,压栈上实现了三种模式:(CONTROL.FPCA、FPCCR.ASPEN 和 FPCCR.LSPEN 决定了哪种模式,该寄存器只有特权模式才能访问):

(1)栈不保存 FP 状态,只压入基本栈(CONTROL.FPCA=0)

(2)栈按照扩展帧保留空间,但只写基本帧信息(FPCCR.LSPEN =1 且CONTROL.FPCA=1或FPCCR.ASPEN=1),如果后续软件处理尝试会用到 FP 指令,那么就会将 FP 状态保存到保留的空间,然后将 FPCCR.LSPACT 设置为 0

(3)栈写入扩展帧数据(FPCCR.LSPEN =0 且CONTROL.FPCA=1或FPCCR.ASPEN=1)

注意:在没有 FP 扩展使能的情况下,如果使用的是 8 字节对齐,在进入到退出的过程中将 CCR.STKALIGN 设置为 0,且 SP 进入时候不是 8 字节对齐,那么可能会导致系统损坏。

2.2 异常执行

(1)设置 PC 值,指向 异常处理函数入口,这里仅仅只是设置 PC 值而已,还没执行

(2)将模式改为 Handler

(3)将异常向量号写入 IPSR

(4)禁用 FP 扩展,使用 MSP

(5)将该向量号设置为激活状态

2.3 故障调试

        从上面可以看出,在进入 故障 ISR 之后,其实如 LR、PSR 这些寄存器可参考意义相对较小,但我们仍旧可以在这里获取当前异常类型(IPSR)和栈顶(SP,在无 SP 溢出和其他会对栈数据进行破坏情况下)

        通过 SP 指针,我们可以找到压栈的数据,这里有 ReturnAddress 数据可以让我们清楚的知道运行到那个地址出现了该错误。

        通过获取当前的异常类型,可以知道是那种异常进入了处理。如果是故障,还可以 SCS 里面的 CFSR、HFSR、MMFAR、BFAR、AFSR、

三、参考文档

ARM:《DDI0403E_d_armv7m_arm.pdf》

欢迎登录大大通,了解更多精彩内容!

你可能感兴趣的:(NXP产线,大大通,经验分享,笔记,arm,arm开发)