3. GIC 架构概述:GICv2/v3/v4 演进历史、GIC在SoC中的位置、中断类型(SPI/PPI/SGI/LPI)
3.1 GIC 演进历史:从 v2 到 v4
通用中断控制器(Generic Interrupt Controller, GIC)是 ARM 架构中标准化的中断管理单元。随着多核处理器、虚拟化技术及高密度服务器场景的需求演进,GIC 经历了四个主要版本的迭代。下表总结了各版本的核心差异与关键特性:
| 特性 | GICv2 | GICv3 | GICv4 / v4.1 |
|---|---|---|---|
| CPU 接口 | 专用引脚(nIRQ/nFIQ) | 内存映射寄存器(System Register 接口) | 同 GICv3,增加虚拟化扩展 |
| 亲和性路由 | 仅支持 8 个 PE(CPU 接口) | 支持最多 2^16 个 PE,通过 Affinity 路由 | 同 GICv3 |
| 虚拟化支持 | 基本虚拟中断(vgic) | 硬件加速虚拟中断(List Registers) | 直接注入虚拟中断(vLPI) |
| LPI 支持 | 不支持 | 支持(通过 ITS) | 支持,并优化虚拟 LPI |
| 中断号范围 | ID0~ID1019(SPI 最多 988 个) | ID0~ID1023 + LPI(16-bit 空间) | 同 GICv3 |
| 典型应用 | Cortex-A9/A15 多核 SoC | Cortex-A53/A72/A76 服务器/移动 SoC | 虚拟化场景(KVM、Xen) |
关键演进驱动力: 多核扩展性(从 8 核到数千核)、虚拟化硬件卸载(减少 Hypervisor 干预)、以及高吞吐设备(NVMe/GPU)对大量中断的需求(LPI)。
3.2 GIC 在 SoC 中的位置
GIC 位于处理器核心(PE)与外设/软件之间,是中断信号的汇聚与分发中心。下图展示了 GICv3 在典型 ARM SoC 中的系统级位置:
架构要点: GICv3 将每个 PE 的 CPU 接口替换为 Redistributor,通过内存映射寄存器直接与 PE 通信,消除了 GICv2 的物理引脚限制,使得支持数百甚至数千个 PE 成为可能。
3.3 中断类型详解:SPI / PPI / SGI / LPI
GIC 将中断源划分为四种类型,每种类型在触发方式、路由目标和配置粒度上各有不同。理解这些类型是编写正确中断处理程序的基础。
3.3.1 共享外设中断 (SPI)
- 中断号范围: GICv2: ID32~ID1019; GICv3: ID32~ID1023
- 触发方式: 电平触发 (Level-sensitive) 或边沿触发 (Edge-triggered),可编程配置
- 路由目标: 可路由到任意一个或多个 PE(通过 Distributor 配置)
- 典型用途: UART、I2C、SPI、GPIO、DMA 等 SoC 内部外设
- 关键特性: 多个 PE 可以共享同一个 SPI 中断源,但通常只由一个 PE 处理
3.3.2 私有外设中断 (PPI)
- 中断号范围: ID16~ID31
- 触发方式: 电平触发或边沿触发,可编程配置
- 路由目标: 固定路由到特定的单个 PE,不可跨 PE 路由
- 典型用途: 每个 PE 私有的 Timer、PMU (Performance Monitor Unit)、CTI (Cross Trigger Interface)
- 关键特性: 每个 PE 都有自己独立的 PPI 实例,配置寄存器也独立
3.3.3 软件生成中断 (SGI)
- 中断号范围: ID0~ID15
- 触发方式: 仅边沿触发 (由软件写入 GICD_SGIR/ICC_SGI1R 寄存器触发)
- 路由目标: 可定向到指定 PE 或 PE 组,支持广播和定向发送
- 典型用途: 核间通信 (IPI)、操作系统调度、TLB 刷新、CPU 热插拔
- 关键特性: 发送方可指定目标 PE 的亲和性 (Affinity),GICv3 支持 16 个 SGI 通道
3.3.4 本地特定外设中断 (LPI)
- 中断号范围: 8192~ (16-bit 空间,最多 65536 个)
- 触发方式: 仅电平触发 (消息中断,基于写操作)
- 路由目标: 通过 ITS (Interrupt Translation Service) 进行转译和路由
- 典型用途: PCIe MSI/MSI-X、NVMe、高速网络控制器、GPU
- 关键特性: 支持中断数量巨大、可动态配置、支持虚拟化直接注入 (vLPI)
开发注意事项: LPI 中断不经过 Distributor 的优先级/使能寄存器,而是通过 ITS 和 Redistributor 的 LPI 配置表 (LPI Configuration Table) 管理。驱动开发时,LPI 的使能/禁用在 ITS 侧完成,而非传统的 GICD 寄存器。
3.4 中断类型对比总结
| 属性 | SPI | PPI | SGI | LPI |
|---|---|---|---|---|
| ID 范围 | 32~1019/1023 | 16~31 | 0~15 | 8192~65535 |
| 触发方式 | 电平/边沿 | 电平/边沿 | 边沿 (软件触发) | 电平 (消息) |
| 路由粒度 | 任意 PE | 固定 PE | 指定 PE/组 | 通过 ITS 转译 |
| 配置方式 | Distributor 寄存器 | Redistributor 寄存器 | 软件写 SGI 寄存器 | ITS 命令 + 内存表 |
| 数量 | ~988 个 | 16 个/PE | 16 个 | ~57344 个 |
| 虚拟化支持 | 基本 (LRS) | 基本 (LRS) | 基本 (LRS) | vLPI 直接注入 |
| 典型延迟 | 中等 | 低 | 极低 | 低 (硬件加速) |
3.5 中断处理流程概览 (GICv3 视角)
一个典型的中断从外设产生到 CPU 处理,经过以下关键阶段:
- 中断产生: 外设 (如 UART) 拉高中断请求线 (SPI),或通过 PCIe 写消息产生 LPI。
- Distributor 仲裁: GICD 根据优先级、使能位和路由配置,选择最高优先级的中断,发送给目标 Redistributor。
- Redistributor 转发: Redistributor 接收中断,检查该 PE 的优先级掩码,若中断优先级高于当前 PE 的优先级掩码,则向 PE 发送 IRQ 信号。
- PE 响应: PE 进入中断模式,读取
ICC_IAR0_EL1(或ICC_IAR1_EL1) 寄存器获取中断 ID,硬件自动清除该中断的 pending 状态 (对于边沿触发)。 - 中断处理: 执行中断服务例程 (ISR),完成必要的设备操作。
- 中断结束: 写入
ICC_EOIR0_EL1(或ICC_EOIR1_EL1) 寄存器,通知 GIC 中断处理完成,允许下一个中断被递送。
驱动开发关键点: 在 Linux 内核中,GIC 驱动 (drivers/irqchip/irq-gic-v3.c) 负责初始化 Distributor 和 Redistributor,注册中断域 (irq_domain),并为每个中断类型提供正确的映射和回调函数。理解上述流程有助于调试中断丢失、优先级反转或虚拟化中断注入失败等问题。