为了方便演示如何实现该方法,采用构造触发BusFault,方便分析
-
首先需要对系统Handler控制及状态寄存器SHCSR.MEMFAULTENA使能
-
往SRAM reserved写入数据,触发BusFault
如上图所示,可以看到触发BusFault前BFSR寄存器第7为高,表示BFAR寄存器有效,且BFAR与MMAR寄存器一致,都为0xE000EDF8
此时,需要注意SP指针为0x2000A208,并且存储内容为0x2000A20C,这有助于找到触发BusFault,压栈前的SP指针
进入中断前PC指针为0x77B4,这个有利于分析压栈地址正确与否
- 进入中断,如下图所示:
可以看到BFSR寄存器为14,为不精确的数据访问违例(violation,本来应该时精确的数据访问违例,不知道为啥后来变成这样了),LR寄存器赋值解释如下
并且SP指针为0x2000A1E8(这个很重要)。根据入栈顺序以及入栈后堆栈中的内容表可反推出旧的SP位置为新的SP+32
可以发现,通过新SP+32的方式找到的旧SP与原来的SP一致
此时,新的SP+24就可以得到压栈前PC指针
通过对比可以发现此时0x77B4就是进入BusFault前,PC指针
也就是说假如清除中断标志位后退出中断,或者说出栈后PC指针就是该值。但是BusFault清除中断后退出中断,PC指针指向为该地址,并不会自动+4。因此还是会再次进入BusFault。这里就解释了为什么MemMange Fault, Bus Fault, Usage Fault清除中断标记位后还是出不来的原因
因此,只需要在该地址上,给0x77B4+4,这样清除中断标记位后,就能使程序不再进入BusFault。
- 但是当程序往下运行时,可以程序又执行了一次压栈,SP指针由0x2000A1E8变成0x2000A1E0,SP指针减了8,故在采用SP指针修改PC指针的时候,一定要注意压栈的次数,SP改变次数,反推进入Handler时候的SP指针 我这里一共改变了12
- 对BFSR寄存器清空,也就是清除中断标记位 注:USFR BFSR MFSR合称 CFSR
- 获取当前SP值,并进入Handler时候的SP指针,其中 24表示压栈后PC偏移地址,+24表示找到压栈后的PC地址,4*6表示压栈前的PC指针(这里指针同地址),可以看到修改后的PC值为0x77B8。此时程序往下执行便不会再次触发BusFault,程序往下继续执行。
便不会再次触发BusFault,程序往下继续执行。
注意:采用修改PC值跳出BusFault,最好在进入BusFault后不在有程序跳转,防止PC值改变,另外程序也应该尽量简短,防止压栈出栈次数太多破坏各寄存器值。并且触发BusFault的整体函数也应该减少程序调用。总之,通过修改PC值,在代码中不是一种好的方法。