ARMLinux中断源码分析(2)――中断处理流程.
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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_
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