ARM GIC 中断控制器基础:GICv2/v3 架构、中断类型与路由机制

在 ARM 生态系统中,通用中断控制器(Generic Interrupt Controller, GIC)是管理中断的核心硬件单元。无论是裸机程序还是 Linux 内核,中断的配置、分发与优先级仲裁都依赖 GIC。理解 GICv2 与 GICv3 的差异,以及 SPI、PPI、SGI 三种中断类型,是后续迁移到 RISC-V PLIC/CLINT 的基础。

学习提示:GICv2 是 ARM Cortex-A7/A9/A15 等处理器的标配;GICv3 从 ARMv8 开始引入,支持更多 PE(Processing Element)和更灵活的路由。RISC-V 的 PLIC 在概念上更接近 GICv2 的 SPI 管理,而 CLINT 则承担了 SGI 和 PPI 的部分功能。

2.1 GIC 架构概览:从 v2 到 v3 的演进

GIC 的核心职责是:接收来自外设或软件的中断请求,进行优先级仲裁,然后将中断分发给目标 CPU 接口。GICv2 和 GICv3 在逻辑上均分为两个主要组件:分发器(Distributor)和CPU 接口(CPU Interface)。

关键区别:GICv3 将 CPU 接口从内存映射寄存器改为系统寄存器(SysReg)访问,并引入 Redistributor 概念,使得每个 PE 拥有独立的配置空间,大幅提升了可扩展性。
GICv2 与 GICv3 架构对比 GICv2 架构 Distributor(分发器) 中断优先级、使能、路由配置 CPU Interface 0 内存映射 CPU Interface 1 内存映射 GICv3 架构 Distributor(分发器) 全局中断路由表(GICR) Redistributor 0 SysReg 访问 Redistributor 1 SysReg 访问 架构演进要点 1. GICv2:CPU Interface 通过内存映射寄存器访问,每个 CPU 核有独立的接口。 2. GICv3:引入 Redistributor,每个 PE 拥有私有配置空间,CPU 接口改为系统寄存器。 3. GICv3 支持 LPI(Locality-specific Peripheral Interrupt),通过 ITS(Interrupt Translation Service)实现消息中断。 4. 路由机制:GICv2 使用位图路由,GICv3 使用路由表(GICR)支持更灵活的 PE 选择。

2.2 中断类型:SPI、PPI、SGI

GIC 将中断源分为三种类型,每种类型在中断号分配、路由目标和触发方式上存在显著差异。理解这些差异是正确配置设备树中断属性的前提。

中断类型 全称 中断号范围 路由目标 典型用途
SGI Software Generated Interrupt ID0 – ID15(GICv2)
ID0 – ID15(GICv3)
任意 PE 或指定 PE 集合 核间通信(IPI)、CPU 自唤醒
PPI Private Peripheral Interrupt ID16 – ID31(GICv2)
ID16 – ID31(GICv3)
仅绑定到单个 PE 本地定时器、PMU、调试单元
SPI Shared Peripheral Interrupt ID32 – ID1019(GICv2)
ID32 – ID1019(GICv3)
任意 PE 或 PE 组 外设中断(UART、I2C、DMA、网络)
迁移注意:RISC-V 的 PLIC 只管理类似 SPI 的外设中断,且中断号从 1 开始(0 表示无中断)。SGI 和 PPI 在 RISC-V 中由 CLINT 管理,使用不同的寄存器接口。设备树中 interrupts 属性的编码方式完全不同。

2.3 中断号分配与路由机制

中断号是 GIC 识别中断源的唯一标识。在 GICv2 中,中断号直接映射到硬件中断线;GICv3 则通过 Interrupt ID 和 vINTID 实现更灵活的映射。路由机制决定了中断最终被哪个 CPU 核处理。

2.3.1 中断号分配规则

  • SGI(ID0-15):由软件通过 GICD_SGIR 寄存器(GICv2)或 ICC_SGI0R_EL1 系统寄存器(GICv3)触发。中断号本身编码了目标 PE 列表。
  • PPI(ID16-31):每个 PE 拥有独立的 PPI 实例。例如,CPU0 的 PPI 定时器中断和 CPU1 的 PPI 定时器中断使用相同的中断号,但物理上独立。
  • SPI(ID32+):全局共享,所有 PE 看到的是同一个中断源。外设中断通常映射到 SPI 范围。
GIC 中断号分配与路由 中断号分配与路由机制(GICv2 示例) SGI (ID0-15) PPI (ID16-31) SPI (ID32+) Distributor 优先级仲裁 使能/屏蔽 路由决策 中断号映射 CPU Interface 0 CPU0 CPU Interface 1 CPU1 CPU Interface 2 CPU2 路由规则 • SGI:软件指定目标 PE • PPI:固定路由到本地 PE • SPI:Distributor 根据 GICD_ITARGETSR 寄存器 路由到 1 个或多个 PE • GICv3 使用 GICR 路由表

2.3.2 路由机制详解

GICv2 的路由通过 GICD_ITARGETSRn 寄存器实现,每个 SPI 中断对应一个 8 位寄存器,每位代表一个 CPU 接口(最多 8 个 PE)。GICv3 则使用 GICR 路由表,支持更精细的 PE 选择,包括通过 Affinity 层级(Aff0、Aff1、Aff2、Aff3)定位到具体的 PE。

设备树中的中断路由:在 ARM 设备树中,interrupts 属性通常包含 <中断类型 中断号 触发方式> 三元组。例如 interrupts = <0 33 4> 表示 SPI(类型 0)、中断号 33、高电平触发(4)。GIC 的 interrupt-parent 属性指向 GIC 节点,由 GIC 驱动解析这些信息并配置路由。

2.4 GICv2 与 GICv3 关键差异总结

特性 GICv2 GICv3
CPU 接口访问方式 内存映射寄存器(GICC_*) 系统寄存器(ICC_*_ELn)
PE 数量支持 最多 8 个 PE 最多 256 个 PE(通过 Affinity 扩展)
中断路由粒度 位图路由(8 位) 路由表 + Affinity 层级
LPI 支持 不支持 支持(通过 ITS)
虚拟化支持 基本虚拟化扩展(GICv2m) 原生虚拟化(GICv3+)
设备树兼容字符串 arm,gic-400 arm,gic-v3
迁移到 RISC-V 的桥梁:RISC-V 的 PLIC 在设备树中通常使用 riscv,plic0 兼容字符串,中断号从 1 开始连续编号,没有 SPI/PPI/SGI 的区分。但理解 ARM GIC 的中断类型有助于在移植时正确映射:外设中断对应 PLIC 的中断源,核间中断对应 CLINT 的 MSIP(Machine Software Interrupt),定时器中断对应 CLINT 的 MTIMER。

2.5 实践:在设备树中描述 GIC 中断

以下是一个典型的 ARM 设备树片段,展示了如何描述 GIC 中断控制器以及外设如何引用中断:

// GICv2 中断控制器节点
gic: interrupt-controller@f1000000 {
    compatible = "arm,gic-400";
    reg = <0x0 0xf1000000 0x0 0x10000>,  // GICD 基地址
          <0x0 0xf2000000 0x0 0x20000>;  // GICC 基地址
    interrupt-controller;
    #interrupt-cells = <3>;  // 3 个 cell:中断类型、中断号、触发方式
};

// 外设节点:UART0 使用 SPI 中断
uart0: serial@f0000000 {
    compatible = "arm,pl011";
    reg = <0x0 0xf0000000 0x0 0x1000>;
    interrupts = <0 33 4>;  // 类型 0=SPI, 中断号 33, 触发方式 4=高电平
    interrupt-parent = <&gic>;
};

在 GICv3 中,设备树描述略有不同,需要增加 redistributor 区域:

// GICv3 中断控制器节点
gic: interrupt-controller@f1000000 {
    compatible = "arm,gic-v3";
    reg = <0x0 0xf1000000 0x0 0x10000>,  // GICD
          <0x0 0xf3000000 0x0 0x100000>; // Redistributor 区域
    interrupt-controller;
    #interrupt-cells = <3>;
    #address-cells = <2>;
    #size-cells = <2>;
    ranges;
};
常见错误:在移植到 RISC-V 时,开发者常错误地将 ARM 的 #interrupt-cells = <3> 直接套用到 PLIC 节点。RISC-V PLIC 通常使用 #interrupt-cells = <1>,只传递中断号,触发方式由外设自身或 SoC 固定配置。务必检查目标平台的设备树绑定文档。

通过本章的学习,你应该能够:

  • 区分 GICv2 和 GICv3 的架构差异及适用场景。
  • 识别 SPI、PPI、SGI 三种中断类型及其在中断号分配上的规律。
  • 理解 GIC 的路由机制,包括位图路由和 Affinity 路由。
  • 在设备树中正确描述 GIC 中断控制器和外设中断引用。