2. 中断处理流程:中断请求、中断响应、中断服务程序(ISR)执行、中断返回、中断现场保护与恢复
中断处理是操作系统响应异步事件的核心机制。一个完整的中断处理生命周期包含五个紧密衔接的阶段:中断请求、中断响应、中断服务程序(ISR)执行、中断返回,以及贯穿始终的中断现场保护与恢复。理解这一流程是掌握操作系统并发与实时性的基础。
2.1 中断处理五阶段总览
下表概括了每个阶段的核心动作、参与硬件/软件模块以及关键特征:
| 阶段 | 核心动作 | 主要参与者 | 关键特征 |
|---|---|---|---|
| 中断请求 | 外设或软件产生中断信号,发送至中断控制器 | 外设、GIC(通用中断控制器) | 电平触发/边沿触发;可屏蔽/不可屏蔽 |
| 中断响应 | CPU 保存当前执行现场,查询中断向量,跳转至 ISR 入口 | CPU、GIC、中断向量表 | 硬件自动完成;原子操作 |
| ISR 执行 | 执行与中断源对应的处理逻辑 | CPU、内核中断处理框架 | 上下文受限;应短小精悍 |
| 中断返回 | 恢复现场,执行中断返回指令,回到被中断点 | CPU | 恢复 CPSR/PC 等关键寄存器 |
| 现场保护与恢复 | 保存/恢复被中断任务的寄存器、状态字、栈指针 | CPU(硬件部分)、ISR 入口/出口代码(软件部分) | 贯穿响应与返回阶段 |
关键概念: 中断现场保护是中断处理正确性的基石。若现场保存不完整,被中断任务恢复后将产生不可预测的行为,导致系统崩溃或数据损坏。
2.2 中断请求(Interrupt Request)
中断请求是中断处理流程的起点。外设通过其中断线向中断控制器(如 ARM GIC)发送请求信号。中断控制器对多个中断源进行优先级仲裁,并将最高优先级的中断转发给 CPU。
- 中断源类型:
- 硬件中断: 由外部设备(定时器、网络控制器、磁盘控制器)产生。
- 软件中断: 由 CPU 执行特定指令(如 ARM 的
SVC、SWI)主动触发,用于系统调用。
- 触发方式:
- 电平触发: 中断信号保持有效电平直到被 CPU 响应。
- 边沿触发: 中断信号在电平跳变(上升沿或下降沿)时被检测。
- 中断控制器仲裁: GIC 根据中断优先级(Priority)和中断 ID 进行裁决,向 CPU 发送
IRQ或FIQ信号。
2.3 中断响应(Interrupt Response)
CPU 在每条指令执行周期的末尾采样中断请求线。当检测到有效中断且中断使能位(CPSR.I 或 CPSR.F)允许响应时,CPU 硬件自动执行以下原子操作序列:
- 保存返回地址: 将当前程序计数器(PC)的值保存到链接寄存器(LR)或专用栈中。
- 保存当前状态: 将当前程序状态寄存器(CPSR)保存到备份状态寄存器(SPSR)中。
- 切换处理器模式: CPU 切换到中断模式(IRQ 或 FIQ 模式),并禁用同级中断。
- 获取中断向量: 从中断向量表中读取对应中断类型的入口地址。
- 跳转执行: 将 PC 设置为中断向量地址,开始执行 ISR。
硬件加速: 上述 1-5 步由 CPU 微架构在数个时钟周期内完成,无需软件干预,保证了中断响应的实时性。
2.4 中断服务程序(ISR)执行
ISR 是处理特定中断事件的软件函数。其执行环境与普通任务有显著区别:
- 上下文受限: ISR 运行在中断上下文中,不可睡眠、不可持有互斥锁、不可进行可能阻塞的系统调用。
- 执行时间要求: ISR 应尽可能短小,通常只完成必要的数据搬运、状态清除和事件标记,将耗时处理推迟到下半部(Bottom Half)或任务上下文。
- 中断嵌套: 高优先级中断可以抢占低优先级 ISR 的执行。GIC 通过优先级掩码控制嵌套深度。
/* 典型的 ISR 框架(ARM Cortex-A 系列) */
void irq_handler(void) {
unsigned int irq_id;
/* 1. 从 GIC 读取中断 ID */
irq_id = gic_read_iar();
/* 2. 根据中断 ID 分发处理 */
switch (irq_id) {
case TIMER_IRQ:
timer_isr();
break;
case UART_IRQ:
uart_isr();
break;
default:
/* 未知中断,错误处理 */
break;
}
/* 3. 向 GIC 发送中断结束信号(EOI) */
gic_write_eoir(irq_id);
}
2.5 中断返回(Interrupt Return)
ISR 执行完毕后,CPU 执行中断返回指令(ARM 架构中为 SUBS PC, LR, #4 或 MOVS PC, LR),该指令完成以下操作:
- 恢复 PC: 从 LR 中取出被中断点的返回地址(需根据流水线调整偏移)。
- 恢复 CPSR: 将 SPSR 中的内容复制回 CPSR,恢复被中断时的处理器状态和中断使能位。
- 恢复处理器模式: CPU 从中断模式切换回被中断前的模式(用户模式、系统模式等)。
至此,CPU 从被中断的指令处继续执行,仿佛中断从未发生过。
2.6 中断现场保护与恢复
现场保护与恢复是中断处理流程中保证正确性的关键环节,分为硬件自动保护和软件手动保护两部分。
| 保护层级 | 保护内容 | 执行者 | 说明 |
|---|---|---|---|
| 硬件自动保护 | PC、CPSR → SPSR、LR | CPU 微架构 | 中断响应时自动完成,不可编程 |
| 软件手动保护 | 通用寄存器(R0-R12)、栈指针(SP)、浮点寄存器等 | ISR 入口/出口代码 | 由编译器或汇编编写者显式压栈/出栈 |
| 嵌套保护 | 多层 LR/SPSR 保存 | 软件 + GIC 硬件 | 中断嵌套时需手动保存前一层 LR/SPSR |
常见错误: 在 ISR 中修改了通用寄存器但未在入口处保存,导致返回后被中断任务使用错误的数据。这是中断处理中最隐蔽的 bug 之一。
2.7 中断处理完整流程示意图
下图展示了从外设请求到中断返回的完整数据流与控制流:
2.8 中断现场保护与恢复的软件实现
在 ARM Cortex-A 系列处理器中,ISR 的入口和出口通常由汇编代码编写,以确保现场保护的完整性。以下是一个典型的现场保护与恢复代码片段:
/* ARM 汇编:中断现场保护与恢复 */
irq_entry:
/* 软件现场保护:压栈被中断任务的通用寄存器 */
SUB lr, lr, #4 /* 调整返回地址(ARM 流水线) */
SRSDB sp!, #0x12 /* 保存 SPSR 和 LR 到 IRQ 模式栈 */
CPS #0x12 /* 切换到 IRQ 模式 */
PUSH {r0-r12, lr} /* 保存通用寄存器 R0-R12 和 LR */
/* 调用 C 语言 ISR 处理函数 */
BL irq_handler
/* 软件现场恢复:出栈通用寄存器 */
POP {r0-r12, lr} /* 恢复通用寄存器 */
RFEIA sp! /* 恢复 SPSR 和 PC,完成中断返回 */
设计原则: 现场保护代码必须与被中断任务的上下文严格对称。压栈顺序与出栈顺序相反,确保寄存器值被正确恢复。
2.9 中断处理流程中的关键时序
中断处理的实时性由以下关键时序指标衡量:
- 中断延迟(Interrupt Latency): 从中断请求信号到达 CPU 到 ISR 第一条指令开始执行的时间间隔。受中断屏蔽、指令执行周期、总线竞争等因素影响。
- 中断响应时间(Interrupt Response Time): 中断延迟 + ISR 执行时间。
- 中断嵌套深度: 允许的高优先级中断抢占低优先级 ISR 的层数,受栈空间和 GIC 优先级配置限制。
理解并优化这些时序指标,是嵌入式实时系统设计中的核心挑战。