2. 中断控制器硬件:GIC v3/v4 架构概述、中断分发与路由、中断触发方式

在 ARM 多核系统中,通用中断控制器(Generic Interrupt Controller, GIC) 是连接外设中断源与 CPU 核心的硬件中枢。GIC v3/v4 是当前主流 ARMv8-A 和 ARMv9-A 平台的标准中断控制器,其设计直接影响中断延迟、亲和性路由和虚拟化支持。本节从架构层次、中断分发/路由机制以及触发方式三个维度展开分析。

2.1 GIC v3/v4 架构概述

GIC v3 相比 v2 引入了 独立的路由表(Redistributor)、消息信号中断(MSI) 的本地支持以及 对大于 8 个 PE(Processing Element) 的可扩展性。GIC v4 则在 v3 基础上增加了 直接注入虚拟中断(Direct Virtual Interrupt Injection) 能力,显著降低虚拟机中断处理的宿主机开销。

架构核心组件: GIC v3/v4 由 Distributor、Redistributor、ITS(Interrupt Translation Service)和 CPU Interface 四部分组成。

下表对比了 GIC v2、v3、v4 的关键差异:

特性 GIC v2 GIC v3 GIC v4
最大 PE 数 ≤ 8 ≥ 256 ≥ 256
中断路由方式 固定 CPU 接口 基于 Redistributor 路由 基于 Redistributor + vPE 路由
MSI 支持 需外部桥接 原生支持(通过 ITS) 原生支持 + 虚拟 MSI
虚拟中断注入 软件模拟(List Register) 软件模拟(List Register) 硬件直接注入(Doorbell)
中断标识范围 ID 0-1019 ID 0-1023(扩展至 16-bit) ID 0-1023(扩展至 16-bit)

下图展示了 GIC v3/v4 的组件层次与数据流关系:

GIC v3/v4 架构组件与数据流 GIC v3/v4 架构组件与中断数据流 外设中断源 SPI (共享外设中断) PPI (私有外设中断) SGI (软件生成中断) LPI (本地专有中断) Distributor 中断使能/优先级/分组 ITS 中断翻译/MSI 路由 Redistributor 每 PE 中断配置/挂起 CPU Interface 优先级掩码/抢占 PE 核心 说明:LPI 通过 ITS 翻译后路由至 Redistributor;SPI/PPI/SGI 经 Distributor 分发。
性能要点: GIC v4 的硬件直接注入(Doorbell 机制)可将虚拟中断直接写入目标 vCPU 的 List Register,无需宿主机 VMM 介入,中断延迟降低约 30%-50%。

2.2 中断分发与路由

GIC v3/v4 的中断分发遵循 中断类型 → Distributor/ITS → Redistributor → CPU Interface → PE 的路径。每种中断类型具有不同的路由策略:

  • SGI(Software Generated Interrupt): 由 PE 通过写 ICC_SGI1R_EL1 寄存器直接发送给目标 PE 的 Redistributor,不经过 Distributor。
  • PPI(Private Peripheral Interrupt): 每个 PE 私有,直接路由到对应 PE 的 Redistributor,无需全局分发。
  • SPI(Shared Peripheral Interrupt): 由 Distributor 根据 中断路由表(Interrupt Routing Table, IRT) 分发到指定 PE 组的 Redistributor。
  • LPI(Locality-specific Peripheral Interrupt): 通过 ITS 进行地址翻译和路由,支持 基于消息的中断(MSI),可精确路由到任意 PE 或 vPE。

下表总结了四种中断类型的路由属性:

中断类型 ID 范围 路由目标 路由控制寄存器 典型用途
SGI 0-15 指定 PE 或 PE 组 ICC_SGI1R_EL1 核间通信(IPI)
PPI 16-31 所属 PE 自身 GICR_ICFGR0/1 本地定时器、PMU
SPI 32-1019 Distributor 路由表指定 PE GICD_IROUTER 外设 DMA、网络控制器
LPI 8192-65535 ITS 翻译后路由至任意 PE ITS 命令表 + GICR_PROPBASER PCIe MSI/MSI-X

下图展示了 SPI 和 LPI 两种典型中断的路由流程对比:

SPI 与 LPI 路由流程对比 SPI 与 LPI 中断路由流程对比 SPI 路由路径 外设触发 SPI Distributor Redistributor CPU Interface 目标 PE LPI 路由路径 PCIe 设备写 MSI ITS 翻译 Redistributor CPU Interface 目标 PE 关键差异:SPI 由 Distributor 查表路由;LPI 由 ITS 翻译地址后直接写入 Redistributor 的挂起表。
路由配置陷阱: SPI 的 GICD_IROUTER 寄存器支持 1-of-N 和 Any 路由模式。若配置为 Any 模式,Distributor 可能将中断路由到当前低负载的 PE,导致中断亲和性不可预测。实时系统应显式指定目标 PE。

2.3 中断触发方式:电平与边沿

GIC v3/v4 支持两种中断触发方式,通过 GICD_ICFGR(Distributor 级) 或 GICR_ICFGR(Redistributor 级) 寄存器配置:

  • 电平触发(Level-sensitive): 中断信号保持高电平(或低电平)直到被清除。GIC 在每次时钟采样时检测电平状态。适用于 共享中断线 和 需要硬件握手的设备。
  • 边沿触发(Edge-triggered): 中断信号在上升沿或下降沿被锁存。GIC 只记录跳变事件,即使信号恢复也不会丢失中断。适用于 脉冲型中断源 和 MSI。

下表从多个维度对比两种触发方式:

对比维度 电平触发 边沿触发
信号检测 持续采样电平状态 检测上升/下降沿跳变
中断丢失风险 低(电平持续有效) 高(脉冲过窄可能丢失)
共享中断线 支持(需轮询中断状态寄存器) 不支持(无法区分共享源)
中断清除方式 必须清除设备端中断源,否则持续触发 自动清除(GIC 记录事件后即可)
典型应用 GPIO、I2C、UART PCIe MSI/MSI-X、定时器、DMA 完成
GIC 配置寄存器 ICFGR 对应位 = 0b00 ICFGR 对应位 = 0b01

下图展示了电平触发与边沿触发在 GIC 内部的采样与挂起逻辑:

电平触发与边沿触发采样逻辑 电平触发 vs 边沿触发:GIC 采样与挂起逻辑 电平触发 中断信号 T1 T2 T3 0 1 1 挂起位持续为 1 直到设备清除 边沿触发 中断信号 T1 T2 T3 0 1 0 挂起位在 T2 锁存后自动清除 电平触发:挂起位反映实时电平;边沿触发:挂起位锁存跳变事件,读 ICC_IAR1_EL1 后自动清除。
性能验证关注点: 电平触发中断在 ISR 中必须确保设备端中断源被清除,否则 GIC 会立即重新触发,导致 中断风暴。边沿触发中断则需注意脉冲宽度是否满足 GIC 的最小采样窗口(通常为 2 个时钟周期)。

在 Linux 内核中,中断触发方式的配置通过设备树或 ACPI 表描述,驱动开发者可通过 irq_set_irq_type() 或 request_threaded_irq() 的 IRQF_TRIGGER_* 标志指定:

/* 电平触发中断注册示例 */
static irqreturn_t my_isr(int irq, void *dev_id)
{
    /* 必须清除设备中断源 */
    writel(0x1, DEVICE_INT_CLEAR_REG);
    return IRQ_HANDLED;
}

/* 边沿触发中断注册示例 */
static irqreturn_t my_edge_isr(int irq, void *dev_id)
{
    /* 无需清除设备,GIC 自动处理 */
    return IRQ_HANDLED;
}

/* 注册时指定触发方式 */
ret = request_irq(irq_num, my_isr,
                  IRQF_TRIGGER_HIGH,   /* 电平触发:高电平 */
                  "my_device", dev_id);

ret = request_irq(irq_num, my_edge_isr,
                  IRQF_TRIGGER_RISING, /* 边沿触发:上升沿 */
                  "my_device_edge", dev_id);
调试技巧: 使用 /proc/interrupts 查看中断触发次数和亲和性;使用 perf stat -e irq_vectors:* 统计 GIC 中断向量分布;对于电平触发中断,若 /proc/interrupts 计数持续增长而设备未产生新中断,说明中断源未正确清除。