关于ARM架构__turn_mmu_on函数中nop(mov r0,r0)指令作用的技术问询
原始代码片段
mcr p15, 0, r5, c3, c0, 0 @ load domain access register mcr p15, 0, r4, c2, c0, 0 @ load page table pointer b __turn_mmu_on .align 5 .type __turn_mmu_on, %function __turn_mmu_on: mov r0, r0 mcr p15, 0, r0, c1, c0, 0 @ write control reg mrc p15, 0, r3, c0, c0, 0 @ read id reg mov r3, r3 mov r3, r3 mov pc, r13
问题梳理
为什么这里会有nop指令?只是为了等待前面的指令完成吗?
mcr p15, 0, r5, c3, c0, 0 @ load domain access register mcr p15, 0, r4, c2, c0, 0 @ load page table pointer但是分支指令会刷新流水线中剩余的指令啊?那这个nop(mov r0, r0)的作用到底是什么?
mov r0, r0就像nop一样,什么都不做。如果我删掉这段代码,会发生什么?MMU还能正常工作吗?我在哪里可以找到原始代码?
00945010c063b (Russell King 2010-10-04 17:56:13 +0100 501) mov r0, r0
我是从内核git仓库获取到这段代码的
解答
咱们一步一步拆解这个问题:
mov r0, r0的核心作用
ARM架构里,修改CP15寄存器(比如开启MMU的mcr p15, 0, r0, c1, c0, 0)的指令属于特权同步指令,但CPU流水线的并行特性,可能导致后续指令在CP15配置生效前就被触发。这里的mov r0, r0本质是流水线填充指令,给硬件足够的周期完成两个关键操作:- 确保之前配置域访问寄存器、页表指针的
mcr指令完全写入CP15寄存器,配置生效; - 让MMU硬件完成从物理地址到虚拟地址的模式切换,避免后续指令使用未就绪的地址转换机制。
你提到分支指令会刷新流水线,但
b __turn_mmu_on是跳转到当前函数入口,进入后第一条指令的延迟,是专门为MMU切换的硬件时序预留的——分支刷新的是跳转前的流水线,而跳转后的流水线需要新的指令填充来等待硬件就绪。- 确保之前配置域访问寄存器、页表指针的
删除该指令的风险
这取决于具体的ARM内核版本和硬件实现:少数硬核可能因为硬件时序宽松侥幸正常,但绝大多数场景下会触发地址错误或系统崩溃。比如MMU还没完成地址转换模式切换,后续的mrc读取CP15寄存器、或者mov pc, r13的跳转操作就会尝试用虚拟地址访问内存,而此时页表映射还未完全生效,直接导致异常。原始代码的位置
这段代码来自Linux内核的ARM架构启动代码,具体在arch/arm/kernel/head.S文件中,你提到的Russell King的提交正是负责优化这个启动阶段的MMU切换流程。
备注:内容来源于stack exchange,提问作者cloudprogram

