MTK lk源码解析8( lk 阶段exceptions.S 解析)

来源:互联网 发布:股票下跌提醒软件 编辑:程序博客网 时间:2024/06/07 15:47

http://blog.csdn.net/xichangbao/article/details/51484629

  1. arm异常模式。

#define FUNCTION(x) .global x; x:

FUNCTION(arm_undefined) // 未定义指令异常
    stmfd     sp!, { r0-r12, r14 } // 批量数据存储指令,用于将r0-r12及r14压入堆栈,stmfd指令的寻址方式为事前递减方式(DB),后缀“!”表示更新sp的值,即sp = sp - 14*4
    sub        sp, sp, #12 // sp = sp - 12
    mov        r0, sp
    mrs        r1, spsr // spsr保存的用户模式的cpsr
    stmia    r0, { r1, r13-r14 }^ // 将spsr,sp,lr入栈,后缀“^”表示sp,lr是用户模式的寄存器
    b        arm_undefined_handler
    b        .

FUNCTION(arm_syscall) // 系统调用模式
    stmfd     sp!, { r0-r12, r14 }
    sub        sp, sp, #12
    mov        r0, sp
    mrs        r1, spsr
    stmia    r0, { r1, r13-r14 }^
    b        arm_syscall_handler
    b        .

FUNCTION(arm_prefetch_abort) // 预取指令异常模式
    stmfd     sp!, { r0-r12, r14 }
    sub        sp, sp, #12
    mov        r0, sp
    mrs        r1, spsr
    stmia    r0, { r1, r13-r14 }^
    b        arm_prefetch_abort_handler
    b        .

FUNCTION(arm_data_abort) // 数据访问终止模式
    stmfd     sp!, { r0-r12, r14 }
    sub        sp, sp, #12
    mov        r0, sp
    mrs        r1, spsr
    stmia    r0, { r1, r13-r14 }^
    b        arm_data_abort_handler
    b        .

FUNCTION(arm_reserved)
    b    .

FUNCTION(arm_irq) // 普通中断模式
    /* XXX only deals with interrupting supervisor mode */

    /* save r4-r6 and use as a temporary place to save while we switch into supervisor mode */
    stmia    r13, { r4-r6 } // r4-r6入栈,使用用户模式的堆栈
    mov        r4, r13
    sub        r5, lr, #4
    mrs        r6, spsr

    /* move into supervisor mode. irq/fiq disabled */
    msr    cpsr_c, #(3<<6 | 0x13) // 切换到超级用户模式,同时关闭中断

    /* save the return address */
    stmfd    sp!, { r5 } // // platform_irq的参数frame中的pc,入栈返回地址:lr - 4

    /* save C trashed regs, supervisor lr */
    stmfd    sp!, { r0-r3, r12, lr } // platform_irq的参数frame中的r0, r1, r2, r3, r12, lr

    /* save spsr */
    stmfd    sp!, { r6 } // platform_irq的参数frame中的spsr

    /* restore r4-r6 */
    ldmia    r4, { r4-r6 } // r4-r6出栈,使用用户模式的堆栈

    /* increment the global critical section count */
    ldr     r1, =critical_section_count
    ldr     r0, [r1]
    add     r0, r0, #1
    str     r0, [r1] // 以上四句指令critical_section_count = critical_section_count + 1

    /* call into higher level code */
    mov    r0, sp /* iframe */ // platform_irq的参数struct arm_iframe *frame
    bl    platform_irq

    /* reschedule if the handler returns nonzero */
    cmp     r0, #0 // 比较platform_irq返回值是否为0
    blne    thread_preempt 不为0跳转到thread_preempt,进行线程抢占

    /* decrement the global critical section count */
    ldr     r1, =critical_section_count
    ldr     r0, [r1]
    sub     r0, r0, #1
    str     r0, [r1] // 以上四句指令critical_section_count = critical_section_count - 1

    /* restore spsr */
    ldmfd    sp!, { r0 }
    msr     spsr_cxsf, r0 // 恢复spsr

    /* restore back to where we came from */
    ldmfd    sp!, { r0-r3, r12, lr, pc }^  // 出栈,返回到pc处进执行

.bss
.align 2
    .global irq_save_spot
irq_save_spot:
    .word    0    /* r4 */
    .word    0    /* r5 */
    .word    0    /* r6 */

.text
FUNCTION(arm_fiq) // 快速中断模式
    sub    lr, lr, #4 // 修正快速中断的返回地址
    stmfd    sp!, { r0-r3, r12, lr } // 入栈

    bl    platform_fiq

    ldmfd    sp!, { r0-r3, r12, pc }^ // 出栈,后缀“^”,同时将spsr复制到cpsr

.ltorg


  1. 未定义指令模式。
void arm_undefined_handler(struct arm_fault_frame *frame)
{
    exception_die(frame, -4, "undefined abort, halting\n");
}

  1. 系统调用模式。
void arm_syscall_handler(struct arm_fault_frame *frame)
{
    exception_die(frame, -4, "unhandled syscall, halting\n");
}

  1. 预取指令异常模式。
void arm_prefetch_abort_handler(struct arm_fault_frame *frame)
{
    exception_die(frame, -4, "prefetch abort, halting\n");
}

  1. 数据访问终止模式。
void arm_data_abort_handler(struct arm_fault_frame *frame)
{
    exception_die(frame, -8, "data abort, halting\n");
}

  1. 普通中断模式。
struct arm_iframe {
    uint32_t spsr;
    uint32_t r0;
    uint32_t r1;
    uint32_t r2;
    uint32_t r3;
    uint32_t r12;
    uint32_t lr;
    uint32_t pc;
};

enum handler_return platform_irq(struct arm_iframe *frame)
{
#if TARGET_USES_GIC_VIC
    if(target_supports_qgic())
        return gic_platform_irq(frame);
    else
        return vic_platform_irq(frame);
#else
    return gic_platform_irq(frame);
#endif
}

/* IRQ handler */
enum handler_return gic_platform_irq(struct arm_iframe *frame)
{
    uint32_t num;
    enum handler_return ret;

    /* Read the interrupt number to be served*/
    num = qgic_read_iar(); // 获取中断号

    if (num >= NR_IRQS)
        return 0;

    ret = handler[num].func(handler[num].arg); // 根据中断号,执行相应中断处理函数

    /* End of interrupt */
    qgic_write_eoi(num); // 通知cpu中断已处理

    return ret;
}

  1. 快速中断模式。
void platform_fiq(struct arm_iframe *frame)
{
#if TARGET_USES_GIC_VIC
    if(target_supports_qgic())
        gic_platform_fiq(frame);
    else
        vic_platform_fiq(frame);
#else
    gic_platform_fiq(frame);
#endif
}

/* FIQ handler */
void gic_platform_fiq(struct arm_iframe *frame)
{
    PANIC_UNIMPLEMENTED;
}


#define PANIC_UNIMPLEMENTED panic("%s unimplemented\n", __PRETTY_FUNCTION__) // lk中不支持快速中断模式

  1. exception_die()。
static void exception_die(struct arm_fault_frame *frame, int pc_off, const char *msg) // 注意第二个参数,不同的异常模式的返回地址不同
{
    inc_critical_section(); // 禁掉中断
    frame->pc += pc_off; // 计算正确的返回地址,frame->pc对应入栈的lr
    dprintf(CRITICAL, msg);
    dump_fault_frame(frame); // 打印帧信息

    halt(); // 挂起
    for(;;); // 死循环
}

  1. dump_fault_frame()。
struct arm_fault_frame {
    uint32_t spsr;
    uint32_t usp;
    uint32_t ulr;
    uint32_t r[13];
    uint32_t pc;
};

struct arm_mode_regs {
    uint32_t fiq_r13, fiq_r14;
    uint32_t irq_r13, irq_r14;
    uint32_t svc_r13, svc_r14;
    uint32_t abt_r13, abt_r14;
    uint32_t und_r13, und_r14;
    uint32_t sys_r13, sys_r14;
};

void dump_fault_frame(struct arm_fault_frame *frame)
{
    // 打印堆栈中的寄存器信息,其中pc值已修正
    dprintf(CRITICAL, "r0  0x%08x r1  0x%08x r2  0x%08x r3  0x%08x\n", frame->r[0], frame->r[1], frame->r[2], frame->r[3]);
    dprintf(CRITICAL, "r4  0x%08x r5  0x%08x r6  0x%08x r7  0x%08x\n", frame->r[4], frame->r[5], frame->r[6], frame->r[7]);
    dprintf(CRITICAL, "r8  0x%08x r9  0x%08x r10 0x%08x r11 0x%08x\n", frame->r[8], frame->r[9], frame->r[10], frame->r[11]);
    dprintf(CRITICAL, "r12 0x%08x usp 0x%08x ulr 0x%08x pc  0x%08x\n", frame->r[12], frame->usp, frame->ulr, frame->pc);
    dprintf(CRITICAL, "spsr 0x%08x\n", frame->spsr);

    struct arm_mode_regs regs;
    arm_save_mode_regs(&regs);
    // 打印异常模式的寄存器值
    dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_FIQ) ? '*' : ' ', "fiq", regs.fiq_r13, regs.fiq_r14);
    dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_IRQ) ? '*' : ' ', "irq", regs.irq_r13, regs.irq_r14);
    dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_SVC) ? '*' : ' ', "svc", regs.svc_r13, regs.svc_r14);
    dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_UND) ? '*' : ' ', "und", regs.und_r13, regs.und_r14);
    dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_SYS) ? '*' : ' ', "sys", regs.sys_r13, regs.sys_r14);

    // dump the bottom of the current stack
    addr_t stack;
    switch (frame->spsr & MODE_MASK) {
        case MODE_FIQ: stack = regs.fiq_r13; break;
        case MODE_IRQ: stack = regs.irq_r13; break;
        case MODE_SVC: stack = regs.svc_r13; break;
        case MODE_UND: stack = regs.und_r13; break;
        case MODE_SYS: stack = regs.sys_r13; break;
        default:
            stack = 0;
    }

    if (stack != 0) {
        dprintf(CRITICAL, "bottom of stack at 0x%08x:\n", (unsigned int)stack);
        hexdump((void *)stack, 128); // 打印异常模式的堆栈内容
    }
}


0 0
原创粉丝点击