2. 中断控制器(GIC/APIC)架构:GICv2/v3/v4演进、中断分发与路由机制
中断控制器是CPU与外围设备之间的中断管理中枢。在ARM体系中使用GIC(Generic Interrupt Controller),x86体系中使用APIC(Advanced Programmable Interrupt Controller)。本章聚焦GIC从v2到v4的架构演进,深入分析中断分发与路由的核心机制,为后续中断优先级配置与响应优化奠定硬件架构基础。
2.1 GIC架构概览与演进脉络
GIC负责接收、优先级排序、分发中断到目标PE(Processing Element)。其演进直接对应多核、虚拟化、大规模中断场景的需求。
| 特性 | GICv2 | GICv3 | GICv4 |
|---|---|---|---|
| CPU接口 | 内存映射寄存器(CPU Interface) | 系统寄存器(ICC_*_ELn) | 系统寄存器 + 虚拟LPI |
| 中断类型 | SGI/PPI/SPI | SGI/PPI/SPI/LPI | SGI/PPI/SPI/LPI + vLPI |
| 路由方式 | 固定CPU或寄存器配置 | 基于Affinity路由(Cluster/Core/Thread) | 基于vPE的直接注入 |
| 虚拟化支持 | List寄存器(有限) | 硬件LPI + ITS | 直接注入虚拟中断(Doorbell) |
| 中断数量 | 最多1020个SPI | 最多16K SPI + 海量LPI | 同GICv3 + vLPI扩展 |
| 多核扩展性 | 一般(共享Distributor瓶颈) | 优秀(Redistributor分散) | 优秀 + 虚拟化卸载 |
2.2 GICv2:经典架构与分发模型
GICv2由Distributor和CPU Interface两个逻辑单元组成。Distributor集中管理所有中断的优先级、使能、触发方式;CPU Interface负责向连接的CPU核发送中断信号。
GICv2中断分发流程
- 中断采样: Distributor检测到外设中断信号(边沿/电平)。
- 优先级仲裁: 比较当前所有待处理中断的优先级,选择最高优先级中断。
- 目标CPU选择: 根据SPI路由寄存器(ICDICFR/ICDIPTR)确定目标CPU。
- 转发至CPU Interface: Distributor将中断ID和优先级发送到目标CPU的CPU Interface。
- 优先级过滤: CPU Interface比较中断优先级与当前运行优先级(Running Priority),若高于则向CPU核断言IRQ。
- 中断确认: CPU读取ICC_IAR寄存器,获取中断ID,同时Distributor将该中断状态置为Active。
- EOI: 中断处理完成后,CPU写入ICC_EOIR,Distributor清除Active状态,允许新中断。
2.3 GICv3:架构革新与LPI引入
GICv3针对多核扩展和虚拟化进行了根本性重构。核心变化:Distributor拆分为Distributor(全局)和Redistributor(每CPU),CPU接口改为系统寄存器访问,引入LPI(Locality-specific Peripheral Interrupt)和ITS(Interrupt Translation Service)。
GICv3中断类型与路由
| 中断类型 | ID范围 | 路由方式 | 典型用途 |
|---|---|---|---|
| SGI (Software Generated Interrupt) | 0~15 | 写入ICC_SGI1R_EL1,指定Affinity | 核间通信(IPI) |
| PPI (Private Peripheral Interrupt) | 16~31 | 固定到所属CPU | 本地定时器、PMU |
| SPI (Shared Peripheral Interrupt) | 32~1019 | Distributor路由表(GICD_IROUTER) | 传统外设中断 |
| LPI (Locality-specific Peripheral Interrupt) | 8192~ | ITS翻译 + Redistributor本地表 | PCIe MSI/MSI-X、大规模虚拟化 |
2.4 GICv4:虚拟中断直接注入
GICv4在v3基础上增加了直接虚拟中断注入能力。核心新增:vLPI(虚拟LPI)、Doorbell机制、vPE(虚拟PE)表。GICv4允许硬件直接将虚拟中断注入Guest VM,无需VMM(Hypervisor)软件模拟。
GICv4 vs GICv3 虚拟化中断路径对比
| 阶段 | GICv3(软件模拟) | GICv4(硬件直接注入) |
|---|---|---|
| 中断到达 | 物理中断触发 → VM Exit到Hypervisor | ITS识别为vLPI → 直接写入Redistributor |
| 中断翻译 | Hypervisor查询虚拟设备表,注入vIRQ | 硬件ITS查询vPE表,生成vLPI |
| 中断注入 | Hypervisor写List寄存器,触发VM Entry | 硬件直接置位vCPU的vLPI pending状态 |
| VM Exit次数 | 每次中断至少1次VM Exit | 0次(vCPU运行时)或1次Doorbell(vCPU睡眠) |
| 延迟 | 数微秒(含VM Exit/Entry开销) | 亚微秒级(硬件直通) |
2.5 中断分发与路由机制深度解析
2.5.1 Affinity路由模型(GICv3+)
GICv3使用Affinity层级标识目标PE。每个PE由Affinity 0~3四层组成,对应Thread/Core/Cluster/SoC。路由寄存器(GICD_IROUTER)写入目标Affinity值,Distributor/ITS根据层级选择目标Redistributor。
/* Linux内核中Affinity路由配置示例 */
/* 将SPI 100路由到CPU 2(Affinity: 0x00000100) */
void route_spi_to_cpu(unsigned int spi, unsigned int cpu) {
u64 affinity = cpu_to_affinity(cpu); /* 转换CPU编号为Affinity值 */
/* GICv3: 写GICD_IROUTER寄存器 */
writeq_relaxed(affinity, gic_dist_base + GICD_IROUTER + spi * 8);
/* 确保写操作完成 */
dsb(sy);
}
/* 读取当前路由 */
u64 current_route = readq_relaxed(gic_dist_base + GICD_IROUTER + spi * 8);
pr_info("SPI %u 当前路由: Affinity 0x%llx\n", spi, current_route);
2.5.2 中断优先级仲裁与抢占
GIC支持8位优先级(实际实现可能只使用高5位或高4位)。数值越小,优先级越高。抢占规则:
- 当新中断优先级 < 当前CPU的运行优先级(Running Priority)时,触发中断抢占。
- 运行优先级在CPU响应中断时自动更新为当前中断的优先级。
- 通过ICC_PMR_EL1(Priority Mask Register)设置全局优先级阈值,低于该阈值的中断被屏蔽。
irq_set_priority()设置中断优先级。注意GICv3的优先级寄存器是8位,但实际有效位取决于实现。ARM建议使用arch/arm64/include/asm/arch_gicv3.h中的gic_write_pmr()操作PMR寄存器。
2.5.3 中断状态机
每个中断在GIC内部经历以下状态:
| 状态 | 描述 | 触发条件 |
|---|---|---|
| Inactive | 中断未触发或已处理完成 | 初始状态/EOI后 |
| Pending | 中断条件满足,等待CPU响应 | 外设触发/软件写Pending位 |
| Active | CPU已确认中断,正在处理 | CPU读IAR寄存器 |
| Active and Pending | 处理中又有新触发 | Active期间中断源再次有效 |