2. Linux中断子系统架构:从硬件中断到CPU响应,再到内核中断服务例程(ISR)的完整路径

本章深入剖析Linux中断子系统的完整架构,从硬件引脚上的电平变化,到CPU的异常响应,再到内核中注册的中断服务例程(ISR)被调用执行的完整路径。理解这一路径是掌握中断处理与NAPI轮询协同设计的基础。

2.1 中断子系统整体架构分层

Linux中断子系统采用分层设计,从上到下依次为:硬件层、中断控制器层、CPU异常处理层、通用中断框架层以及设备驱动层。每一层都封装了特定的职责,并通过标准接口与上下层交互。

核心观点: 中断路径的本质是“硬件事件 → 软件处理”的桥接过程。每一层都在减少CPU的轮询负担,提高事件响应效率。
Linux中断子系统分层架构 Linux 中断子系统分层架构 硬件设备层 PCIe网卡 / USB控制器 / 定时器 / GPIO外设 中断控制器层 APIC (x86) / GIC (ARM) / INTC (RISC-V) CPU异常处理层 中断向量表(IDT/IVT) → 保存上下文 → 跳转入口 通用中断框架层 (Generic IRQ) irq_desc / irq_chip / 中断流处理 / 中断线程化 设备驱动层 (ISR) request_irq() / devm_request_irq() / 中断服务例程

2.2 硬件中断信号到CPU的传递路径

当外设产生中断时,信号传递遵循以下物理路径:

  1. 外设断言中断线: 设备通过其INT引脚拉高或拉低电平,向中断控制器发送请求。
  2. 中断控制器仲裁与路由: 控制器根据优先级、亲和性设置,决定将中断送达哪个CPU核心。
  3. CPU核心接收中断信号: CPU在指令边界检查INTR引脚或LAPIC的IRQ线,若中断未被屏蔽,则进入中断响应周期。
  4. CPU自动保存关键上下文: 硬件自动将EFLAGS/RFLAGS、CS、EIP/RIP压栈,并加载中断门描述符中的段选择子和偏移量。
中断信号传递各阶段延迟对比
阶段 典型延迟 影响因素
外设信号建立 10~100 ns 总线协议、电气特性
中断控制器仲裁 50~500 ns 优先级比较、路由表查找
CPU响应与上下文保存 100~300 ns 流水线冲刷、微码操作
内核入口代码执行 200~1000 ns 页表切换、栈切换

2.3 CPU响应中断:从向量表到入口代码

CPU响应中断后,硬件强制跳转到中断向量表(x86的IDT,ARM的异常向量表)中对应的表项。该表项包含一个门描述符,指向内核的中断入口代码。

架构差异提示: x86架构使用IDT(中断描述符表),每个中断向量对应一个门描述符;ARM架构使用异常向量表(Exception Vector Table),通常位于0xFFFF0000或0x00000000。RISC-V则使用mtvec/stvec寄存器指向中断入口。
CPU中断响应流程 CPU 中断响应流程 (x86 架构示例) 1. 外设触发中断 2. 控制器路由到CPU 3. CPU 响应中断 4. 硬件自动操作 压栈 SS/ESP/EFLAGS/CS/EIP 从IDT加载CS:EIP 5. 内核入口代码 common_interrupt / handle_arch_irq 6. 通用中断框架 generic_handle_irq_desc()

2.4 内核中断服务例程(ISR)的执行路径

CPU进入内核入口代码后,软件逻辑开始接管。以下是ISR被调用的完整路径:

  1. 保存完整寄存器上下文: 入口代码(如x86的common_interrupt)将通用寄存器、段寄存器压栈,建立pt_regs结构。
  2. 调用中断流处理函数: 根据中断号查找irq_desc,调用对应的handle_irq流处理函数(如handle_edge_irq、handle_level_irq)。
  3. 执行已注册的ISR: 流处理函数遍历irq_desc->action链表,依次调用每个irqaction中的handler函数指针。
  4. 中断结束(EOI)与返回: ISR执行完毕后,流处理函数向中断控制器发送EOI命令,允许后续中断到达。最后执行iret或eret指令恢复上下文。
关键约束: ISR运行在中断上下文中,必须快速完成(通常建议在微秒级)。ISR中禁止调用可能导致睡眠的函数(如mutex_lock、kmalloc(GFP_KERNEL))。对于耗时操作,应使用中断下半部(Softirq/Tasklet/Workqueue)或NAPI轮询机制。

2.5 中断描述符(irq_desc)与中断流处理

内核使用irq_desc结构体管理每个中断号的状态与处理逻辑。该结构体是中断子系统的核心数据结构。

irq_desc 核心字段说明
字段 类型 作用
irq_data struct irq_data 包含中断号、芯片私有数据、中断类型(电平/边沿)
handle_irq irq_flow_handler_t 中断流处理函数指针,决定中断处理策略
action struct irqaction * 指向已注册ISR的链表头,支持共享中断
status unsigned int 中断状态标志(IRQ_INPROGRESS、IRQ_DISABLED等)
depth unsigned int 中断禁用嵌套深度,用于disable_irq/enable_irq配对

中断流处理函数是连接通用框架与具体ISR的桥梁。常见流处理函数包括:

  • handle_simple_irq: 用于无需硬件控制器的简单中断,直接调用ISR。
  • handle_level_irq: 用于电平触发中断,在ISR执行期间屏蔽中断源,防止重复触发。
  • handle_edge_irq: 用于边沿触发中断,处理时需注意丢失的边沿事件。
  • handle_fasteoi_irq: 用于支持EOI寄存器的中断控制器,如ARM GIC v2/v3。
irq_desc 与 ISR 调用关系 irq_desc 与 ISR 调用关系 irq_desc irq: 中断号 handle_irq: 流处理函数 irq_data.chip: 控制器操作 action: ISR链表头 status: 状态标志 depth: 禁用嵌套深度 irqaction #1 handler: my_isr() irqaction #2 handler: my_isr2() handle_irq() 遍历调用

2.6 中断路径中的关键数据结构关系

整个中断路径涉及多个关键数据结构,它们之间的协作关系如下:

  • irq_domain: 将硬件中断号(hwirq)映射到Linux IRQ号,是中断控制器与通用框架的桥梁。
  • irq_chip: 封装中断控制器的底层操作(mask/unmask/ack/eoi),由具体硬件驱动实现。
  • irqaction: 代表一个设备驱动注册的中断处理请求,包含handler、dev_id、flags等。
  • pt_regs: 保存中断发生时的CPU寄存器状态,用于恢复现场。
路径总结: 硬件中断信号 → 中断控制器路由 → CPU向量表跳转 → 内核入口代码保存上下文 → 通用中断框架查找irq_desc → 流处理函数调用irqaction链表中的ISR → ISR执行 → EOI → 恢复上下文返回。

2.7 中断路径性能关键点

从硬件到ISR的完整路径中,以下环节对性能影响最大:

中断路径性能关键点与优化方向
环节 性能开销 优化方向
中断控制器路由 中等 使用中断亲和性(IRQ affinity)绑定到特定CPU,避免跨核转发
CPU上下文保存 高 使用快速系统调用(如x86的sysenter)减少保存量;ARM的v7/v8支持硬件自动保存
irq_desc查找 低 使用radix树或直接数组索引,O(1)查找
ISR执行 取决于驱动 将耗时操作推迟到下半部;使用NAPI轮询合并中断
EOI与返回 低 使用EOI寄存器直接写操作,避免函数调用开销