/* * Interrupt dispatcher */ vector_stub irq, IRQ_MODE, 4 .long __irq_usr @ 0 (USR_26 / USR_32) .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) .long __irq_invalid @ 2 (IRQ_26 / IRQ_32) .long __irq_svc @ 3 (SVC_26 / SVC_32) .long __irq_invalid @ 4 .long __irq_invalid @ 5 .long __irq_invalid @ 6 .long __irq_invalid @ 7 .long __irq_invalid @ 8 .long __irq_invalid @ 9 .long __irq_invalid @ a .long __irq_invalid @ b .long __irq_invalid @ c .long __irq_invalid @ d .long __irq_invalid @ e .long __irq_invalid @ f
vector_stub这是一个宏,是个很关键的宏。
.macro vector_stub, name, mode, correction=0 .align 5 vector_\name: .if \correction@修正返回地址,为什么要修正?进入异常模式时lr中保存的是当前PC,异常返回后,需要执行的是当前状态的下一条指令,根据arm spec需要-4或者-8 sub lr, lr, #\correction .endif @ @ Save r0, lr_<exception> (parent PC) and spsr_<exception> @ (parent CPSR) @ stmia sp, {r0, lr} @ save r0, lr,到sp栈顶指针指定的内存 mrs lr, spsr @spsr读到lr,这是异常之前的状态,spsr_irq str lr, [sp, #8] @ save spsr到sp+8的内存中 @ @ Prepare for SVC32 mode. IRQs remain disabled. @ mrs r0, cpsr @cpsr读到r0,这是异常之后的 eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)@改mode了,异或特点:异或0不变,异或1取反;之前是0的bit都会置1,是1的bit不变。 #define PSR_ISETSTATE PSR_T_BIT //thumb #define PSR_ISETSTATE 0 //arm msr spsr_cxsf, r0 @r0保存到spsr_cxsf 格式: MSR{<条件码>CPSR_f|SPSR_f,<#ommed_8r> MSR{<条件码>CPSR_<field>|SPSR_<field>,Rm 其中:<field>字段可以是以下之一或多种:(位从右到左) C:控制域屏蔽字段(PSR中的第0位到第7位); X:扩展域屏蔽字段(PSR中的第8位到第15位); S:状态域屏蔽字段(PSR中的第16位到第32位); F:标志域屏蔽字段(PSR中的第24位到第31位)。 注意了这里只是改了spsr_irq的mode,还没有开始切换呢。 @ @ the branch table must immediately follow this code @ and lr, lr, #0x0f @lr保存的是spsr,低4bit,是mode THUMB( adr r0, 1f ) THUMB( ldr lr, [r0, lr, lsl #2] ) mov r0, sp @将irq的栈顶地址给r0,就可以通过r0读irq的栈了 ARM( ldr lr, [pc, lr, lsl #2] )@pc = lr<<2;lr = pc+lr,有左移还是因为long对齐,__irq_usr 位于0偏移处,__irq_svc位于3*4偏移处。 movs pc, lr @ branch to handler in SVC mode跳转的同时,做模式切换,s表示同时将spsr赋给cpsr,这里就切换过来了;切换到svc mode,spsr_svc应该保存的是切换之前的cpsr,应该是irq mode为2啊;可为什么读回来是0呢? 在异常发生后,ARM内核会自动做以下工作,确实是由CPU自动处理的: 1 保存执行状态:将CPSR复制到发生的异常模式下SPSR中; 2 模式切换:将CPSR模式位强制设置为与异常类型相对应的值,同时处理器进入到ARM执行模式,禁止所有IRQ中断,当进入FIQ快速中断模式时禁止FIQ中断; 3 保存返回地址:将下一条指令的地址(被打断程序)保存在LR(异常模式下LR_excep)中。 4 跳入异常向量表:强制设置PC的值为相应异常向量地址,跳转到异常处理程序中。 如果直接模式切换了,cpsr就不会copy了?所以spsr_svc中保存的还是上一次异常user to irq时的user mode? ENDPROC(vector_\name) .align 2 @ handler addresses follow this label 1: .endm
为什么要切换svc呢?应该是中断嵌套的要求,中断嵌套可能导致链接寄存器r14_irq被破坏,就找不到返回点了。
1 arm体系下pt_regs结构struct pt_regs {long uregs[18];};uregs[0] - uregs[17]分别对应,r0 - r15,cpsr,ORIG_r0
#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]
2 irq中断时堆栈的变化
--------
spsr
--------
lr ,中断返回地址,修正后的
--------
r0
-------- <-进入irq_svc或irq_usr之前,sp的值,也是r0的值
pt_regs
--------- <-进入svc_entry或usr_entry后,sp的值