更新ARM GIC ICC_PMR寄存器后为何需要DSB SY指令?
背景
在Linux内核ARM64架构的代码中,当ICC_CTLR_EL1.PMHE == 0b1(优先级掩码提示使能)时,更新SYS_ICC_PMR_EL1(中断优先级掩码寄存器)后会执行pmr_sync(),该函数最终会触发DSB SY指令。对应的代码示例如下:
./arch/arm64/include/asm/irqflags.h: 45 write_sysreg_s(GIC_PRIO_IRQON, SYS_ICC_PMR_EL1); 0xffff80008069ff90 <+156>: mov x0, #0xe0 // #224 0xffff80008069ff94 <+160>: msr s3_0_c4_c6_0, x0 46 pmr_sync(); 0xffff80008069ff98 <+164>: dsb sy
提交信息中的解释为:
当优先级掩码提示使能(PMHE)== 0b1时,GIC可能会使用PMR值来决定是否向PE发送IRQ信号,因此修改PMR值后,可能需要DSB SY指令以确保中断能在有限时间内发送到CPU。
疑问与解答
为什么内存屏障指令DSB SY会被用于系统寄存器操作?
首先要纠正一个常见误解:ARM架构的DSB指令并非只针对内存操作,它的核心作用是等待所有在它之前发起的操作(包括系统寄存器访问、外设交互、内存操作等)完成硬件层面的同步后,才允许执行后续指令。
对于SYS_ICC_PMR_EL1这类GIC相关的系统寄存器,msr指令只是CPU发起了写操作,但这个操作并非在CPU内部完成——它需要同步到GIC的硬件逻辑中。GIC作为独立的系统外设,和CPU之间的交互存在延迟,比如GIC的中断分发器可能需要一段时间才能接收到新的PMR值。
DSB SY如何确保中断及时送达CPU?
当PMHE=1时,GIC的中断分发逻辑会直接参考PMR的值来判断是否将符合优先级的中断发送给PE。如果没有DSB SY,CPU执行完msr指令后就继续后续代码,但GIC可能还在使用旧的PMR值,导致两种问题:
- 本该被允许的高优先级中断无法及时送达;
- 本该被屏蔽的低优先级中断错误发送。
DSB SY是全系统范围的屏障指令,它会强制等待之前的msr操作完成与GIC的硬件同步,确保GIC已经加载了新的PMR值。这样后续代码执行时,GIC的中断判断逻辑已经基于更新后的PMR工作,从而保证符合条件的中断能在预期时间内送达CPU。
内容的提问来源于stack exchange,提问作者Changbin Du

