基本上Linux支持的平台都或多或少采用了中断的概念,中断可以周期性产生或者随机产生,如:网卡硬件在收到数据包时会产生中断,而后内核中断处理例程将进行处理。
中断的分类:
- 硬件中断
由与CPU连接的外设产生的中断,外设无法产生中断,是通过一个中断控制器产生中断。
- 软中断
由内核模拟实现的一种中断机制,是平台无关的,它依赖于硬件中断。
同步中断和异常:
由CPU自身产生,例如 除零 或用户空间应用程序访问了一个地址空间,该地址空间没有关联物理页,这将产生缺页异常,内核需要关注CPU产生的各种异常,并进行响应的处理。
异步中断:
它们由外部设备产生,可能发生于任何时间,当中断产生时内核可能处于任何状态,内核会尽快处理该类型中断,然后将CPU时间交还给用户进程。
中断号:
每一个中断都有一个中断号,用于区分不同的中断情况,例如:网卡,当数据分组到来时,将产生中断号N,内核会识别这个网卡中断并调用合适的处理例程,但是不同体系架构支持的中断号数量不一,如IA32处理器仅支持最大15个中断数目,并且其中一些已分配给固定的设备: 鼠标、键盘等。
中断共享:
为了解决中断数量少而采用的一种中断使用方式,多个设备使用一个中断号来使系统支持更多的设备,这需要内核和硬件均支持才能做好。
CPU产生中断中,会根据中断号调用相应的中断服务例程,以x86架构为例,在初始化系统时会安装各类中断例程到IDT(中断描述符表),中断号为索引每个中断项就是中断处理例程的地址。
内核安装的CPU内部中断历程:
static const __initconst struct idt_data def_idts[] = {
INTG(X86_TRAP_DE, asm_exc_divide_error),
INTG(X86_TRAP_NMI, asm_exc_nmi),
INTG(X86_TRAP_BR, asm_exc_bounds),
INTG(X86_TRAP_UD, asm_exc_invalid_op),
INTG(X86_TRAP_NM, asm_exc_device_not_available),
INTG(X86_TRAP_OLD_MF, asm_exc_coproc_segment_overrun),
INTG(X86_TRAP_TS, asm_exc_invalid_tss),
INTG(X86_TRAP_NP, asm_exc_segment_not_present),
INTG(X86_TRAP_SS, asm_exc_stack_segment),
INTG(X86_TRAP_GP, asm_exc_general_protection),
INTG(X86_TRAP_SPURIOUS, asm_exc_spurious_interrupt_bug),
INTG(X86_TRAP_MF, asm_exc_coprocessor_error),
INTG(X86_TRAP_AC, asm_exc_alignment_check),
INTG(X86_TRAP_XF, asm_exc_simd_coprocessor_error),
#ifdef CONFIG_X86_32
TSKG(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS),
#else
INTG(X86_TRAP_DF, asm_exc_double_fault),
#endif
INTG(X86_TRAP_DB, asm_exc_debug),
#ifdef CONFIG_X86_MCE
INTG(X86_TRAP_MC, asm_exc_machine_check),
#endif
SYSG(X86_TRAP_OF, asm_exc_overflow),
#if defined(CONFIG_IA32_EMULATION)
SYSG(IA32_SYSCALL_VECTOR, entry_INT80_compat),
#elif defined(CONFIG_X86_32)
SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32),
#endif
};
以上是中断的地址,在内核启动过程中Start_Kernel->trap_init
void __init idt_setup_traps(void)
{
idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true);
}
内核中断涉及的数据结构:
//这个结构体在5.x内核版本中扩展了很多,我裁剪了不太重要的成员。
struct irq_desc {
struct irq_common_data irq_common_data; //该中断的信息 如 中断号、 dev_id(实现中断共享的关键)
irq_flow_handler_t handle_irq;
struct irqaction *action; /* IRQ action list */ 中断处理例程链表
}