• 2009-01-07

    u-boot arm920t data_abort 异常处理分析

    Tag:

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://hunbalo.blogbus.com/logs/33513377.html

    在porting u-boot到 microsot device emulator 的时候遇到了data abort问题,索性分析一下
    u-boot中data abort异常处理的实现。
    截取data abort 异常处理相关的代码片断,展开宏
    .globl _start
    _start: b       start_code
     ldr pc, _undefined_instruction
     ldr pc, _software_interrupt
     ldr pc, _prefetch_abort
     ldr pc, _data_abort
     ldr pc, _not_used
     ldr pc, _irq
     ldr pc, _fiq

    _undefined_instruction: .word undefined_instruction
    _software_interrupt: .word software_interrupt
    _prefetch_abort: .word prefetch_abort
    _data_abort:  .word data_abort
    _not_used:  .word not_used
    _irq:   .word irq
    _fiq:   .word fiq

    ...
    data_abort:
     ;expand macro get_bad_stack
      ldr r13, _armboot_start  @ setup our mode stack
     sub r13, r13, #(CONFIG_STACKSIZE)
     sub r13, r13, #(CFG_MALLOC_LEN)
     sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

     str lr, [r13]   @ save caller lr / spsr
     mrs lr, spsr
     str     lr, [r13, #4]

     mov r13, #MODE_SVC   @ prepare SVC-Mode
     @ msr spsr_c, r13
     msr spsr, r13
     mov lr, pc
     movs pc, lr
     ;expand macro bad_save_user_regs
    sub sp, sp, #S_FRAME_SIZE
     stmia sp, {r0 - r12}   @ Calling r0-r12
     ldr r2, _armboot_start
     sub r2, r2, #(CONFIG_STACKSIZE)
     sub r2, r2, #(CFG_MALLOC_LEN)
     sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
     ldmia r2, {r2 - r3}   @ get pc, cpsr
     add r0, sp, #S_FRAME_SIZE  @ restore sp_SVC

     add r5, sp, #S_SP
     mov r1, lr
     stmia r5, {r0 - r3}   @ save sp_SVC, lr_SVC, pc, cpsr
     mov r0, sp 
     
     bl do_data_abort
     
     下面的代码完成设置abt模式下的堆栈,并保存spsr和Lr(r14, 异常发生指令的pc+8)
     进入abort模式时
     spsr_abt = spsr
     r14_abt = pc+8
     将这两个寄存器8个字节的数据保存在abt模式的堆栈中
     ldr r13, _armboot_start  @ setup our mode stack
     sub r13, r13, #(CONFIG_STACKSIZE)
     sub r13, r13, #(CFG_MALLOC_LEN)
     sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

     str lr, [r13]   @ save caller lr / spsr
     mrs lr, spsr
     str     lr, [r13, #4]
     
     切换到svc模式,由于abt模式也是特权模式,因此可以模式切换
     mov r13, #MODE_SVC   @ prepare SVC-Mode
     @ msr spsr_c, r13
     msr spsr, r13
     mov lr, pc
     movs pc, lr 
     
    在svc的堆栈中,保存r0-r12
    sub sp, sp, #S_FRAME_SIZE
     stmia sp, {r0 - r12}   @ Calling r0-r12 
     
    把进入abt模式时保存的r14(发生异常时的pc+8的值), spsr分别放在r2,r3中
     ldr r2, _armboot_start
     sub r2, r2, #(CONFIG_STACKSIZE)
     sub r2, r2, #(CFG_MALLOC_LEN)
     sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
     ldmia r2, {r2 - r3}   @ get pc, cpsr 
    保存发生异常时的sp到r0, lr到r1
    sp=>r0
    lr=>r1
    pc=>r2
    cpsr=>r3
     
     add r0, sp, #S_FRAME_SIZE  @ restore sp_SVC
     add r5, sp, #S_SP
     mov r1, lr
     
    保存sp, lr, pc, cpsr到sr_frame
     stmia r5, {r0 - r3}   @ save sp_SVC, lr_SVC, pc, cpsr
     sr_frame作为参数传给do_data_abort
     mov r0, sp 
     
     bl do_data_abort
     
     
     这样在调用do_data_abort函数时
     sr_frame的结构如下
     
     CPSR
     PC
     LR
     SP
     R12
     R11
     R10
     R9
     R8
     R7
     R6
     R5
     R4
     R3
     R2
     R1
     R0
    传给do_data_abort()函数的值就是指向sp_frame的指针

    void do_data_abort (struct pt_regs *pt_regs)
    {
     printf ("data abort\n");
     show_regs (pt_regs);
     bad_mode ();
    }
    struct pt_regs {
     long uregs[18];
    };

    #define ARM_cpsr uregs[16]
    #define ARM_pc  uregs[15]
    #define ARM_lr  uregs[14]
    #define ARM_sp  uregs[13]
    #define ARM_ip  uregs[12]
    #define ARM_fp  uregs[11]
    #define ARM_r10  uregs[10]
    #define ARM_r9  uregs[9]
    #define ARM_r8  uregs[8]
    #define ARM_r7  uregs[7]
    #define ARM_r6  uregs[6]
    #define ARM_r5  uregs[5]
    #define ARM_r4  uregs[4]
    #define ARM_r3  uregs[3]
    #define ARM_r2  uregs[2]
    #define ARM_r1  uregs[1]
    #define ARM_r0  uregs[0]
    #define ARM_ORIG_r0 uregs[17]
    pt_regs就是sp_frame

    do_data_abort()就不分析了,把这些寄存器都显示出来。

    通过这些分析,可以知道这就是发生异常时的所有寄存器现场,但是pc要减去8才是异常指令的地址

     


    收藏到:Del.icio.us