1,entry-armv.S
.macro irq_handler
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b @返回到1处,asm_do_IRQ返回后将再次查询发生的中断
bne asm_do_IRQ @kernel的中断处理函数
...
.endm
2,entry-macro.S
下面这个宏查询ISPR(IRQ待定中断服务寄存器,当有需要处理的中断时,这个寄存器的相应位会置位,任意时刻,最多一个位会置位),计算出的中断号放在irqnr指定的寄存器中;这个宏在不同的ARM芯片上是不一样的,下面是W90X900的定义
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov \base, #W90X900_VA_IRQ@装入中断服务寄存器地址
ldr \irqnr, [ \base, #AIC_IPER]
ldr \irqnr, [ \base, #AIC_ISNR] @装入中断服务寄存器值
cmp \irqnr, #0 @比较一下,是不是没有中断了
.endm
3,下面这个宏是所有中断服务过程进入时的前序,主要是在当前堆栈上分配一个pt_regs结构,把r0-r15以及cpsr等保存到这个结构中,在进入irq_handler时,sp指向pt_regs底端
.macro svc_entry
sub sp, sp, #S_FRAME_SIZE @sizeof(pt_regs),分配一个pt_regs结构
stmib sp, {r1 - r12} @保存r1-r12
ldmia r0, {r1 - r3} @r0指向何处?这个地方的内容是什么?参见4节(1)(2)处
add r5, sp, #S_SP @S_SP为sp寄存器在pt_regs中的偏移
mov r4, #-1 @ ORIG_r0=-1?
add r0, sp, #S_FRAME_SIZE @r0为中断前的堆栈指针,将成为pt_regs中的sp的值
str r1, [sp] @ save the "real" r0 copied from the exception stack
mov r1, lr
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r0 - sp_svc
@ r1 - lr_svc
@ r2 - lr_, already fixed up for correct return/restart
@ r3 - spsr_
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
stmia r5, {r0 - r4}
.endm
4,
.macro vector_stub, name, mode, correction=0
.align 5
vector_\name:
.if \correction
sub lr, lr, #\correction @修正返回地址,如果必要的话
.endif
@
@ Save r0, lr_ (parent PC) and spsr_
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr (1)(为什么向上长呢?)
mrs lr, spsr
str lr, [sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE)
msr spsr_cxsf, r0
@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f @这里lr的值是spsr的值,因此,这个指令之后lr的值为spsr[0-3],即,系统模式的低4位
mov r0, sp (2)
ldr lr, [pc, lr, lsl #2] @lr = pc+lr<<2,usr:pc,fiq:pc+4,irq:pc+8,svc:pc+12,abt:pc+28,und:pc+44,system:pc+60
movs pc, lr @ branch to handler in SVC mode
.endm
对于irq中断,会这样调用上面这个宏:
vector_stub irq, IRQ_MODE, 4
5,中断处理过程总体结构,当中断发生后控制先转移到4,然后跳转到__irq_svc
__irq_svc:
svc_entry
irq_handler
ldr r0, [sp, #S_PSR] @ irqs are already disabled,S_PSR为cpsr在pt_regs中的偏移;sp指向在svc_entry中分配的pt_regs结构
msr spsr_cxsf, r0 @恢复spsr
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
...
.global __stub_start
__stub_start:
vector_stub irq , IRQ_MODE ,4
.long __irq_usr
.long __irq_invalid
.long __irq_invalid
.long __irq_svc
.long __irq_invalid
...
@以下与irq中断无关,但是是arm整个异常处理结构的一部分,因此列示在这里
vector_stub dabt, ABT_MODE, 8
...
vector_stub pabt, ABT_MODE, 4
...
vector_stub und, UND_MODE
...
vector_fiq:
...
vector_addrexcptn:
...
.LCvswi:
...
.globl __stubs_end
__stubs_end:
...
@下面这些才是最初的入口点,__vector_start和__vector_end之间的代码会被移动到CONFIG_VECTORS_BASE开始的地方,例如0xc000000
.globl __vectors_start
__vectors_start:
swi SYS_ERROR0 @Reset
b vector_und + stubs_offset @Undefined instruction
ldr pc, .LCvswi + stubs_offset @swi instruction
b vector_pabt + stubs_offset @Prefetch Abort
b vector_dabt + stubs_offset @Data Abort
b vector_addrexcptn + stubs_offset @ARM reserved
b vector_irq + stubs_offset @IRQ
b vector_fiq + stubs_offset @FIQ
.globl __vectors_end
__vectors_end:
...
附录1,arm体系下pt_regs结构
struct pt_regs {
long uregs[18];
};
uregs[0] - uregs[17]分别对应,r0 - r15,cpsr,ORIG_r0
附录1,irq中断时堆栈的变化
--------
spsr
--------
lr ,中断返回地址,修正后的
--------
r0
-------- <-进入irq_svc之前,sp的值,也是r0的值
pt_regs
--------- <-进入svc_entry后,sp的值
阅读(1115) | 评论(0) | 转发(0) |