原创文章, 转载请注明出处。
这篇文章主要讨论的话题是当中断发生时Linux内核是如何处理中断的。
当CPU检测到中断的时候,linux内核首先会跳转至arch/arm/kernel/entry-armv.S中进行处理,
然后切换到IRQ_MODE(vector_stub irq, IRQ_MODE, 4),最后运行到irq_handler。code如下:
vector_irq: irq中断的入口, vector_irq的定义为:vector_stub
vector_stub irq, IRQ_MODE, 4
__irq_svc:
svc_entry
irq_handler
.macro irq_handler
ldr r1, =handle_arch_irq
mov r0, sp
ldr pc, [r1]
可知该段汇编最终会调用handle_arch_irq,那么handle_arch_irq是什么呢?想了解这个问题,
需要对gic的初始化过程进行分析, code如下:
gic_of_init() drivers/irqchip/irq-gic.c
->__gic_init_bases()
->set_handle_irq(gic_handle_irq)
{
handle_arch_irq = handle_irq;
}
至此,中断处理过程从汇编跳到了C语言,不熟悉汇编的人可以放松下来了,继续分析:
gic_handle_irq(struct pt_regs *regs) drivers/irqchip/irq-gic.c
{
1. 获取struct gic_chip_data的结构体gic,gic = &gic_data[0];
2. 获取cpu interface的base address,void __iomem *cpu_base = gic_data_cpu_base(gic);
3. do while(1)循环进行中断处理
{
1. 获得硬件中断号
{
1. irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
2. irqnr = irqstat & GICC_IAR_INT_ID_MASK;
}
2. if (likely(irqnr > 15 && irqnr < 1020)), 如果为PPI或SPI中断, 走irq domain的处理方式
{
irq_enter()
{
account_irq_enter_time(current);
preempt_count_add(HARDIRQ_OFFSET);
}
__handle_domain_irq(gic->domain, irqnr, regs);
{
1. 保护现场, struct pt_regs *old_regs = set_irq_regs(regs);
2. 根据硬件中断号找到gic domain对应的软件中断号, 如果找到的软件中断号有误,直接返回
{
irq = irq_find_mapping(dom