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

内容发布更新时间 : 2024/12/23 21:28:47星期一 下面是文章的全部内容请认真阅读。

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

ARM支持7类异常中断,所以中断向量表设8个条目,每个条目4字节,共32字节。 异常名称 复位 未定义的指令 软件中断 指令预取中止 数据访问中止 保留 外部中断请求IRQ 快速中断请求FIQ 中断向量 0x0 0x4 0x8 0x0c 0x10 0x14 0x18 0x1c 异常中断模式 特权模式 特权模式 中止模式 中止模式 IRQ模式 FIQ模式 优先级 1 6 5 2 4 3 未定义指令中止模式 6 回顾第一节所讲的内容,当一个异常或中断发生时,处理器会将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_stubirq, 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