要开启MMU,需要建立页表映射,而且需要处理缓存一致性的问题,这样内核启动的依赖条件就会变得复杂。为了降低启动代码的复杂度,约定在Linux内核启动时,MMU是关闭的。这样也就意味着不能利用高速缓存的性能。为了获得更好的性能,也为了后续可以给不同的地址空间设置不同的访问属性以更好地管理内存,需要在某个阶段把MMU打开,并使能高速缓存。
但是,在关闭MMU的情况下,处理器访问的是物理地址,而MMU打开时,处理器访问的地址变成了虚拟地址。现代处理器大多数是多级流水线架构,处理器会提前预取多条指令到流水线中。打开MMU只需要向SCTLR_ELx
寄存器写入特定值即可,运行到此处时,处理器已经提前预取了多条指令,这些指令要操作的地址实际是物理地址。当打开MMU后,处理器会将上述地址作为虚拟地址使用,MMU会尝试将其翻译为对应的物理地址,访问就会出现错误。
上述问题可以通过使用位置无关码和在打开MMU后,马上清空CPU流水线解决。但是如果打开了CONFIG_RELOCATABLE
或CONFIG_RANDOMIZE_BASE
,代码复杂度就会大大提高。创建一个虚拟地址和物理地址相等的临时映射,也就是恒等映射,可以大大降低代码复杂度,解决上述问题。