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
在操作系统启动时,需要设置一个合适的优先级阈值,确保关键中断能够被处理,同时屏蔽不重要的中断。
在执行关键任务时,提高优先级阈值(设置较小的数值),屏蔽大多数中断,确保关键任务不被中断干扰。
在实时系统中,通过动态调整优先级阈值,确保高优先级任务能够及时响应。
在低功耗模式下,可以提高优先级阈值,只允许少数关键中断唤醒系统。
在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中,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安全环境中,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位)才能访问此寄存器