ARM GIC 架构概览:GIC v2/v3/v4 演进、Distributor 与 Redistributor、CPU Interface

通用中断控制器(Generic Interrupt Controller, GIC)是 ARM 架构中管理中断的核心硬件单元,负责接收外设、软件触发或处理器间的中断信号,经过优先级仲裁、分发和屏蔽后,将中断事件路由到指定的 CPU 核心。GIC 的版本演进直接反映了多核、虚拟化和大规模系统对中断处理能力的需求变化。

2.1 GIC 版本演进与核心差异

GIC 从 v1 发展到 v4,每一代都在中断数量、路由灵活性、虚拟化支持和消息传递机制上做了显著增强。下表总结了各版本的关键特性:

特性 GIC v2 GIC v3 GIC v4
中断线数量 最多 1020 个 SPI 最多 1024 个 SPI + 16 个 LPI 同 v3,LPI 扩展
CPU 接口 内存映射寄存器(GICC 基址) 系统寄存器(ICC_*_ELn) 同 v3
Redistributor 无(Distributor 直连 CPU) 每个 CPU 对应一个 Redistributor 同 v3,增加 vLPI 支持
虚拟化支持 基础虚拟中断(vgic v2) 增强虚拟中断(vgic v3) 直接注入虚拟中断(vLPI)
中断消息传递 仅通过内存映射写 支持 MSI(基于写请求) 支持直接消息传递(Doorbell)
典型应用 Cortex-A7/A15 多核 Cortex-A53/A72 服务器/移动 虚拟化密集场景(如 NFV)
实践提示: 在设备树中,GIC v2 使用 compatible = "arm,cortex-a15-gic",而 GIC v3 使用 compatible = "arm,gic-v3"。驱动代码中通过读取 GICD_TYPER 寄存器的位域可判断硬件版本。

2.2 GIC v2 架构:Distributor 与 CPU Interface

GIC v2 采用经典的两级结构:Distributor 和 CPU Interface。Distributor 集中管理所有中断的使能、优先级、触发方式和目标 CPU,而每个 CPU 核心拥有独立的 CPU Interface,负责向核心提交中断信号。

GIC v2 中断类型:
  • SGI(Software Generated Interrupt): 软件触发,用于核间通信,ID 0-15。
  • PPI(Private Peripheral Interrupt): 私有外设中断,每个 CPU 独享,ID 16-31。
  • SPI(Shared Peripheral Interrupt): 共享外设中断,可路由到任意 CPU,ID 32-1019。
GIC v2 架构:Distributor + CPU Interface Distributor (GICD) 中断使能/屏蔽寄存器 优先级仲裁 (8 级) 目标 CPU 路由 (SPI) 触发方式配置 (边沿/电平) 中断 ID 范围: 0-1019 CPU Interface 0 GICC 基址 IRQ/FIQ 输出 优先级掩码 CPU Interface 1 GICC 基址 IRQ/FIQ 输出 优先级掩码 外设 SPI SGI/PPI GIC v2 关键约束 • CPU Interface 数量固定(最多 8 个) • SPI 路由通过 GICD_ITARGETSR 寄存器配置 • 不支持 LPI(基于消息的中断)

2.3 GIC v3/v4 架构:Redistributor 的引入

GIC v3 对架构进行了重大重构,引入了 Redistributor 组件,每个 CPU 核心对应一个 Redistributor,负责管理该核心的 PPI、SGI 和 LPI(Locality-specific Peripheral Interrupt)。Distributor 不再直接与 CPU 接口交互,而是通过 Redistributor 进行间接通信。GIC v4 在此基础上增加了对虚拟中断的直接注入支持(vLPI)。

驱动开发注意: GIC v3 的 CPU Interface 不再使用内存映射寄存器(GICC 基址),而是通过系统寄存器(如 ICC_IAR0_EL1、ICC_EOIR0_EL1)访问。设备树中不再需要 reg 属性描述 GICC 区域,只需描述 Distributor 和 Redistributor 的基址。
GIC v3/v4 架构:Distributor + Redistributor + CPU Interface Distributor (GICD) SPI 使能/优先级/路由 LPI 配置表 (ITS 关联) 全局中断控制 中断 ID 0-1023 (SPI) Redistributor 0 PPI/SGI 管理 LPI 挂起表 CPU 0 私有中断 Redistributor 1 PPI/SGI 管理 LPI 挂起表 CPU 1 私有中断 CPU 0 核心 ICC_*_EL1 系统寄存器 CPU 1 核心 ICC_*_EL1 系统寄存器 ITS (Interrupt Translation Service) 设备表/中断翻译表/集合表 GIC v3/v4 关键改进 • Redistributor 分担 Distributor 负载,支持更多 CPU 核心(最多 256 个) • LPI 通过 ITS 实现基于消息的中断,适合 PCIe MSI/MSI-X

2.4 Distributor、Redistributor 与 CPU Interface 职责对比

下表从寄存器接口、中断类型管理和路由策略三个维度,对比 GIC v3 中三个核心模块的职责:

模块 寄存器前缀 管理的中断类型 路由策略 内存映射区域
Distributor GICD_ SPI(共享外设中断) 全局路由表(GICD_IROUTER) GICD 基址(设备树 reg 第一个区域)
Redistributor GICR_ PPI、SGI、LPI 每个 CPU 独立管理私有中断 GICR 基址(设备树 reg 第二个区域)
CPU Interface ICC_*_ELn 所有已使能中断的提交 系统寄存器直接访问,无内存映射 无(GIC v3 废弃 GICC 区域)

2.5 设备树中 GIC 节点的典型描述

以下代码展示 GIC v3 在设备树中的标准描述方式,注意 reg 属性包含 Distributor 和 Redistributor 两个地址范围:

gic: interrupt-controller@2f000000 {
    compatible = "arm,gic-v3";
    #interrupt-cells = <3>;
    #address-cells = <2>;
    #size-cells = <2>;
    interrupt-controller;
    reg = <0x0 0x2f000000 0x0 0x10000>,   /* GICD */
          <0x0 0x2f100000 0x0 0x200000>;   /* GICR */
    interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
};
字段说明:
  • #interrupt-cells = <3>:中断描述符包含中断类型(0=SPI, 1=PPI)、中断号、触发标志。
  • reg 第一个区域:Distributor 寄存器基址(0x2f000000,大小 64KB)。
  • reg 第二个区域:Redistributor 寄存器基址(0x2f100000,大小 2MB,按 CPU 核心数扩展)。
  • interrupts:GIC 自身维护中断(如维护中断)使用 PPI 9。

2.6 中断处理流程:从外设到 CPU

以 GIC v3 为例,一个 SPI 中断从外设触发到 CPU 核心处理的完整路径如下:

  1. 外设断言中断线:SPI 中断信号到达 Distributor 的输入引脚。
  2. Distributor 仲裁:读取 GICD_ISPENDR 确认挂起状态,根据 GICD_IPRIORITYR 进行优先级比较,选择最高优先级中断。
  3. 路由决策:查询 GICD_IROUTER 寄存器,确定目标 CPU 核心(支持亲和性路由)。
  4. Redistributor 接收:目标 CPU 对应的 Redistributor 接收中断,更新 GICR_ISPENDR 和 GICR_ISACTIVER。
  5. CPU Interface 提交:CPU 核心通过系统寄存器 ICC_IAR0_EL1 读取中断 ID,硬件自动将中断提交到异常向量表。
  6. 中断服务例程执行:Linux 内核的 GIC 驱动调用 handle_domain_irq() 进入中断处理流程。
  7. EOI 确认:中断处理完成后,写入 ICC_EOIR0_EL1 发送结束信号,Redistributor 清除挂起状态。
调试技巧: 在 Linux 内核中,可以通过 /proc/interrupts 查看每个 CPU 核心的中断分布,确认 GIC 路由是否按预期工作。如果中断全部集中在 CPU0,检查 GICD_IROUTER 寄存器配置或内核 irqbalance 服务状态。

2.7 本章小结