代码造成进入异常中断
异常类型
Fault的原因
- 默认 只要HardFault,其他Fault需要手动打开
使能Fault处理
这些Fault异常默认都是禁止的,所以都会上访成HardFault。可以通过系统处理控制和状态寄存器(SCB->SHCSR)来使能,将位16~位18置1就会使用这些Fault异常。
状态寄存器(SCB->SHCSR) | ||
---|---|---|
16 | MEMFAULTENA | |
17 | BUSFAULTENA | |
18 | USGFAULTENA |
- (MemManage Fault)存储管理错误
MemManage错误由MPU配置定义的访问规则引发。例如,非特权的代码访问了只支持特权访问的存储器区域,向被MPU定义为只读的存储器位置进行写操作,试图从不可执行区域(XN)执行代码。这些访问可以是在指令执行,取指期间的数据访问或执行过程中的栈操作。
Memory Manage Fault(MFSR),地址:0xE000ED28 | ||
---|---|---|
7 | MMARVALID | MMARVALID位为1,可以利用MemManage错误地址寄存器(SCB->MMFAR)确定引发错误的存储器地址。 |
6:5 | ||
4 | MSTKERR | 入栈访问不允许区域 |
3 | MUNSTKERR | 出栈访问不允许区域 |
2 | ||
1 | DACCVIOL | 不可访问区域读写数据,为1错误的代码可由栈帧中的PC定位 |
0 | IACCVIOL | 不可访问区域读指令,为1错误的代码可由栈帧中的PC定位 |
- 总线错误
Bus Fault是由存储器访问期间从处理器总线接口上收到的错误响应触发。包括取值,数据读写和栈操作。如果取指产生了总线错误,只有错误的位置进入执行阶段时才会触发总线错误。
总线错误分为精确的总线错误和不精确的总线错误两类。精确的总线错误是在存储器访问指令执行后错误异常立即产生。不精确的总线错误是因为处理器总线接口上存在写缓冲,存储器访问指令执行一段时间后才产生错误异常。有时候为了方便调试可以使用辅助控制寄存器中的DISDEFWBUF位禁止写缓冲。
SCB->CFSR中的第二字节是Bus Fault(BFSR),地址:0xE000ED29 | ||
---|---|---|
7 | BFARVALID | BFAR寄存器有效(BFAR 保存总线故障地址) |
4 | STKERR | 入栈错误 |
3 | UNSTKERR | 出栈错误 |
2 | IMPRECISERR | 不精确总线错误 |
1 | PRECISERR | 精确总线错误 |
0 | IBUSERR | 指令错误 |
- (Usage fault)用法错误
Usage fault可由多种情况引发。包括执行未定义的指令,非对齐操作,除零,非法指令(试图切换到ARM状态,执行协处理器指令),使用多重加载/存储指令时地址没对齐。
SCB->CFSR的高半字是 Usage Fault(UFSR),地址:0xE000ED2A | ||
---|---|---|
9 | DIVBYZERO | 企图执行除0的操作 |
8 | UNALIGNED | 企图执行非对齐访问 |
3 | NOCP | 企图执行协处理器指令 |
2 | INVPC | 无效异常返回码 |
1 | INVSTATE | 切换到ARM状态 |
0 | UNDEFINSTR | 为定义指令 |
4、(Hard fault)硬件错误错误 | ||
SCB->HFSR,地址:0xE000ED2C | ||
- | - | - |
31 | DEBUGEVT | 调试事件产生 |
30 | FORCED | 由bus memory Usage Fault升级的硬件错误 |
2~29 | - | - |
1 | VECTBL | 取中断向量时出错 |
0 | - | - |
异常代码定位
查看使用的哪个sp寄存器
当代码错误造成进入异常中断可通过查看cpu寄存器
R14 = 0XFFFFFFF9
异常返回值 | 描述 | |
---|---|---|
0xFFFFFFF1 | 返回Handler模式,异常返回使用MSP,返回后使用MSP | 合法异常 |
0xFFFFFFF9 | 返回Thread 模式,异常返回使用MSP,使用MSP | 合法异常 |
0xFFFFFFFD | 返回Thread 模式,异常返回使用PSP,使用PSP | 合法异常 |
0xFFFFFFE1 | 返回Handler 模式,异常返回使用MSP,使用MSP | |
0xFFFFFFE9 | 返回Thread 模式,异常返回使用MSP,使用MSP | |
0xFFFFFFED | 返回Thread 模式,异常返回使用PSP,使用PSP |
通过上表可以看到 异常返回值是0xFFFFFFF9,异常返回使用的MSP,表示异常代码的现场栈指针存放在MSP中
。
获取栈定地址
通过异常返回值知道使用的MSP
,
MSP = 0x2800AF10
获取栈内容
通过调试器memory窗口查看,sp栈顶地址的内容。
address 8 0 16 9 24 17 32 18
0x2800AF10 00000001 00FFFFFF 0000000E 00000001
0x2800AF20 00000001 10058BA5 10058BC4 2100F200
异常后寄存器入栈顺序
上一步我们找到了栈顶地址,并通过memory窗口查找到了栈内容,接下来了解Cortex-M 寄存器入栈顺序。
可以通过上图看到,入栈顺序,一次从上到下,出栈时反之;
左侧是开启浮点运算后 入栈顺序,可以看到先保存的浮点运算单元的寄存器,然后保存cpu的寄存器。
右侧是未开启浮点运算入栈顺序,保存cpu的寄存器。
R0 R1 R2 R3
0x2800AF10 00000001 00FFFFFF 0000000E 00000001
R12 LR PC PSR
0x2800AF20 00000001 10058BA5 10058BC4 2100F200
通过对栈中的数据分析可以看到 导致进入异常中断的代码地址为 0X10058BC4