本文共 3815 字,大约阅读时间需要 12 分钟。
硬件When an IRQ is detected, the following actions are performed: R14_irq = address of next instruction to be executed + 4 SPSR_irq = CPSR CPSR[4:0] = 0b10010 /* Enter IRQ mode */ CPSR[5] = 0 /* Execute in ARM state */ /* CPSR[6] is unchanged */ CPSR[7] = 1 /* Disable normal interrupts */ CPSR[8] = 1 /* Disable Imprecise Data Aborts (v6 only) */ CPSR[9] = CP15_reg1_EEbit /* Endianness on exception entry */ if high vectors configured then PC = 0xFFFF0018 else PC = 0x00000018软件建议 To return after servicing the interrupt, use: SUBS PC,R14,#4软件 ldr pc, _irq _irq: .word irq.globl IRQ_STACK_START_INIRQ_STACK_START_IN: .word 0x0badc0de irq: get_bad_stack ---- irq mode ldr r13, IRQ_STACK_START_IN @ setup our mode stack // 压栈 lr_irq str lr, [r13] @ save caller lr in position 0 of saved stack // 压栈 spsr_irq mrs lr, spsr @ get the spsr str lr, [r13, #4] @ save spsr in position 1 of saved stack // 准备切换到 Supervisor mode mov r13, #0x13 @ prepare SVC-Mode @ msr spsr_c, r13 // 在 irq mode 模式下 切换到 Supervisor mode msr spsr, r13 @ switch modes, make sure moves will execute ----- Supervisor mode // 将pc放到 lr_svc 中,以便 可以返回 irq mode 下 执行的最后一条指令的下一条指令 mov lr, pc @ capture return pc // 将 lr_svc 放到 pc,转回执行 irq mode 下 执行的最后一条指令的下一条指令 movs pc, lr @ jump to next instruction & switch modes. bad_save_user_regs .macro bad_save_user_regs @ carve out a frame on current user stack // sp_svc = sp_svc - 72,用来保存 13个寄存器,13*4=52 byte ,还有20个byte,可以存5个寄存器 sub sp, sp, #72 // 将 r0-r12 保存到 sp_svc 中 stmia sp, { r0 - r12} @ Save user registers (now in svc mode) r0-r12 // 将 之前保存在 IRQ_STACK_START_IN 的 lr_irq spsr_irq 分别弹到 r2 和 r3 中 // 再保存4个到 之前13个的上面 ldr r2, IRQ_STACK_START_IN @ get values for "aborted" pc and cpsr (into parm regs) ldmia r2, { r2 - r3} // r0 = sp_svc + 72 ,r0保存的是地址,地址中是 sp_SVC add r0, sp, #72 @ grab pointer to old stack // r5 = sp_svc + 52 ,r5保存的是地址,地址中是 ??? add r5, sp, #52 // r1 保存的是 lr_SVC mov r1, lr // 将 r0 r1 r2 r3 保存到 r5 的地址中去 stmia r5, { r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr // 保存当前的栈到r0,做为第一个参数 mov r0, sp @ save current stack into r0 (param register) .endm /* 此时的状态是 r0保存了一个地址,这个地址是栈顶 在栈顶之上,有17个之前保存的寄存器,排序依次为 -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | -------- | | --------------r0中的地址 , 即 栈顶 */ bl do_irq// arch/arm/include/asm/proc-armv/ptrace.h 中有 struct pt_regs 的定义/* this struct defines the way the registers are stored on the stack during a system call. */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]void do_irq (struct pt_regs *pt_regs){ efi_restore_gd(); // null printf ("interrupt request\n"); // 这句话应该被替换,调用 ok6410 注册 的中断处理函数 // 而且 这个 do_irq 函数也不是 被 __weak 修饰 // 看起来 这个do_irq 函数就是 必走的一步了 // 但是没有去 读 gic 相关的寄存器 去判断中断源 ,而是打印了一句,看起来,中断机制在 u-boot 中还不完善 // 返回, 类似于 软件推荐的 SUBS PC,R14,#4 fixup_pc(pt_regs, -8); uint32_t pc = ((((regs)->uregs[15]) & ~0)) + offset; regs->uregs[15] = pc | (regs->uregs[15] & 0); show_regs (pt_regs); show_efi_loaded_images(pt_regs); // null bad_mode (); panic ("Resetting CPU ...\n"); reset_cpu(0);}
转载地址:http://xbigi.baihongyu.com/