ICC_PMR 寄存器详解

ARM中断控制器优先级屏蔽寄存器

这个寄存器是干啥的?

ICC_PMR(Interrupt Controller Priority Mask Register)是ARM GICv3/v4中断控制器中的一个关键寄存器,它就像一个"门卫",决定哪些中断能够被传递到处理器核心。

简单来说,ICC_PMR设置了一个优先级阈值:只有优先级高于这个阈值的中断才会被处理器处理,优先级低于或等于这个值的中断会被暂时屏蔽。

优先级数值越低表示优先级越高(0是最高优先级,255是最低优先级)。这与我们通常的理解可能相反,需要特别注意。

怎么使用这个寄存器?

ICC_PMR是一个32位寄存器,但只有低8位[7:0]有效,高24位保留(必须写0)。

寄存器位域

位域 名称 描述
[31:8] RES0 保留位,必须写0
[7:0] Priority 优先级屏蔽值,决定哪些中断能被处理

访问方式

在AArch32架构下,使用MCR/MRC指令访问:

// 读取ICC_PMR到R0
MRC p15, 0, r0, c4, c6, 0

// 将R0的值写入ICC_PMR
MCR p15, 0, r0, c4, c6, 0

在AArch64架构下,对应的寄存器是ICC_PMR_EL1,使用MSR/MRS指令访问:

// 读取ICC_PMR_EL1到X0
MRS x0, ICC_PMR_EL1

// 将X0的值写入ICC_PMR_EL1
MSR ICC_PMR_EL1, x0

什么场景下需要使用?

1. 系统初始化

在操作系统启动时,需要设置一个合适的优先级阈值,确保关键中断能够被处理,同时屏蔽不重要的中断。

2. 关键代码段保护

在执行关键任务时,提高优先级阈值(设置较小的数值),屏蔽大多数中断,确保关键任务不被中断干扰。

3. 实时性要求高的场景

在实时系统中,通过动态调整优先级阈值,确保高优先级任务能够及时响应。

4. 功耗管理

在低功耗模式下,可以提高优先级阈值,只允许少数关键中断唤醒系统。

实际应用示例

Linux内核中的使用

在Linux内核中,ICC_PMR常用于控制中断屏蔽:

// 设置优先级阈值,只允许优先级高于0x80的中断
write_sysreg_s(0x80, ICC_PMR_EL1);

// 在关键代码段中,提高阈值以屏蔽大多数中断
local_irq_save(flags);
write_sysreg_s(0x10, ICC_PMR_EL1); // 只允许高优先级中断

// 执行关键操作
critical_section();

// 恢复原来的优先级阈值
write_sysreg_s(0x80, ICC_PMR_EL1);
local_irq_restore(flags);

ATF (ARM Trusted Firmware) 中的使用

在ATF中,ICC_PMR用于安全世界和正常世界的切换:

// 进入安全世界时,设置较高的优先级阈值
// 只允许安全相关的高优先级中断
func enter_secure_world
    mrs x0, ICC_PMR_EL1
    str x0, [sp, #-16]!  // 保存当前PMR值
    mov x0, #0x10        // 设置新的优先级阈值
    msr ICC_PMR_EL1, x0
    // 执行安全操作
    ...
    ldr x0, [sp], #16    // 恢复原来的PMR值
    msr ICC_PMR_EL1, x0
endfunc

OP-TEE 中的使用

在OP-TEE安全环境中,ICC_PMR用于保护安全操作:

// TEE中执行安全敏感操作时
TEE_Result secure_operation(void)
{
    uint32_t old_pmr;
    
    // 保存当前PMR设置
    old_pmr = read_icc_pmr();
    
    // 设置高优先级阈值,只允许安全关键中断
    write_icc_pmr(0x20);
    
    // 执行安全敏感操作
    do_secure_operation();
    
    // 恢复原来的PMR设置
    write_icc_pmr(old_pmr);
    
    return TEE_SUCCESS;
}

注意事项

1. 优先级数值与优先级高低成反比:数值越小,优先级越高

2. 复位后ICC_PMR的默认值为0x00,这意味着所有中断都会被屏蔽

3. 在EL0(用户模式)下访问ICC_PMR会导致未定义异常

4. 需要先启用GIC系统寄存器接口(设置ICC_SRE.SRE位)才能访问此寄存器