GICv3作为ARMv8架构的标准中断控制器,其设计充分考虑了多核处理器的中断管理需求。与早期版本相比,GICv3引入了Affinity Routing机制,通过重分发器(Redistributor)和CPU接口分离的设计,显著提升了多核系统的中断处理效率。
GICv3的物理组成分为三个关键部件:
c复制#define GICD_CTLR 0x0000 // 分发器控制寄存器
#define GICD_TYPER 0x0004 // 类型寄存器
#define GICD_IROUTERn 0x6000 // SPI路由寄存器组
bash复制Redistributor基地址 = GICR_BASE + (CPU_Affinity * 0x20000)
关键提示:在初始化阶段必须确保Distributor和Redistributor的访问顺序。正确的启动流程应为:先禁用全局中断(GICD_CTLR=0),配置所有Redistributor,最后启用Distributor。
GICv3的中断源按INTID划分为多个区域:
在64位系统中,LPI的INTID空间可扩展到16bit(0-65535),这通过GICD_TYPER.IDbits字段可查询实际支持的范围。我们在实际项目中曾遇到一个典型问题:某SoC的LPI范围被限制在8192-32767,超出此范围的配置会导致静默失败。
GICv3的优先级配置通过两组寄存器实现:
优先级值采用8位表示(实际实现可能只支持部分高位),其中最低有效位具有最高优先级。一个常见的配置误区是未考虑优先级位宽:
c复制// 错误配置:假设实现仅支持高4位,实际写入0xF0会被截断为0x00
write_reg(GICD_IPRIORITYn, 0xF0);
// 正确做法:查询GICD_TYPER.PRIbits确定可用位宽
uint8_t pri_bits = (read_reg(GICD_TYPER) >> 29) & 0x7;
uint8_t priority = (0x1F << (8 - pri_bits)); // 使用最高有效位
ICC_BPRn_EL1寄存器将优先级分为组优先级和子优先级,其分界点通过Binary Point设置。我们通过一个实时控制系统案例说明其重要性:
某无人机飞控系统需要保证:
配置方案:
c复制// 设置Binary Point为4,即高4位为组优先级
write_reg(ICC_BPR1_EL1, 4);
// 优先级分配:
// - 传感器中断:0x10 (组优先级1)
// - 通信中断: 0x20 (组优先级2)
// - 重传请求: 0x21 (组优先级2)
此时比较规则变为:
GICv3与ARM TrustZone的深度集成体现在三个中断组:
典型配置流程:
c复制// 在EL3设置中断组别
void configure_interrupt_group(uint32_t intid, uint8_t group) {
uint32_t reg_offset = intid / 32;
uint32_t bit_offset = intid % 32;
// 先禁用中断
write_reg(GICD_ICENABLERn + reg_offset*4, 1 << bit_offset);
// 设置组别
if (group == 0) {
write_reg(GICD_IGROUPRn + reg_offset*4, 0 << bit_offset);
write_reg(GICD_IGRPMODRn + reg_offset*4, 0 << bit_offset);
} else if (group == 1) {
// Secure Group 1
write_reg(GICD_IGROUPRn + reg_offset*4, 0 << bit_offset);
write_reg(GICD_IGRPMODRn + reg_offset*4, 1 << bit_offset);
} else {
// Non-secure Group 1
write_reg(GICD_IGROUPRn + reg_offset*4, 1 << bit_offset);
}
// 重新启用中断
write_reg(GICD_ISENABLERn + reg_offset*4, 1 << bit_offset);
}
GICD_IROUTERn寄存器提供两种路由模式:
我们在负载均衡系统中发现一个关键优化点:对于高频率中断(如网络数据包接收),采用1-of-N路由可显著提升吞吐量。测试数据显示:
配置示例:
c复制// 设置SPI#50为1-of-N路由模式
uint64_t router_val = (1ULL << 31); // 设置路由模式位
write_reg(GICD_IROUTERn + 50*8, router_val);
// 允许所有CPU参与分发
for (int cpu = 0; cpu < num_cpus; cpu++) {
clear_bit(GICR_CTLR, DPG1NS, cpu_redist_base[cpu]);
}
ITS的初始化是GICv3最复杂的环节之一,主要步骤包括:
c复制// 计算Device Table大小
uint32_t devid_bits = (read_reg(GITS_TYPER) >> 13) & 0x1F;
size_t dt_size = 1 << (devid_bits + 3); // 每个条目8字节
// 分配对齐内存
void *dt_base = aligned_alloc(64KB, dt_size);
memset(dt_base, 0, dt_size);
c复制// 配置64KB对齐的命令队列
write_reg(GITS_CBASER, (uint64_t)cmdq_base | CBASER_CACHEABILITY | CBASER_SHAREABILITY);
write_reg(GITS_CWRITER, 0);
bash复制# MAPD命令格式:映射设备到ITT
ITS_CMD_MAPD(dev_id, itt_base, itt_size)
# MAPTI命令:关联EventID与INTID
ITS_CMD_MAPTI(dev_id, event_id, intid, collection)
# MAPC命令:绑定Collection到Redistributor
ITS_CMD_MAPC(collection, redist_addr)
通过实测发现LPI配置对系统延迟有显著影响:
c复制struct its_cmd *cmd = cmdq_base + get_write_pointer();
for (int i = 0; i < BATCH_SIZE; i++) {
build_mapti_cmd(cmd++, dev_id, event_id+i, intid+i, coll_id);
}
write_reg(GITS_CWRITER, (cmd - cmdq_base) % CMDQ_SIZE);
c复制uint64_t propbaser = (phys_addr & 0xFFFFFFFFFF000) |
(1 << 12) | // Inner WB
(1 << 10); // Outer WB
write_reg(GICR_PROPBASER, propbaser);
bash复制# 将Collection 3从中断迁移到CPU1->CPU2
ITS_CMD_MAPC(3, cpu2_redist_addr)
ITS_CMD_SYNC(cpu2_redist_addr)
ITS_CMD_MOVALL(cpu1_redist_addr, cpu2_redist_addr)
ITS_CMD_SYNC(cpu1_redist_addr)
mermaid复制sequenceDiagram
participant P as Peripheral
participant D as Distributor
participant R as Redistributor
participant C as CPU Interface
P->>D: 断言中断信号(SPI)
D->>D: 优先级仲裁
D->>R: 根据IROUTERn路由
R->>C: 检查ICC_PMR_EL1
C->>PE: 触发异常向量
c复制// 中断服务例程模板
void isr(void) {
// 1. 读取IAR获取INTID
uint32_t intid = read_reg(ICC_IAR1_EL1);
// 2. 处理中断
handle_interrupt(intid);
// 3. 写EOIR完成处理
write_reg(ICC_EOIR1_EL1, intid);
}
实现安全嵌套中断需注意:
c复制// 配置嵌套优先级层次
set_priority(TIMER_INT, 0x10); // 最高
set_priority(UART_INT, 0x80); // 最低
assembly复制el1_irq:
msr sp_el0, x18 // 保存用户SP
ldr x18, =irq_stack // 切换到IRQ专用栈
sub x18, x18, #256
stp x0-x30, [x18] // 保存完整上下文
c复制// Stage1: 降低运行优先级
write_reg(ICC_EOIR1_EL1, intid);
// Stage2: 实际中断完成
write_reg(ICC_DIR_EL1, intid);
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 中断未触发 | 分发器未启用 | 检查GICD_CTLR.Enable |
| 中断卡死 | 未写EOI寄存器 | 跟踪ISR返回路径 |
| 优先级失效 | Binary Point配置错误 | 验证ICC_BPR1_EL1值 |
| LPI丢失 | ITS命令未同步 | 检查SYNC命令执行 |
GICv3提供的关键性能监测点:
c复制// 配置性能计数器监测中断延迟
write_reg(GICD_PMCR, 0x1); // 启用计数器
write_reg(GICD_PMSIR, 0x5); // 选择中断响应时间指标
// 读取统计结果
uint32_t latency = read_reg(GICD_PMSR) & 0xFFFFFF;
我们在某5G基带项目中通过此方式发现:当系统负载超过70%时,LPI处理延迟会从平均150ns骤增至1.2μs。最终通过优化ITS命令批处理将峰值延迟降低至600ns。