1 异常向量入口: arch\arm\kernel\entry-armv.S
.section .vectors, "ax", %progbits
.L__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, .L__vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
2 中断向量: vector_irq
/*
* Interrupt dispatcher
*/
vector_stub irq, IRQ_MODE, 4 // 相当于 vector_irq: ...,
// 它会根据SPSR寄存器的值,
// 判断被中断时CPU是处于USR状态还是SVC状态,
// 然后调用下面的__irq_usr或__irq_svc
.long __irq_usr @ 0 (USR_26 / USR_32)
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f
3 __irq_usr/__irq_svc
这2个函数的处理过程类似:
保存现场
调用 irq_handler
恢复现场
4 irq_handler: 将会调用C函数 handle_arch_irq
.macro irq_handler
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
ldr r1, =handle_arch_irq //handle_arch_irq 是个C函数
mov r0, sp
badr lr, 9997f
ldr pc, [r1]
#else
arch_irq_handler_default
#endif
9997:
.endm
5 handle_arch_irq的处理过程
handle_arch_irq 里面会读取寄存器来分辨是哪个中断发生了, 然后去调用对应的中断处理函数, 我们可以看一下handle_arch_irq 这个函数是在哪里设置的,
调用set_handle_irq这个函数来设置handle_arch_irq,
读取寄存器获得中断信息: hwirq
把hwirq转换为virq
调用 irq_desc[virq].handle_irq
对于S3C2440, s3c24xx_handle_irq 是用于处理中断的C语言入口函数,在分析内核对中断的处理流程之前先看一下下面的图。
我们的中断控制器有32位,每一位代表一种中断,中断控制器可以向CPU发出32种中断,每一种中断的处理函数都不一样,那么在Linux内核中,我们怎么管理这32种中断以及他们的处理函数呢,最简单的方法我们创建一个数组,数组的每一项用来保存每一种中断以及他们的处理函数,内核确实也是这么做的,
从上图中我们可以看到,irq_desc里面有一个handle_irq了,然后在action链表中还有一个handle,实际使用时,我们的handle_irq会调用action链表中我们提供的具体的处理函数handler,然后handle_irq再清中断,这样处理的好处是这个handler_irq帮我们处理了中断,然后我们提供的handler处理函数不需要清除中断只需要专注于需要处理的事情就可以了,
从上图中我们可以看到,irq_desc里面还有一个irq_data,然后irq_data里面还有个chip,然后irq_chip里面有一堆的函数,然后这里面的 函数就是用来屏蔽中断,使能中断,清除中断的,
中断处理流程:
假设中断结构如下:
sub int controller ---> int controller ---> cpu
发生中断时,
cpu跳到"vector_irq", 保存现场, 调用C函数handle_arch_irq
handle_arch_irq:
a. 读 int controller, 得到hwirq
b. 根据hwirq得到virq
c. 调用 irq_desc[virq].handle_irq
如果该中断没有子中断, irq_desc[virq].handle_irq的操作:
a. 取出irq_desc[virq].action链表中的每一个handler, 执行它
b. 使用irq_desc[virq].irq_data.chip的函数清中断
如果该中断是由子中断产生, irq_desc[virq].handle_irq的操作:
a. 读 sub int controller, 得到hwirq'
b. 根据hwirq'得到virq
c. 调用 irq_desc[virq].handle_irq