4. GIC 中断状态机:状态定义与转换机制
GIC(Generic Interrupt Controller)使用一个有限状态机来管理每个中断源的生命周期。理解这四种状态及其转换条件是开发可靠中断驱动的基石。任何中断请求(无论是边沿触发还是电平触发)都遵循这一状态模型。
4.1 四种中断状态定义
| 状态 | 缩写 | 描述 | 典型场景 |
|---|---|---|---|
| Inactive | I | 中断未触发,处于空闲状态。中断控制器不向PE发送任何信号。 | 系统启动后,所有中断源默认处于此状态。 |
| Pending | P | 中断条件已满足,等待CPU处理。中断信号已到达GIC,但尚未分发给任何PE。 | 外设产生中断请求,GIC记录该事件。 |
| Active | A | 中断已分发到PE,CPU正在执行对应的中断服务程序(ISR)。 | CPU读取GICC_IAR寄存器,中断进入Active状态。 |
| Active and Pending | A&P | CPU正在处理当前中断,同时该中断源又产生了新的中断请求。 | 高频率中断或电平中断在ISR执行期间再次被断言。 |
关键概念: 对于电平触发的中断,只要外部信号保持有效,中断就会在硬件层面持续处于Pending状态。GIC通过状态机确保不会丢失任何中断事件,即使在ISR执行期间。
4.2 中断状态转换图
下图展示了GIC中断状态机的完整转换路径。箭头上的标注表示触发转换的硬件或软件事件。
4.3 状态转换触发条件详解
每个状态转换都由特定的硬件事件或软件操作触发。以下是所有转换路径的详细说明:
- Inactive → Pending:中断源产生有效信号(边沿跳变或电平断言)。GIC分发器记录该中断,将其标记为Pending。
- Pending → Active:CPU通过读取
GICC_IAR(Interrupt Acknowledge Register)来响应中断。GIC将最高优先级的中断分发给该CPU,状态变为Active。 - Active → Inactive:ISR执行完毕后,CPU向
GICC_EOIR(End of Interrupt Register)写入中断ID。GIC确认处理完成,状态回归Inactive。 - Active → Active and Pending:在ISR执行期间,同一中断源再次触发(电平保持有效或新边沿到达)。GIC保留新的Pending请求。
- Active and Pending → Active:ISR写EOIR结束当前中断,GIC发现仍有Pending请求,立即将新中断分发给CPU,状态回到Active。
- Active and Pending → Pending:ISR写EOIR结束当前中断,但GIC决定暂不分发(例如优先级被屏蔽或目标PE不同),状态退回到Pending。
- Pending → Inactive(特殊):仅适用于电平触发中断。如果外部电平在CPU读取IAR之前已经去断言,GIC可能清除Pending状态。
驱动开发陷阱: 在ISR中必须严格配对读取GICC_IAR和写入GICC_EOIR。如果忘记写EOIR,中断将永远卡在Active状态,导致该中断源无法再次触发,系统表现为“中断丢失”。对于共享中断(如SPI),写EOIR前务必确认中断源是否确实由本设备产生。
4.4 边沿触发 vs 电平触发的状态行为差异
| 特性 | 边沿触发 (Edge-triggered) | 电平触发 (Level-sensitive) |
|---|---|---|
| Pending保持条件 | GIC内部锁存边沿事件,即使信号恢复也保持Pending | 必须依赖外部信号持续有效;信号去断言后Pending自动清除 |
| Active and Pending | 新边沿到达时进入,ISR写EOIR后自动重新分发 | 只要外部电平保持有效,ISR写EOIR后立即再次进入Pending |
| 丢失风险 | 极低,GIC锁存每个边沿 | 较高,如果ISR执行期间电平短暂抖动可能丢失 |
| 软件处理要求 | ISR中通常需要清除外设的中断标志位 | ISR中必须操作外设使电平去断言,否则陷入无限中断 |
| 典型应用 | 按键、网络数据包到达、DMA完成 | GPIO输入、电源管理事件、错误信号 |
4.5 状态机在GIC寄存器层面的体现
GIC通过两组关键寄存器来跟踪每个中断的状态:
- GICD_ISPENDR / GICD_ICPENDR:Set/Clear Pending寄存器。软件可以主动设置或清除Pending状态,用于软件触发中断或取消中断。
- GICD_ISACTIVER / GICD_ICACTIVER:Set/Clear Active寄存器。允许软件直接操作Active状态,主要用于虚拟化场景或调试。
- GICC_IAR:读取此寄存器返回当前最高优先级的中断ID,同时将该中断状态从Pending变为Active。
- GICC_EOIR:写入此寄存器通知GIC中断处理完成,状态从Active变为Inactive(或从A&P变为Pending/Active)。
实战要点: 在Linux内核中,
handle_IRQ() 函数负责读取IAR,调用中断处理流控层(如handle_edge_irq或handle_level_irq),最后写EOIR。流控层会根据中断类型自动处理状态机转换,驱动开发者通常只需关注外设级别的操作。
4.6 状态机与中断优先级、抢占的关系
状态机与GIC的优先级机制紧密耦合:
- 当多个中断同时处于Pending状态时,GIC选择优先级最高的中断分发到CPU。
- 如果高优先级中断在低优先级ISR执行期间到达,GIC可以抢占当前Active中断,使低优先级中断退居后台,高优先级中断进入Active状态。
- 抢占发生时,低优先级中断的状态仍然是Active(未被EOIR),高优先级中断进入Active。此时GIC内部维护一个嵌套的Active栈。
- 写EOIR必须严格按照后进先出(LIFO)顺序,先结束高优先级中断,再结束低优先级中断。