ARMLinux中断源码分析(2)――中断处理流程.

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

ARM Linux中断源码分析(2)——中断处理流程

ARM支持7类异常中断,所以中断向量表设8个条目,每个条目4字节,共32字节。

回顾第一节所讲的内容,当一个异常或中断发生时,处理器会将PC设置为特定地址,从而跳转到已经初始化好的异常向量表。因此,要理清中断处理流程,先从异常向量表开始。对于ARM Linux而言,异常向量表和异常处理程序都存在arch/arm/kernel/entry_armv.S汇编文件中。

vector异常向量表

点击(此处折叠或打开

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 @中断入口,vector_irq

10. b vector_fiq + stubs_offset

11.

12. .globl __vectors_end

13. __vectors_end:

vector_irq+stubs_offset为中断的入口点,此处之所以要加上stubs_offset,是为了实现位置无关编程。首先分析一下stubs_offset(宏是如何计算的:

.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

在第3节中已经提到,内核启动时会将异常向量表拷贝到 0xFFFF_0000,将异常向量处理程序的stub 拷贝到 0xFFFF_0200。图5-1描述了异常向量表和异常处理程序搬移前后的内存布局。

图5-1 异常向量表和异常处理程序搬移前后对比

当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(±32M)写入指令码。由于内核启动时中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成b vector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。设搬移后的偏移量为offset,如图5-1所示,

offset = L1+L2

= [0x200 - (irq_PC_X - __vectors_start_X] + (vector_irq_X - __stubs_start_X

= [0x200 - (irq_PC - __vectors_start] + (vector_irq - __stubs_start

= 0x200 - irq_PC + __vectors_start + vector_irq - __stubs_start

= vector_irq + (__vectors_start + 0x200 - __stubs_start - irq_PC

令stubs_offset = __vectors_start + 0x200 - __stubs_start

则offset = vector_irq + stubs_offset - irq_PC,所以中断入口点为“b vector_irq + stubs_offset”,其中减去irq_PC是由汇编器在编译时完成的。

vector_irq处理函数

在分析vector_irq处理函数之前,先了解一下当一个异常或中断导致处理器模式改变时,ARM处理器内核的处理流程如下图所示:

中断刚发生时,处理器处于irq模式。在__stubs_start和__stubs_end之间找到vector_irq处理函数的定义vector_stub irq, IRQ_MODE, 4,其中vector_stub是一个宏(在

arch/arm/kernel/entry_armv.S中定义),为了分析更直观,我们将vector_stub宏展开如下:

1. /*

2. * Interrupt dispatcher

3. */

4. vector_irq:

5. .if 4

6. sub lr, lr, #4 @在中断发生时,lr指向最后执行的指令地址加上8。只有在当前指令执行完毕后,才进入中断处理,所以返回地址应指向下一条指令,即(lr-4)处。

7. .endif

8.

9. @

10. @ Save r0, lr_(parent PC and spsr_

11. @ (parent CPSR

12. @

13. stmia sp, {r0, lr} @ 保存r0, lr到irq模式下的栈中

14. mrs lr, spsr

15. str lr,[sp, #8] @保存spsr到irq模式下的栈中

16.

17. @

18. @ Prepare for SVC32 mode. IRQs remain disabled.

19. @

20. mrs r0, cpsr

21. eor r0, r0, #( IRQ_MODE ^ SVC_MODE @设置成SVC模式,但未切换

22. msr spsr_cxsf, r0 @保存到spsr_irq中

23.

24. @

25. @ the branch table must immediately follow this code

26. @

27. and lr, lr, #0x0f @lr存储着上一个处理器模式的cpsr值,lr = lr & 0x0f取出用于判断发生中断前是用户态还是核心态的信息,该值用于下面跳转表的索引。

28. mov r0, sp @将irq模式下的sp保存到r0,作为参数传递给即将调用的__irq_usr或

__irq_svc

29. ldr lr,[pc, lr,lsl #2] @pc指向当前执行指令地址加8,即跳转表的基址。lr作为索引,由于是4字节对齐,所以lr = lr << 2.

30. movs pc, lr @ branch to handler in SVC mode

31. @当mov指令后加“s”且目标寄存器为pc时,当前模式下的spsr会被复制到cpsr,从而完成模式切换(从irq模式切换到svc模式)并且跳转到pc指向的指令继续执行

32. ENDPROC(vector_irq

相关文档
最新文档