1. 中断基础概念:中断定义、中断向量表、中断优先级、中断嵌套与共享中断的引入背景

1.1 中断定义与核心机制

中断(Interrupt)是嵌入式系统与操作系统内核中一种关键的异步事件处理机制。当外设(如触摸屏、传感器、网络控制器)需要 CPU 关注时,通过硬件信号线向 CPU 发送中断请求。CPU 在完成当前指令后,暂停正在执行的程序,保存上下文,跳转至预先注册的中断服务程序(ISR, Interrupt Service Routine)执行,完成后恢复原程序继续运行。

中断的本质:一种硬件驱动的、异步的、优先级可编程的事件通知与处理模型。它使得 CPU 无需轮询外设状态,从而大幅提升系统实时性与吞吐量。
中断触发与处理流程 中断触发与处理流程 外设 (触摸屏/传感器) 中断控制器 (GIC/APIC) CPU 核心 (保存/恢复上下文) ISR (中断服务程序) 中断请求 IRQ 信号 跳转 返回 说明:中断请求由外设发起,经中断控制器仲裁后送达 CPU,CPU 保存现场后执行 ISR,完成后恢复现场继续原任务。

1.2 中断向量表(IVT)与中断描述符表(IDT)

中断向量表是系统启动阶段建立的一张映射表,用于将中断号(IRQ Number)与对应的中断服务程序入口地址关联起来。在 ARM Cortex-A 系列处理器中,该表称为中断向量表(Vector Table);在 x86 架构中称为中断描述符表(IDT)。Android 设备主要基于 ARM 架构,因此以下以 ARM 为例。

概念 ARM 架构 x86 架构 作用
中断向量表 Vector Table(基地址由 VBAR 寄存器指定) IDT(基地址由 IDTR 寄存器指定) 存储异常/中断处理程序入口地址
表项大小 每个表项 4 字节(32 位)或 8 字节(64 位) 每个表项 8 字节(保护模式) —
最大中断数 通常 256 个(0~255) 256 个(0~255) —
动态修改 通过内核修改 VBAR 或重映射 通过 LIDT 指令加载新表 支持运行时注册/注销 ISR
Android 内核实践:在 Linux/Android 内核中,中断向量表由 arch/arm/kernel/entry-armv.S 或 arch/arm64/kernel/entry.S 中的汇编代码初始化。设备驱动通过 request_irq() 或 devm_request_irq() 将 ISR 注册到内核中断子系统,内核负责将 ISR 地址填入向量表对应表项。
中断向量表结构示意 ARM 中断向量表结构示意 向量表基地址 (VBAR) 偏移 0x00 复位 (Reset) 入口地址: 0x8000_0000 偏移 0x04 未定义指令 (Undef) 入口地址: 0x8000_0004 偏移 0x08 软件中断 (SWI/SVC) 入口地址: 0x8000_0008 偏移 0x1C IRQ 中断 入口地址: 0x8000_001C 说明:每个表项占 4 字节(32 位),共 256 个表项。IRQ 中断位于偏移 0x1C。

1.3 中断优先级与中断嵌套

中断优先级决定了当多个中断同时到达时,CPU 优先处理哪一个。ARM GIC(Generic Interrupt Controller)支持 16~256 级优先级(取决于 GIC 版本)。高优先级中断可以抢占低优先级中断的执行,形成中断嵌套。

  • 中断优先级:每个中断源分配一个优先级数值(数值越小优先级越高)。GIC 通过优先级比较器决定哪个中断先送达 CPU。
  • 中断嵌套:当 CPU 正在执行低优先级 ISR 时,若高优先级中断到达,CPU 可暂停当前 ISR,保存现场,执行高优先级 ISR,完成后返回低优先级 ISR 继续执行。
  • 嵌套深度限制:受限于栈空间和中断控制器配置,实际系统中通常限制嵌套层数(如 2~3 层),避免栈溢出。
注意:在 Android 内核中,中断嵌套可能导致优先级反转、死锁或实时性下降。共享中断场景下,多个设备共用同一 IRQ 线,嵌套行为更加复杂,需要驱动开发者谨慎处理。
中断优先级与嵌套时序 中断优先级与嵌套时序 时间 → 主程序 低优先级 ISR 高优先级 ISR 恢复 IRQ_LOW IRQ_HIGH 说明:高优先级中断(IRQ_HIGH)在低优先级 ISR 执行期间到达,CPU 暂停低优先级 ISR, 执行高优先级 ISR 完成后,再恢复低优先级 ISR 继续执行。 GIC 优先级等级(示例) 优先级 0 (最高) 优先级 5 优先级 10 优先级 15 优先级 31 (最低)

1.4 共享中断的引入背景

在嵌入式系统早期,每个外设独占一条中断线(IRQ Line)。随着 SoC 集成度提高,外设数量激增,但芯片封装引脚和中断控制器输入线数量有限。以 ARM GIC-400 为例,最多支持 256 个 SPI(Shared Peripheral Interrupt)中断源,而一个现代智能手机 SoC 可能包含 50+ 个外设模块,中断线资源成为瓶颈。

共享中断(Shared Interrupt)应运而生:多个外设共用同一条 IRQ 线,中断控制器在触发中断时,由内核中断子系统依次调用注册在该 IRQ 线上的所有 ISR,每个 ISR 自行判断是否为自己的设备产生了中断。

对比维度 独占中断 共享中断
中断线分配 每个外设独占一条 IRQ 线 多个外设共用一条 IRQ 线
ISR 注册 request_irq(irq, handler, IRQF_NO_SHARED, ...) request_irq(irq, handler, IRQF_SHARED, ...)
中断处理 直接执行对应 ISR 遍历共享链,逐个调用 ISR 直到找到处理者
硬件要求 中断线必须支持电平触发或边沿触发 必须支持电平触发(电平保持直到所有设备处理完毕)
调试复杂度 低,中断源明确 高,需区分哪个设备产生中断
共享中断的典型场景:在 Android 设备中,多个 GPIO 按键(音量键、电源键、指纹传感器)常共享同一条 IRQ 线;I2C 总线上的多个从设备也可能共享中断线。共享中断是节省硬件引脚、降低 BOM 成本的关键技术。
共享中断架构示意 共享中断架构示意 中断控制器 (GIC) IRQ #42 (共享线) 设备 A (触摸屏) 设备 B (指纹传感器) 设备 C (音量按键) 设备 D (其他) 内核中断子系统 (共享链遍历) 依次调用 A→B→C→D 的 ISR,直到某 ISR 返回 IRQ_HANDLED

1.5 共享中断在 Android 中的挑战

共享中断虽然节省了硬件资源,但也给驱动开发和调试带来了显著挑战:

  1. 中断源识别:每个 ISR 必须通过读取设备寄存器状态来判断中断是否属于自己的设备,不能误处理其他设备的中断。
  2. 性能开销:共享链上的所有 ISR 都会被调用,即使中断并非自己的设备,也会产生额外的函数调用开销。
  3. 中断处理顺序:内核按照注册顺序遍历共享链,先注册的 ISR 先被调用。如果某个 ISR 处理时间过长,会延迟后续 ISR 的执行。
  4. 调试困难:当共享 IRQ 线出现异常(如中断风暴、丢失中断)时,难以快速定位是哪个设备导致的问题。
  5. 电源管理:共享中断线在系统休眠时可能被任意一个设备唤醒,需要精确的唤醒源识别机制。