1. 中断概念:中断的定义、中断向量表、中断服务程序(ISR)的基本概念与硬件触发流程

1.1 中断的定义

中断(Interrupt)是嵌入式系统与通用计算机中一种核心的硬件机制,它允许外设或软件通过一个电信号或消息,异步地通知处理器发生了需要立即关注的事件。当处理器接收到中断信号后,会暂停当前正在执行的程序流,保存现场,然后跳转到一个预先定义好的处理程序去响应这个事件,处理完成后再恢复原来的程序继续执行。

核心特征:中断的“异步性”意味着它可以在主程序执行的任意时刻发生,不受主程序控制。这与轮询(Polling)方式形成鲜明对比——轮询需要CPU主动、周期性地检查设备状态,效率低下且实时性差。

1.2 中断向量表(Interrupt Vector Table, IVT)

中断向量表是一张存储在内存固定区域的表格,其每个表项(称为中断向量)存放着对应中断服务程序(ISR)的入口地址。当硬件中断发生时,CPU通过中断控制器获取中断号,然后以该中断号为索引在IVT中查找对应的ISR地址,并跳转执行。

概念 说明
中断向量号 每个中断源被分配一个唯一的数字标识(0~255),用于索引IVT。
中断向量 IVT中的每一个表项,存储着对应ISR的起始地址(段基址+偏移量)。
IVT基址 IVT在内存中的起始物理地址。在x86实模式下通常位于0x0000:0x0000;在ARM Cortex-M中位于向量表偏移寄存器(VTOR)指定的地址。
表项大小 在x86实模式下每个向量占4字节(段:偏移);在ARM Cortex-M中每个向量占4字节(函数地址)。
注意:在Linux内核启动早期,系统会从引导加载程序(如U-Boot)设置的IVT切换到内核自己管理的中断描述符表(IDT)。IDT是IVT在保护模式下的进化版本,除了地址外还包含权限级别(DPL)和门类型等信息。

1.3 中断服务程序(ISR)的基本概念

中断服务程序(Interrupt Service Routine, ISR)是响应特定中断事件而执行的专用函数。ISR必须满足以下关键约束:

  • 快速执行:ISR执行期间,同级或更低优先级的中断通常被屏蔽,过长的ISR会严重影响系统的实时响应能力。
  • 不可阻塞:ISR中不能调用可能导致睡眠(sleep)或阻塞(block)的内核函数(如 mutex_lock、copy_from_user)。
  • 保存/恢复上下文:ISR入口必须保存所有可能被破坏的寄存器,出口必须恢复,确保被中断的程序能正确继续。
  • 可重入性:在支持中断嵌套的系统中,高优先级ISR可能打断低优先级ISR,因此ISR应尽量设计为可重入或使用锁保护共享数据。

1.4 硬件触发流程

一个典型的中断从硬件触发到CPU开始执行ISR,经历以下标准步骤:

  1. 外设事件发生:硬件设备(如网卡、定时器、GPIO引脚)产生一个中断请求信号。
  2. 中断控制器仲裁:中断控制器(如x86的APIC、ARM的GIC)接收多个中断源信号,根据优先级、使能状态和当前CPU状态,选择一个最高优先级的中断向CPU核心发送。
  3. CPU响应中断:CPU在每条指令执行的最后阶段检查中断请求线。若检测到有效中断且中断允许标志(IF)为1,则进入中断响应周期。
  4. 保存现场:CPU自动将当前程序计数器(PC/CS:IP)、处理器状态字(PSW/EFLAGS)以及部分寄存器压入堆栈。
  5. 获取中断向量:CPU向中断控制器发送中断响应信号(INTA),中断控制器返回中断向量号。
  6. 查表跳转:CPU以中断向量号为索引,从IVT/IDT中读取ISR入口地址,并跳转执行。
  7. 执行ISR:CPU开始执行中断服务程序,处理硬件事件。
  8. 中断返回:ISR执行完毕后执行中断返回指令(如x86的 iret),CPU从堆栈恢复之前保存的现场,继续执行被中断的程序。
关键时序指标:中断延迟(Interrupt Latency) = 从硬件中断信号产生到CPU开始执行ISR第一条指令的时间。该指标直接影响系统的实时性能,通常由中断控制器仲裁时间、CPU响应时间、现场保存时间共同决定。
中断硬件触发流程 中断硬件触发流程 ① 外设事件发生 ② 中断控制器仲裁 ③ CPU响应中断 ④ 保存现场 ⑤ 获取中断向量 ⑥ 查表跳转ISR ⑦ 执行ISR ⑧ 中断返回 ⑨ 恢复现场 说明: 中断延迟 = 步骤①~③的时间总和。在Linux内核中,中断控制器(如GIC/APIC)的配置直接影响中断优先级和CPU间的负载均衡。 步骤④~⑨由CPU硬件自动完成,ISR开发者只需关注步骤⑦中的业务逻辑。

1.5 中断向量表结构示例(ARM Cortex-M)

以ARM Cortex-M系列处理器为例,中断向量表的前16个向量为系统异常(如复位、NMI、硬fault),从向量号16开始为外部中断(IRQ)。向量表基址由VTOR寄存器控制,支持运行时重定位。

/* ARM Cortex-M 向量表示例(部分) */
__attribute__((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
    /* 系统异常(向量号 0~15) */
    (void (*)(void)) &__StackTop,      /* 0: 初始栈指针 */
    Reset_Handler,                     /* 1: 复位 */
    NMI_Handler,                       /* 2: NMI */
    HardFault_Handler,                 /* 3: 硬fault */
    /* ... 其他系统异常 ... */
    SVC_Handler,                       /* 11: SVC */
    /* ... */
    /* 外部中断(向量号 16~255) */
    TIM2_IRQHandler,                   /* 28: TIM2 全局中断 */
    TIM3_IRQHandler,                   /* 29: TIM3 全局中断 */
    I2C1_EV_IRQHandler,                /* 31: I2C1 事件中断 */
    /* ... */
};
Linux内核视角:在ARM Linux中,内核启动时会通过 early_trap_init() 或 vectors_fixup() 将异常向量表复制到高地址(0xffff0000)或由VTOR指向的地址,并设置中断处理入口为 asm_do_IRQ,该函数最终调用注册到内核的通用中断处理框架(Generic IRQ layer)。

1.6 中断与异常的区别

特性 中断(Interrupt) 异常(Exception)
触发源 外部硬件设备(异步) CPU内部指令执行(同步)
发生时机 指令边界之间,不可预测 指令执行过程中,可预测
典型例子 网卡收到数据包、定时器超时 除零错误、缺页、系统调用(trap)
返回行为 返回到被中断指令的下一条 可能返回到当前指令(fault)、下一条(trap)或终止(abort)
Linux处理 通过 request_irq() 注册ISR 通过 set_trap_handler() 或do_page_fault()处理
总结:中断是嵌入式Linux系统响应外部事件的第一推动力。理解中断向量表的布局、ISR的约束条件以及硬件触发流程,是后续学习中断下半部(softirq、tasklet、workqueue)的基础。在下一章中,我们将深入分析Linux内核如何将中断处理拆分为上半部(Top Half)和下半部(Bottom Half),以解决ISR必须快速执行与复杂处理逻辑之间的矛盾。