微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM+Linux中断系统详细分析

ARM+Linux中断系统详细分析

时间:11-09 来源:互联网 点击:

位于arch/arm/kernel/entry-armv.S

点击(此处)折叠或打开

  1. .globl __vectors_start
  2. __vectors_start:
  3. swi SYS_ERROR0
  4. b vector_und + stubs_offset//复位异常
  5. ldr pc, .LCvswi + stubs_offset //未定义异常
  6. b vector_pabt + stubs_offset//软件中断异常
  7. b vector_dabt + stubs_offset//数据异常
  8. b vector_addrexcptn + stubs_offset//保留
  9. b vector_irq + stubs_offset //普通中断异常
  10. b vector_fiq + stubs_offset//快速中断异常
  11. .globl __vectors_end
  12. __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代码简略如下

点击(此处)折叠或打开

  1. .globl __stubs_start
  2. __stubs_start:
  3. /*
  4. * Interrupt dispatcher
  5. */
  6. vector_stub irq, IRQ_MODE, 4
  7. .long __irq_usr @ 0 (USR_26 / USR_32)
  8. .long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
  9. .long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
  10. .long __irq_svc @ 3 (SVC_26 / SVC_32)
  11. vector_stub dabt, ABT_MODE, 8
  12. vector_stub pabt, ABT_MODE, 4
  13. vector_stub und, UND_MODE
  14. /*
  15. * Undefined FIQs
  16. */
  17. vector_fiq:
  18. disable_fiq
  19. subs pc, lr, #4
  20. vector_addrexcptn:
  21. b vector_addrexcptn

vector_stub是个函数调用宏,根据中断前的工作模式决定进入__irq_usr,__irq_svc。这里入__irq_svc,同时看到这里FIQ产生时,系统未做任何处理,直接返回,即Linux没有提供对FIQ的支持,继续跟进代码

点击(此处)折叠或打开

  1. __irq_svc:
  2. svc_entry
  3. irq_handler

svc_entry是一个宏,主要实现了将SVC模式下的寄存器、中断返回地址保存到堆栈中。然后进入最核心的中断响应函数irq_handler,irq_handler实现过程arch\arm\kernel\entry-armv.S

点击(此处)折叠或打开

  1. .macro irq_handler
  2. get_irqnr_preamble r5, lr
  3. 1: get_irqnr_and_base r0, r6, r5, lr @判断中断号,通过R0返回,3.5节有实现过程
  4. movne r1, sp
  5. @
  6. @ routine called with r0 = irq number, r1 = struct pt_regs *
  7. @
  8. adrne lr, 1b
  9. bne asm_do_IRQ @进入中断处理。
  10. ……
  11. .endm

get_irqnr_and_base中断号判断过程,include/asm/arch-s3c2410/entry-macro.s

点击(此处)折叠或打开

  1. .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
  2. mov \base, #S3C24XX_VA_IRQ
  3. @@ try the interrupt offset register, since it is there
  4. ldr \irqstat, [ \base, #INTPND ]
  5. teq \irqstat, #0
  6. beq 1002f
  7. ldr \irqnr, [ \base, #INTOFFSET ] @通过判断INTOFFSET寄存器得到中断位置
  8. @@ we have the value
  9. 1001:
  10. adds \irqnr, \irqnr, #IRQ_EINT0 @加上中断号的基准数值,得到最终的中断号,注意:此时没有考虑子中断的具体情况。IRQ_EINT0在include/asm/arch-s3c2410/irqs.h中定义.从这里可以看出,中断号的具体值是有平台相关的代码决定的,和硬件中断挂起寄存器中的中断号是不等的。
  11. 1002:
  12. @@ exit here, Z flag unset if IRQ
  13. .endm

asm_do_IRQ实现过程,arch/arm/kernel/irq.c

点击(此处)折叠或打开

  1. asmlinkage void asm_do_IRQ(unsignedintirq,

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top