@@ and work it out for ourselves mov \\irqnr, #0 @@ start here @@ work out which irq (if any) we got movs \\tmp, \\irqstat, lsl#16 addeq \\irqnr, \\irqnr, #16
moveq \\irqstat, \\irqstat, lsr#16 tst \\irqstat, #0xff
addeq \\irqnr, \\irqnr, #8
moveq \\irqstat, \\irqstat, lsr#8 tst \\irqstat, #0xf
addeq \\irqnr, \\irqnr, #4
moveq \\irqstat, \\irqstat, lsr#4 tst \\irqstat, #0x3
addeq \\irqnr, \\irqnr, #2
moveq \\irqstat, \\irqstat, lsr#2 tst \\irqstat, #0x1
addeq \\irqnr, \\irqnr, #1 @@ we have the value 1001:
adds \\irqnr, \\irqnr, #IRQ_EINT0 @加上中断号的基准数值,得到最终的中断号,注意:此时没有考虑子中断的具体情况,(子中断的问题后面会有讲解)。IRQ_EINT0在include/asm/arch-s3c2410/irqs.h中定义.从这里可以看出,中断号的具体值是有平台相关的代码决定的,和硬件中断挂起寄存器中的中断号是不等的。 1002:
@@ exit here, Z flag unset if IRQ .endm
3.6 asm_do_IRQ实现过程,arch/arm/kernel/irq.c
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) {
struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc = irq_desc + irq;//根据中断号找到对应的irq_desc /*
* Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */
if (irq >= NR_IRQS)
desc = &bad_irq_desc;
irq_enter();//没做什么特别的工作,可以跳过不看
desc_handle_irq(irq, desc);// 根据中断号和desc进入中断处理 /* AT91 specific workaround */ irq_finish(irq); irq_exit();
set_irq_regs(old_regs);
6
}
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc) {
desc->handle_irq(irq, desc);//中断处理 }
上述asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)使用了asmlinkage标识。那么这个标识的含义如何理解呢?
该符号定义在kernel/include/linux/linkage.h中,如下所示:
#include //各个具体处理器在此文件中定义asmlinkage #ifdef __cplusplus
#define CPP_ASMLINKAGE extern \#else
#define CPP_ASMLINKAGE #endif
#ifndef asmlinkage//如果以前没有定义asmlinkage #define asmlinkage CPP_ASMLINKAGE #endif
对于ARM处理器的,没有定义asmlinkage,所以没有意义(不要以为参数是从堆栈传递的,对于ARM平台来说还是符合ATPCS过程调用标准,通过寄存器传递的)。
但对于X86处理器的中是这样定义的:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) 表示函数的参数传递是通过堆栈完成的。
3.7 描述3.3节中的ret_to_user 中断返回过程,/arch/arm/kernel/entry-common.S ENTRY(ret_to_user) ret_slow_syscall:
disable_irq @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending no_work_pending:
/* perform architecture specific actions before user return */ arch_ret_to_user r1, lr
@ slow_restore_user_regs
ldr r1, [sp, #S_PSR] @ get calling cpsr ldr lr, [sp, #S_PC]! @ get pc
msr spsr_cxsf, r1 @ save in spsr_svc
ldmdb sp, {r0 - lr}^ @ get calling r0 - lr mov r0, r0
7
add sp, sp, #S_FRAME_SIZE - S_PC
movs pc, lr @ return & move spsr_svc into cpsr
第三章主要跟踪了从中断发生到调用到对应中断号的desc->handle_irq(irq, desc)中断函数的过程。后面的章节还会继续讲解后面的内容。
8