1 中断处理
一般的中断处理过程如图1所示,可以看出中断的处理过程是软件和硬件协同完成的。
图1 中断处理过程
当中断发生后,当前处理器上正在执行的任务将被中断, CPU(Processor Interrupt logic)将会完成一些保护现场跳到中断向量表等工作,在跳转中断向量表后开始执行一些体系结构相关的工作,然后进入通用的中断处理流程,然后找到相应的中断处理函数并执行该函数。
1.1 CPU自动完成的工作
Ø R14_irq = 下一条待执行指令地址 + 4
Ø SPSR_irq = CPSR
Ø CPSR[4:0] = 0b10010 //置CPU为irq模式
Ø CPSR[5]=0 //运行在arm态
Ø CPSR[7]=1 //关闭IRQ中断
Ø CPSR[9] = CP15_reg1_EEbit //设置异常处理模式为Endianness模式
Ø 根据硬件设置,跳转到0xffff0018,即跳转到中断向量表对应项
1.2 中断处理过程
请参考ARM Linux中断处理过程分析。在这里只做简单的梳理,中断发生后的软件处理过程如下:
1 根据当前CPU的工作状态找到底层中断处理函数(__irq_usr或__irq_svc), 调用usr_entry或svc_entry保存现场并禁止抢占,然后调用irq_handler;
2 irq_handler最终调用arch_irq_handler_default读取GIC的相关信息,确定中断号和中断状态等,调用中断处理C函数,根据不同的中断号调用不同的C函数,例如asm_do_IRQ、do_IPI或do_local_timer。具体代码如下:
irq_handler在arch/arm/kernel/entry-armv.S定义
/*
* Interrupt handling. Preserves r7, r8, r9
*/
.macro arch_irq_handler_default
get_irqnr_preamble r5, lr @SoC相关代码,定义在entry-macro.S中。
1: get_irqnr_and_base r0, r6, r5, lr @SoC相关代码,定义在entry-macro.S中。
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, BSYM(1b)
bne asm_do_IRQ
#ifdef CONFIG_SMP
/*
* XXX
*
* this macro assumes that irqstat (r6) and base (r5) are
* preserved from get_irqnr_and_base above
*/
ALT_SMP(test_for_ipi r0, r6, r5, lr)
ALT_UP_B(9997f)
movne r1, sp
adrne lr, BSYM(1b)
bne do_IPI
#ifdef CONFIG_LOCAL_TIMERS
test_for_ltirq r0, r6, r5, lr
movne r0, sp
adrne lr, BSYM(1b)
bne do_local_timer
#endif
#endif
9997:
.endm
3 中断处理完成后,将恢复现场,并根据需要决定是否调度。
对中断号的分配方案做如下说明:
Interrupts 0-15 are IPI
16-28 are reserved
29-31 are local. We allow 30 to be used for the watchdog.
32-1020 are global
1021-1022 are reserved
1023 is "spurious" (no interrupt)
1.3 SPI中断处理(asm_do_IRQ)
SPI(share peripheral interrupt)中断,用于一般的硬件产生的中断,中断号的范围是32-1020。
asm_do_IRQ将调用体系结构无关的Linux内核中断部分代码完成中断处理工作,具体的函数调用流程如下:
asm_do_IRQ
generic_handle_irq
generic_handle_irq_desc
desc->handle_irq// handle_fasteoi_irq
handle_irq_event
handle_irq_event_percpu
res = action->handler(irq, action->dev_id);
asm主要是将irq传递给Linux内核的中断处理部分,然后Linux内核根据irq找到irq_desc结构,然后调用相应的中断处理函数。