@
@ r2 - lr_, already fixed up for correct return/restart
@ r3 - spsr_
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
@ Also, separately save sp_usr and lr_usr
@
stmia r0, {r2 - r4}
stmdb r0, {sp, lr}^
@
@ Enable the alignment trap while in kernel mode
@
alignment_trap r0
@
@ Clear FP to mark the first stack frame
@
zero_fp
.endm
上面的这段代码主要在填充结构体pt_regs ,这里提到的struct pt_regs,在include/asm/ptrace.h中定义。此时sp指向struct pt_regs。
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]
3.4 irq_handler的实现过程,archarmkernelentry-armv.S
.macro irq_handler
get_irqnr_preamble r5, lr
@在include/asm/arch-s3c2410/entry-macro.s中定义了宏get_irqnr_preamble为空操作,什么都不做
1: get_irqnr_and_base r0, r6, r5, lr @判断中断号,通过R0返回,3.5节有实现过程
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b
bne asm_do_IRQ @进入中断处理。
……
.endm
3.5 get_irqnr_and_base中断号判断过程,include/asm/arch-s3c2410/entry-macro.s
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov base, #S3C24XX_VA_IRQ
@@ try the interrupt offset register, since it is there
ldr irqstat, [ base, #INTPND ]
teq irqstat, #0
beq 1002f
ldr irqnr, [ base, #INTOFFSET ] @通过判断INTOFFSET寄存器得到中断位置
mov tmp, #1
tst irqstat, tmp, lsl irqnr
bne 1001f
@@ the number specified is not a valid irq, so try
@@ 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);
}
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 "C"
#else
#define CPP_ASMLINKAGE
#endif
#ifndef asmlinkage//如果以前没有定义asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#endif
对于ARM处理器的,没有定义asmlinkage,所以没有意义(不要以为参数是从堆栈传递的,对于ARM平台来说还是符合ATPCS过程调用标准,通过寄存器传递的)。
但对于X86处理器的中是这样定义的: