4. GICv3 系统架构:核心组件的职责划分
GICv3 架构相比 GICv2 最大的变化在于引入了 Redistributor 和 ITS(Interrupt Translation Service),并将 CPU Interface 从外部独立单元移入处理器核心内部。整个中断系统由四个核心组件构成:Distributor、Redistributor、ITS 和 CPU Interface。理解每个组件的职责边界,是驱动开发和系统调试的基础。
4.1 组件全景与数据流
下图展示了 GICv3 中四个核心组件之间的连接关系以及中断请求的宏观流动路径。SPI 由 Distributor 分发,PPI/SGI 由 Redistributor 本地处理,LPI 则经过 ITS 翻译后路由到目标 Redistributor。
4.2 Distributor(分发器)职责
Distributor 是 GICv3 中负责全局中断资源管理的组件,通常作为内存映射外设存在于系统总线上。它主要处理 SPI(共享外设中断) 的配置与分发。
| 功能模块 | 职责描述 | 关键寄存器/操作 |
|---|---|---|
| 中断使能/禁用 | 全局控制 SPI 的使能状态,支持按中断号单独控制 | GICD_ISENABLERn / GICD_ICENABLERn |
| 优先级管理 | 为每个 SPI 分配 8 位优先级值,决定抢占行为 | GICD_IPRIORITYRn |
| 目标路由 | 将 SPI 路由到指定的 Redistributor(即目标 CPU 核心) | GICD_IROUTERn(支持亲和性路由) |
| 触发方式配置 | 配置 SPI 为电平触发或边沿触发 | GICD_ICFGRn |
| 中断分组 | 将中断分为 Group 0(安全)或 Group 1(非安全) | GICD_IGROUPn / GICD_IGRPMODRn |
0x2F000000 附近。驱动初始化时首先需要映射 Distributor 的 MMIO 区域,并读取 GICD_TYPER 寄存器获取支持的中断线数量。
4.3 Redistributor(再分发器)职责
Redistributor 是 GICv3 引入的关键组件,每个 CPU 核心拥有一个专属的 Redistributor。它负责管理该核心私有的中断类型:PPI(私有外设中断)、SGI(软件生成中断) 以及来自 ITS 的 LPI(本地特定外设中断)。
Redistributor 的核心价值在于将中断状态机从全局 Distributor 中解耦,每个核心独立维护自己的中断挂起、激活和优先级状态,避免了多核同时访问 Distributor 带来的锁竞争。
| 中断类型 | 中断号范围 | 管理组件 | 特点 |
|---|---|---|---|
| PPI | 16-31 | Redistributor | 每个核心私有,如 per-CPU 定时器 |
| SGI | 0-15 | Redistributor | 软件触发,用于核间通信(IPI) |
| LPI | 8192 起 | Redistributor + ITS | 通过 ITS 翻译后路由,支持大量中断源 |
Redistributor 的寄存器空间分为两个区域:RD_base(控制寄存器)和 SGI_base(SGI 相关寄存器)。驱动初始化时需要为每个 CPU 核心找到其对应的 Redistributor 基地址,这通常通过解析 GICR_TYPER 中的 Affinity 字段完成。
/* 伪代码:遍历 Redistributor 区域,匹配当前 CPU 核心 */
void gicv3_redist_init(void) {
uint64_t redist_base = gicr_base_from_dtb();
uint32_t cpu_aff = read_cpu_mpidr() & 0xFF; // 获取当前核心 ID
while (1) {
uint64_t typer = readl(redist_base + GICR_TYPER);
if ((typer >> 8) & 0xFF == cpu_aff) {
// 找到当前核心对应的 Redistributor
gic_data->redist_base[cpu_id] = redist_base;
break;
}
// 跳转到下一个 Redistributor 帧
redist_base += SZ_64K; // Redistributor 帧大小
}
}
4.4 ITS(中断翻译服务)职责
ITS 是 GICv3 中支持 LPI(本地特定外设中断) 的核心引擎。它本质上是一个 中断路由表查询引擎,负责将设备发送的 EventID(设备侧中断标识)翻译为 GIC 内部的 INTID(中断号)和目标 CPU 核心。
ITS 的工作流程可以概括为三个步骤:
- 设备表查询: 根据设备发送的 DeviceID 查找该设备对应的中断翻译表基地址。
- 中断翻译: 使用 EventID 在翻译表中查找对应的 INTID 和 目标 Redistributor。
- 中断注入: 将翻译后的中断信息写入目标 Redistributor 的 LPI 挂起表,触发中断。
ITS_BASER 寄存器配置基地址。表项格式必须严格遵循 GICv3 规范,错误的表项配置会导致 LPI 中断丢失或路由到错误的 CPU 核心。
4.5 CPU Interface(CPU 接口)职责
在 GICv3 中,CPU Interface 被集成到处理器核心内部,不再作为独立的外设存在。它通过 系统寄存器(System Registers) 而非内存映射寄存器与操作系统交互,这显著降低了中断处理的延迟。
CPU Interface 的核心职责包括:
- 中断优先级屏蔽: 通过
ICC_PMR_EL1设置当前 CPU 的优先级阈值,低于该阈值的中断被屏蔽。 - 中断确认(IAR): 读取
ICC_IAR0_EL1(Group 0)或ICC_IAR1_EL1(Group 1)获取当前最高优先级中断的中断号。 - 中断结束(EOI): 写入
ICC_EOIR0_EL1或ICC_EOIR1_EL1通知 GIC 中断处理完成。 - 中断抢占控制: 管理中断嵌套和抢占逻辑,确保高优先级中断可以抢占低优先级中断处理。
- 运行优先级管理: 通过
ICC_RPR_EL1读取当前 CPU 的运行优先级。
| 系统寄存器 | 访问类型 | 功能描述 |
|---|---|---|
ICC_PMR_EL1 |
读/写 | 优先级屏蔽寄存器,设置中断阈值 |
ICC_IAR1_EL1 |
读 | 中断确认寄存器,返回 Group 1 中断号 |
ICC_EOIR1_EL1 |
写 | 中断结束寄存器,标记 Group 1 中断完成 |
ICC_BPR1_EL1 |
读/写 | 二进制点寄存器,控制优先级分组 |
ICC_CTLR_EL1 |
读/写 | 控制寄存器,使能/禁用 CPU Interface |
/* Linux 内核 GICv3 驱动中 CPU Interface 中断处理入口示例 */
static asmlinkage void __exception_irq_entry gicv3_handle_irq(struct pt_regs *regs) {
u32 irqnr;
/* 1. 读取 IAR 确认中断 */
irqnr = gic_read_iar();
/* 2. 处理中断 */
if (likely(irqnr & ICC_IAR1_EL1_INTID_MASK)) {
handle_domain_irq(gic_data.domain, irqnr, regs);
}
/* 3. 写入 EOI 结束中断 */
gic_write_eoir(irqnr);
}
4.6 组件职责对比总结
下表从多个维度对比四个组件的职责边界,帮助驱动开发者在调试时快速定位问题组件。
| 对比维度 | Distributor | Redistributor | ITS | CPU Interface |
|---|---|---|---|---|
| 管理的中断类型 | SPI | PPI、SGI、LPI | LPI(翻译服务) | 所有已使能中断 |
| 寄存器访问方式 | MMIO | MMIO | MMIO | 系统寄存器 |
| 每核心实例数 | 1(全局) | 每个核心 1 个 | 1(可选) | 每个核心 1 个 |
| 主要功能 | SPI 路由与配置 | 本地中断状态机 | EventID → INTID 翻译 | 中断确认与结束 |
| 中断优先级控制 | 设置 SPI 优先级 | 设置 PPI/SGI 优先级 | 不直接参与 | 优先级屏蔽与抢占 |