内容发布更新时间 : 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.