ARM中Bus Error的测试
在芯片测试的时候,我们有时候会碰到Bus Error的情况,这种情况下程序会进到bus error的中断中,中断返回的时候,再次回到原来位置,访问地址的时候再次进入中断,这样就造成程序不停进中断,导致正常测试被打断。为了避免这种情况的发生,我们需要修改程序返回的地址,这里面涉及的东西就有点复杂了,这里简单记录一下。
问题分析
上面例子中,我们访问了一个非法的地址产生中断,程序会将必要的寄存器压栈之后跳转到中断中执行,中断执行完毕之后,从栈中取出之前的程序指针继续执行。
这个流程比较简单,其实问题的解决方法也在这个流程里面,因为中断返回之后还是回到出问题的地址,再次运行引发连续中断,所以我们只需要将程序返回到的地址加一个偏移,直接让他到下一条指令就好了(暂时先不管16位和32位指令,统一认为是32位的指令,即使是16位指令,我们可以直接跳过两条指令)。如果想维持程序运行完整性,可以在预期出现中断的指令后面加若干NOP
指令。
代码实现
因为牵扯到对程序栈的操作,所以一般的C语言是搞不定的,这里我们就必须通过汇编实现:
typedef struct {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
} hw_stackframe_t;
void default_isr(void)
{
// set up arguments and call _hardfault_isr
asm("mov r0, lr\n" // arg 0
"mrs r1, psp\n" // arg 1
"mrs r2, msp\n" // arg 2
"b _default_isr\n");
}
static void _default_isr(uint32_t lr, void *psp, void *msp) __attribute__((used));
static void _default_isr(uint32_t lr, void *psp, void *msp)
{
#define VECTORNUM (*(volatile uint8_t*)(0xE000ED04))
hw_stackframe_t *frame;
// Find the active stack pointer (MSP or PSP)
if(lr & 0x4)
frame = psp;
else
frame = msp;
printf("\r\n** HARD FAULT **\r\n\tpc=0x%x\r\n\tmsp=0x%p\r\n\tpsp=0x%p\r\n",
frame->pc, msp, psp);
printf("\r\n****default_isr entered on vector %d*****\r\n",VECTORNUM);
// add PC by 4
frame->pc += 4;
return;
}
上述代码中的结构体就是描述了一个堆栈信息,汇编中会直接将lr
, psp
, msp
存入r0~2
作为参数,然后跳转到_default_isr
中实现参数调用,这样lr
, psp
, msp
就直接成为C函数的参数,我们也就可以很方便的使用里面的内容了,得到这几个寄存器的值之后我们判断当前用到的堆栈指针地址,并让我们定义的结构体指针指向这个地址,之后就可以通过结构体实现对堆栈中内容进行读写操作了。
这里我们就是简单的把PC加4就可以了。
最后更新于 2019-07-24 06:25:58 并被添加「」标签,已有 4563 位童鞋阅读过。
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。