ARM+Linux中断系统详细分析
位于arch/arm/kernel/entry-armv.S
点击(此处)折叠或打开
- .globl __vectors_start
- __vectors_start:
- swi SYS_ERROR0
- b vector_und + stubs_offset//复位异常
- ldr pc, .LCvswi + stubs_offset //未定义异常
- b vector_pabt + stubs_offset//软件中断异常
- b vector_dabt + stubs_offset//数据异常
- b vector_addrexcptn + stubs_offset//保留
- b vector_irq + stubs_offset //普通中断异常
- b vector_fiq + stubs_offset//快速中断异常
- .globl __vectors_end
- __vectors_end:
stubs_offset值如下:
.equstubs_offset,__vectors_start+0x200-__stubs_start
stubs_offset是如何确定的呢?(引用网络上的一段比较详细的解释)
当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(±32M)写入指令码。从上面的代码可以看到中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成bvector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。我们把搬移前的中断向量表中的irq入口地址记irq_PC,它在中断向量表的偏移量就是irq_PC-vectors_start,vector_irq在stubs中的偏移量是vector_irq-stubs_start,这两个偏移量在搬移前后是不变的。搬移后vectors_start在0xffff0000处,而stubs_start在0xffff0200处,所以搬移后的vector_irq相对于中断向量中的中断入口地址的偏移量就是,200+vector_irq在stubs中的偏移量再减去中断入口在向量表中的偏移量,即200+vector_irq-stubs_start-irq_PC+vectors_start=(vector_irq-irq_PC)+vectors_start+200-stubs_start,对于括号内的值实际上就是中断向量表中写的vector_irq,减去irq_PC是由汇编器完成的,而后面的vectors_start+200-stubs_start就应该是stubs_offset,实际上在entry-armv.S中也是这样定义的。
2.中断响应
当有外部中断产生时,跳转到异常向量表的“bvector_irq + stubs_offset //普通中断异常”
进入异常处理函数,跳转的入口位置arch\arm\kernel\entry-armv.S代码简略如下
点击(此处)折叠或打开
- .globl __stubs_start
- __stubs_start:
- /*
- * 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)
- vector_stub dabt, ABT_MODE, 8
- vector_stub pabt, ABT_MODE, 4
- vector_stub und, UND_MODE
- /*
- * Undefined FIQs
- */
- vector_fiq:
- disable_fiq
- subs pc, lr, #4
- vector_addrexcptn:
- b vector_addrexcptn
vector_stub是个函数调用宏,根据中断前的工作模式决定进入__irq_usr,__irq_svc。这里入__irq_svc,同时看到这里FIQ产生时,系统未做任何处理,直接返回,即Linux没有提供对FIQ的支持,继续跟进代码
点击(此处)折叠或打开
- __irq_svc:
- svc_entry
- …
- irq_handler
svc_entry是一个宏,主要实现了将SVC模式下的寄存器、中断返回地址保存到堆栈中。然后进入最核心的中断响应函数irq_handler,irq_handler实现过程arch\arm\kernel\entry-armv.S
点击(此处)折叠或打开
- .macro irq_handler
- get_irqnr_preamble r5, lr
- 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
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寄存器得到中断位置
- …
- @@ 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
asm_do_IRQ实现过程,arch/arm/kernel/irq.c
点击(此处)折叠或打开
- asmlinkage void asm_do_IRQ(unsignedintirq,
ARMLinux中断系 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)