2. GIC(Generic Interrupt Controller)简介

通用中断控制器(GIC)是 ARM 架构中用于管理中断的核心硬件单元。它负责接收来自外设、软件和处理器内部的中断请求,进行优先级仲裁、分发和路由,最终将中断信号传递给对应的 CPU 核心。在 Linux 内核启动流程中,GIC 的初始化是中断子系统建立的基础,直接影响系统的实时性和响应能力。

2.1 GIC 的版本演进(GICv1/v2/v3/v4)

ARM GIC 经历了多个版本的迭代,每个版本在中断数量、分发机制、虚拟化支持和安全扩展方面都有显著提升。下表总结了各版本的核心差异:

特性 GICv1 GICv2 GICv3 GICv4
中断线数量 最多 1020 个 SPI 最多 1020 个 SPI 最多 1020 个 SPI + 扩展 SPI 同 GICv3
CPU 接口 内存映射寄存器 内存映射寄存器 系统寄存器(ICC_*) 同 GICv3
亲和性路由 不支持 不支持 支持(Affinity Routing) 同 GICv3
虚拟化支持 无 基本虚拟化(vGIC) 增强虚拟化(LPI 支持) 直接注入虚拟中断(Direct Injection)
LPI(Locality-specific Peripheral Interrupt) 不支持 不支持 支持 支持
典型应用 Cortex-A9 等早期多核 Cortex-A15/A7 大小核 Cortex-A53/A72 及服务器 虚拟化场景(如 KVM)
版本选择提示: 在嵌入式 Linux 开发中,GICv2 和 GICv3 最为常见。GICv2 适用于传统多核 SoC,而 GICv3 在 64 位 ARMv8 平台上已成为标准配置,其系统寄存器接口减少了内存映射访问的开销。

下图展示了 GIC 版本演进的关键里程碑和主要新增特性:

GIC 版本演进时间线 GICv1 基础中断控制 最多 1020 SPI 内存映射接口 GICv2 + 虚拟化支持 + 大小核亲和 内存映射接口 GICv3 + 系统寄存器接口 + LPI 支持 + 亲和性路由 GICv4 + 直接注入 虚拟中断 说明: GICv3 是当前 ARMv8 平台的主流选择,其系统寄存器接口(ICC_*)减少了内存映射访问延迟。 GICv4 主要面向虚拟化场景,支持直接注入虚拟中断到 Guest OS,减少 VM-Exit 开销。

2.2 GIC 在 ARM 架构中的地位

GIC 是 ARM 架构中中断子系统的核心组件,位于外设和 CPU 核心之间。它承担着中断信号的汇聚、优先级排序和分发任务。在 ARM 多核系统中,GIC 的地位可以概括为以下几点:

  • 中断汇聚中心: 所有外设中断(SPI、PPI、SGI)和软件触发中断都通过 GIC 进行统一管理。
  • 优先级仲裁器: GIC 根据配置的优先级字段,决定哪个中断优先被处理,支持抢占和嵌套。
  • 分发与路由: 在 GICv3 及以上版本中,支持将中断路由到指定的 CPU 核心或核心组(Cluster)。
  • 虚拟化桥接: 在虚拟化环境中,GIC 负责将物理中断转换为虚拟中断,并注入到 Guest OS。

下图展示了 GIC 在 ARM 系统架构中的位置和连接关系:

GIC 在 ARM 系统架构中的位置 外设层(Peripherals) UART | I2C | SPI | GPIO | Timer | DMA | Ethernet GIC(Generic Interrupt Controller) 中断汇聚 | 优先级仲裁 | 分发路由 | 虚拟化桥接 Distributor Redistributor CPU Interface CPU 核心(Core 0 | Core 1 | Core 2 | Core 3)

2.3 GIC 与 CPU 接口的关系

GIC 与 CPU 之间的接口是中断传递的关键通道。不同版本的 GIC 采用了不同的接口方式,直接影响中断延迟和软件访问方式。

2.3.1 接口类型对比

接口类型 GIC 版本 访问方式 典型寄存器 延迟特点
内存映射接口 GICv1 / GICv2 通过 CPU 内存总线访问 GICC_*(CPU Interface) 较高,依赖总线仲裁
系统寄存器接口 GICv3 / GICv4 通过 MSR/MRS 指令访问 ICC_*(系统寄存器) 较低,直接访问

2.3.2 中断信号传递流程

当外设产生中断时,信号经过以下路径到达 CPU:

  1. 外设触发: 外设将中断信号发送到 GIC 的 Distributor 单元。
  2. 优先级仲裁: Distributor 根据中断优先级和当前运行状态,选择最高优先级的中断。
  3. 路由决策: 根据亲和性配置(GICv3+),将中断路由到目标 Redistributor。
  4. CPU 接口通知: Redistributor 通过 CPU 接口(内存映射或系统寄存器)向目标 CPU 发送 IRQ 或 FIQ 信号。
  5. CPU 响应: CPU 在异常向量表中跳转到中断处理程序,读取 GICC_IAR(GICv2)或 ICC_IAR0_EL1(GICv3)获取中断 ID。
关键区别: 在 GICv2 中,CPU 通过读取内存映射寄存器 GICC_IAR 获取中断 ID;而在 GICv3 中,CPU 通过系统寄存器 ICC_IAR0_EL1 或 ICC_IAR1_EL1 读取,无需经过内存总线,延迟更低。

下图展示了 GICv2 和 GICv3 在 CPU 接口访问路径上的差异:

GICv2 vs GICv3 CPU 接口访问路径 GICv2 路径 CPU → 内存总线 → GICC 寄存器 延迟:~50-100ns(总线仲裁) GICv3 路径 CPU → 系统寄存器(ICC_*) 延迟:~10-20ns(直接访问) 性能影响: GICv3 的系统寄存器接口减少了中断响应路径中的内存总线访问,降低了中断延迟。 在 Linux 内核中,GICv3 驱动使用 read_sysreg() 和 write_sysreg() 宏直接操作 ICC_* 寄存器。

2.3.3 中断类型与 CPU 接口的对应关系

GIC 支持多种中断类型,每种类型与 CPU 接口的交互方式略有不同:

  • SGI(Software Generated Interrupt): 由软件通过写入 GICD_SGIR(GICv2)或 ICC_SGI0R_EL1(GICv3)触发,用于核间通信(IPI)。
  • PPI(Private Peripheral Interrupt): 每个 CPU 核心私有的外设中断,如本地定时器,通过 Redistributor 直接路由到对应核心。
  • SPI(Shared Peripheral Interrupt): 共享外设中断,由 Distributor 根据配置路由到指定核心或核心组。
  • LPI(Locality-specific Peripheral Interrupt): GICv3 引入,基于消息的中断,通过 ITS(Interrupt Translation Service)进行路由,适合大量外设场景。
注意事项: 在 GICv3 中,LPI 中断不支持通过内存映射寄存器直接访问,必须通过 ITS 和系统寄存器配合使用。Linux 内核中,LPI 的配置涉及 its_alloc_tables() 和 its_alloc_collections() 等复杂流程。