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中断状态机的完整转换路径。箭头上的标注表示触发转换的硬件或软件事件。

GIC 中断状态机转换图 Inactive 空闲状态 Pending 等待处理 Active 正在处理 Active & Pending 中断触发 读GICC_IAR 写GICC_EOIR 新中断到达 写GICC_EOIR 写GICC_EOIR 电平去断言 说明: 实线箭头表示标准转换路径;虚线箭头表示电平触发中断的特殊情况。写GICC_EOIR是软件主动完成中断处理的标志。

4.3 状态转换触发条件详解

每个状态转换都由特定的硬件事件或软件操作触发。以下是所有转换路径的详细说明:

  1. Inactive → Pending:中断源产生有效信号(边沿跳变或电平断言)。GIC分发器记录该中断,将其标记为Pending。
  2. Pending → Active:CPU通过读取GICC_IAR(Interrupt Acknowledge Register)来响应中断。GIC将最高优先级的中断分发给该CPU,状态变为Active。
  3. Active → Inactive:ISR执行完毕后,CPU向GICC_EOIR(End of Interrupt Register)写入中断ID。GIC确认处理完成,状态回归Inactive。
  4. Active → Active and Pending:在ISR执行期间,同一中断源再次触发(电平保持有效或新边沿到达)。GIC保留新的Pending请求。
  5. Active and Pending → Active:ISR写EOIR结束当前中断,GIC发现仍有Pending请求,立即将新中断分发给CPU,状态回到Active。
  6. Active and Pending → Pending:ISR写EOIR结束当前中断,但GIC决定暂不分发(例如优先级被屏蔽或目标PE不同),状态退回到Pending。
  7. 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)顺序,先结束高优先级中断,再结束低优先级中断。
中断抢占场景下的状态机嵌套 t0 t1 t2 t3 低优先级中断 (Active) 高优先级中断 (Active) 低优先级ISR开始 高优先级抢占 高优先级ISR结束 低优先级ISR恢复 写EOIR顺序:先写高优先级中断ID,再写低优先级中断ID。GIC内部维护Active栈来支持嵌套。