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

内容发布更新时间 : 2024/11/16 18:54:02星期一 下面是文章的全部内容请认真阅读。

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

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

字节。

异常名称 复位 未定义的指令 中断向量 0x0 异常中断模式 特权模式 未定义指令中止模式 特权模式 中止模式 中止模式 优先级 1 0x4 6 软件中断 指令预取中止 数据访问中止 保留 外部中断请求IRQ 快速中断请求FIQ

0x8 6 0x0c 5 0x10 2 0x14 0x18 IRQ模式 4 0x1c FIQ模式 3

回顾第一节所讲的内容,当一个异常或中断发生时,处理器会将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.