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就可以了。

发表新评论