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分散) 优秀 + 虚拟化卸载
架构选择提示: 在嵌入式Linux 5.x+内核中,GICv3已成为主流默认配置。GICv2主要用于Cortex-A7/A15等老平台;GICv4主要面向需要高性能虚拟化IO的场景(如NFV、边缘计算)。

2.2 GICv2:经典架构与分发模型

GICv2由Distributor和CPU Interface两个逻辑单元组成。Distributor集中管理所有中断的优先级、使能、触发方式;CPU Interface负责向连接的CPU核发送中断信号。

GICv2 架构框图 Distributor 中断优先级寄存器 中断使能/屏蔽 触发方式配置 中断状态机 路由表(SPI目标CPU) CPU Interface 0 优先级掩码 中断确认 EOI寄存器 运行优先级 CPU Interface 1 优先级掩码 中断确认 EOI寄存器 运行优先级 CPU 0 IRQ/FIQ CPU 1 IRQ/FIQ 外设中断源 SPI #32 ~ PPI (每CPU私有) 说明:GICv2中Distributor为全局共享,所有CPU Interface通过内存映射访问,多核竞争时存在总线瓶颈。

GICv2中断分发流程

  1. 中断采样: Distributor检测到外设中断信号(边沿/电平)。
  2. 优先级仲裁: 比较当前所有待处理中断的优先级,选择最高优先级中断。
  3. 目标CPU选择: 根据SPI路由寄存器(ICDICFR/ICDIPTR)确定目标CPU。
  4. 转发至CPU Interface: Distributor将中断ID和优先级发送到目标CPU的CPU Interface。
  5. 优先级过滤: CPU Interface比较中断优先级与当前运行优先级(Running Priority),若高于则向CPU核断言IRQ。
  6. 中断确认: CPU读取ICC_IAR寄存器,获取中断ID,同时Distributor将该中断状态置为Active。
  7. EOI: 中断处理完成后,CPU写入ICC_EOIR,Distributor清除Active状态,允许新中断。
GICv2瓶颈: 所有CPU Interface寄存器通过内存映射访问,Distributor为单点。在高中断率场景(如万兆网卡),Distributor总线带宽成为瓶颈,导致中断延迟抖动增大。

2.3 GICv3:架构革新与LPI引入

GICv3针对多核扩展和虚拟化进行了根本性重构。核心变化:Distributor拆分为Distributor(全局)和Redistributor(每CPU),CPU接口改为系统寄存器访问,引入LPI(Locality-specific Peripheral Interrupt)和ITS(Interrupt Translation Service)。

GICv3 架构框图 Distributor SPI配置/使能 全局优先级 SGI/PPI路由 安全扩展 GICD_* 寄存器 Redistributor 0 LPI配置表 PPI/SGI管理 唤醒/睡眠 GICR_* 寄存器 Redistributor 1 LPI配置表 PPI/SGI管理 唤醒/睡眠 GICR_* 寄存器 ITS 中断翻译服务 Device Table Interrupt Collection LPI路由重映射 CPU 0 ICC_*_EL1 CPU 1 ICC_*_EL1 外设/MSI设备 LPI中断 PCIe MSI/MSI-X MSI写事务 关键变化:CPU接口从内存映射改为系统寄存器(ICC_*_EL1),中断确认/EOI通过MSR/MRS指令完成,避免内存映射延迟。 Redistributor每CPU独立,LPI配置表本地缓存,大幅降低多核竞争。

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、大规模虚拟化
LPI核心优势: LPI采用内存写(Write)方式触发,而非传统中断线的电平/边沿。ITS将设备ID+EventID翻译为中断ID和目标CPU,支持数百万中断源,且路由表可动态重映射,非常适合虚拟化场景。

2.4 GICv4:虚拟中断直接注入

GICv4在v3基础上增加了直接虚拟中断注入能力。核心新增:vLPI(虚拟LPI)、Doorbell机制、vPE(虚拟PE)表。GICv4允许硬件直接将虚拟中断注入Guest VM,无需VMM(Hypervisor)软件模拟。

GICv4 虚拟中断直接注入流程 物理设备 PCIe网卡 MSI中断 ITS 翻译映射 vPE表查询 Redistributor vLPI配置 Doorbell检测 Hypervisor (VMM) vGIC模拟(仅初始化) Guest VM vCPU运行 直接处理vLPI 直接注入(无VM Exit) 仅初始化配置 GICv4核心价值:物理中断到达时,ITS直接查询vPE表,将vLPI写入目标vCPU的Redistributor, 无需Hypervisor介入。Doorbell机制在vCPU未运行时通过物理中断唤醒,实现零软件开销的虚拟中断交付。

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)设置全局优先级阈值,低于该阈值的中断被屏蔽。
优先级配置实战建议: 在Linux内核中,通过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期间中断源再次有效
GIC中断状态机 Inactive Pending Active Active & Pending 中断触发 读IAR 新触发 ← 上一章 📖 返回目录 下一章 →