4. GIC(通用中断控制器)介绍:ARM GIC架构概述
通用中断控制器(Generic Interrupt Controller,GIC)是ARM架构中用于管理中断的核心硬件单元。在设备树中,GIC节点是中断控制器节点的典型代表,其属性配置直接决定了操作系统如何感知和处理外设中断。理解GIC的架构层次与变体差异,是正确编写中断控制器DTS节点的前提。
4.1 GIC架构层次
ARM GIC从v2到v4架构经历了多次演进,每一代都在中断数量、分发机制和虚拟化支持上有所增强。下表总结了主流GIC架构版本的核心差异:
| GIC版本 | 典型实现 | 最大中断数 | CPU接口 | 虚拟化支持 | 常见应用 |
|---|---|---|---|---|---|
| GICv2 | GIC-400 | 最多1020个SPI | 内存映射寄存器 | 基本虚拟中断 | Cortex-A7/A9/A15,嵌入式Linux |
| GICv3 | GIC-500 | 最多1024个SPI + 16个PPI | 系统寄存器(ICC_*) | 硬件虚拟化(LPI) | Cortex-A53/A72,服务器SoC |
| GICv4 | GIC-600 | 扩展LPI空间 | 系统寄存器 | 直接注入虚拟中断(vLPI) | 虚拟化密集场景,数据中心 |
4.2 GIC-400:GICv2的典型代表
GIC-400是ARM为Cortex-A系列处理器配套的GICv2实现,广泛用于移动SoC、工业控制板和入门级服务器。其内部结构分为两个主要逻辑单元:
- Distributor(分发器): 负责中断优先级管理、使能/屏蔽、触发方式配置(电平/边沿)以及中断目标CPU选择。
- CPU Interface(CPU接口): 每个CPU核心拥有独立的接口,负责向核心发送中断信号、应答中断(EOI)以及获取中断ID。
GIC-400支持三种中断类型:
| 中断类型 | ID范围 | 说明 |
|---|---|---|
| SGI(软件生成中断) | ID 0–15 | 用于核间通信,由软件写入寄存器触发 |
| PPI(私有外设中断) | ID 16–31 | 每个CPU私有,如本地定时器、PMU |
| SPI(共享外设中断) | ID 32–1019 | 所有CPU共享,由外设触发 |
gic: interrupt-controller@2c001000 {
compatible = "arm,cortex-a15-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x2c001000 0x1000>, /* Distributor基地址 */
<0x2c002000 0x2000>; /* CPU接口基地址 */
};
注意:#interrupt-cells = <3> 表示每个中断描述符占用3个cell,分别表示中断类型/ID、触发标志和优先级。
4.3 GIC-500:GICv3的演进
GIC-500是ARM面向64位服务器和高端嵌入式场景推出的GICv3实现。相比GIC-400,它在架构上做了重大调整:
- Redistributor(再分发器)引入: 每个CPU核心拥有独立的Redistributor单元,负责管理PPI和SGI,减轻Distributor的负担。
- 系统寄存器访问: CPU接口不再占用内存地址空间,而是通过ICC_*系统寄存器直接操作,降低了访问延迟。
- LPI(Locality-specific Peripheral Interrupt)支持: 基于消息的中断机制,适合PCIe MSI/MSI-X场景,中断数量可扩展至几乎无限。
GIC-500的设备树节点需要指定Distributor和Redistributor的基地址,且Redistributor区域大小与CPU核心数相关:
gic: interrupt-controller@2f000000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x2f000000 0x10000>, /* Distributor基地址 */
<0x2f100000 0x200000>; /* Redistributor基地址(覆盖所有CPU) */
interrupts = <1 9 4>; /* 维护中断(可选) */
};
GICv3的#interrupt-cells仍为3,但第三个cell的编码含义与GICv2不同,需参考ARM GICv3规范。
4.4 GIC-400与GIC-500关键对比
| 对比维度 | GIC-400(GICv2) | GIC-500(GICv3) |
|---|---|---|
| CPU接口访问方式 | 内存映射寄存器 | 系统寄存器(ICC_*) |
| 中断路由 | Distributor直接路由到CPU | Distributor → Redistributor → CPU |
| LPI支持 | 不支持 | 支持(基于ITS) |
| 虚拟化扩展 | 基本虚拟中断(GICv2m) | 硬件虚拟化(vPE、vLPI) |
| 设备树reg属性 | 2个区域(Distributor + CPU Interface) | 2个区域(Distributor + Redistributor) |
| 典型兼容字符串 | arm,cortex-a15-gic |
arm,gic-v3 |
每个Redistributor帧大小(通常0x20000)× CPU核心数。例如4核系统至少需要0x80000字节。
4.5 GIC架构内部数据流
下图展示了GIC-400与GIC-500在中断从外设到CPU核心的传递路径上的结构差异:
4.6 中断触发方式与编码
在设备树中,中断触发方式通过interrupts属性的第二个cell(对于GICv2/v3)或专用标志位描述。GIC-400和GIC-500均支持以下触发模式:
| 触发方式 | 编码值(GICv2) | 编码值(GICv3) | 说明 |
|---|---|---|---|
| 上升沿触发 | 0x01 | 0x01 | 边沿敏感,适合定时器、DMA完成 |
| 高电平触发 | 0x04 | 0x04 | 电平敏感,适合按键、外部唤醒 |
| 下降沿触发 | 0x02 | 0x02 | 较少使用,部分外设支持 |
| 低电平触发 | 0x08 | 0x08 | 电平敏感,低电平有效 |
/* GIC-400:SPI中断,ID=42,高电平触发 */
interrupts = <0 42 4>;
/* GIC-500:PPI中断,ID=14,上升沿触发 */
interrupts = <1 14 1>;
第一个cell:0=SPI,1=PPI;第二个cell:中断ID;第三个cell:触发标志。
4.7 选择GIC变体的工程考量
在实际SoC设计中,选择GIC-400还是GIC-500取决于以下因素:
- CPU架构: 32位Cortex-A系列通常搭配GIC-400;64位Cortex-A系列推荐GIC-500。
- 中断密度: 需要超过1020个SPI或大量MSI中断时,GIC-500的LPI机制更具优势。
- 虚拟化需求: 运行多个虚拟机(如KVM、Xen)时,GIC-500的硬件虚拟化支持能显著降低中断延迟。
- 软件兼容性: 现有Linux内核版本对GIC-400支持更成熟,GIC-500需要较新内核(4.0+)和ATF固件配合。
compatible = "arm,gic-v3", "arm,cortex-a15-gic";,内核驱动会按优先级匹配。但实际硬件必须与第一个兼容字符串对应,否则可能导致初始化失败。