ARM Bootloader:禁用MMU和缓存

3 arm bootloader mmu

根据一些教程,我们将在bootlaoder的开头禁用MMU和I/D-Caches.如果我理解正确,它的目的是直接在程序中使用物理地址,所以如果我错了请纠正我.谢谢!

其次,我们这样做是为了禁用MMU和缓存:

mrc P15,0,R0,C1,C0,0

bic R0,R0,#0x00002300 @ clear bits 13,9:8

bic R0,R0,#0x00000087 @清除位7,2:0

orr R0,R0,#0x00000002 @ set bit 2(A)对齐

orr R0,R0,#0x00001000 @设置位12(I)I-Cache

mcr P15,0,R0,C1,C0,0

D-Cache,MMU和数据地址对齐故障检查已被清除位2:0禁用,但为什么我们在下列仪器中立即启用位2?要确保此操作有效?

最后一个问题是为什么D-cache被禁用但是I-caches能够?加快仪器加工?

old*_*mer 9

最后一个问题是为什么D-cache被禁用但是I-caches能够?加快仪器加工?

MMU具有用于确定哪些存储器区域可缓存的设置.如果您没有打开mmu但是您已打开数据缓存(如果可能),那么您无法安全地与外围设备通信.如果您读取uart状态寄存器,例如通过缓存,就像任何其他数据操作一样,无论该状态是什么,都会保留在缓存中以供后续读取,直到该缓存行被驱逐并且您再获得一次实际操作寄存器.让我们假设您有一些代码可以轮询uart状态寄存器,等待rx缓冲区中的字符.如果第一次读取显示没有字符,那么该状态进入缓存,您将永远保持循环,因为您永远不会再次与状态寄存器通信,您只需获取寄存器的缓存副本.如果那里有一个字符然后该状态也被缓存,你读取rx寄存器,也许做一些事情,如果再次回来,如果状态没有从数据缓存中逐出,那么你会得到陈旧状态,显示有一个字符,你的rx缓冲区读取可能也可能不会被缓存,因此你可能会得到缓存中的陈旧值,你可能会得到一个陈旧的值或者你读到时外围设备所做的任何事情,并且没有新值或你可能获得一个新值,但在这些情况下你得到的是对外围设备的正确访问.当mmu打开时,您使用mmu将该外围设备使用的地址空间标记为非(数据) - 可缓存,并且您没有此问题.关闭mmu后,您需要关闭arm系统的数据缓存.

保持I-cache开启是可以的,因为指令只读取指令......对于裸机应用程序来说还可以,例如,如果你使用的闪存可能会有读取干扰(spi或i2c闪烁) .问题是这个应用程序是一个引导加载程序,所以你必须要特别小心.例如,您的引导加载程序在地址0x8000处有一些代码,它至少运行一次,然后您选择将其用作引导加载程序,引导加载程序可能位于地址0x10000000,允许您在0x8000加载新程序,此加载使用数据访问所以它不通过指令缓存.因此,有可能指令缓存具有上次在0x8000区域时的部分或全部代码,并且当您在0x8000分支到引导加载的代码时,您将从缓存中获取旧程序或者令人讨厌的混合旧程序和新程序的缓存和未缓存的部分.因此,如果您的引导加载程序允许启用i-cache,则需要在分支到引导加载的代码之前使缓存无效.

最后,如果您或任何使用此引导加载程序的人想要使用jtag,那么您会遇到同样的问题,但更糟糕的是,当您告诉jtag调试器时,不会通过i-cache的数据周期将新程序写入ram然后运行新程序,你将获得1)只有新程序,2)新程序和来自缓存的旧程序片段的混合3)来自缓存的旧程序.

所以d-cache在没有mmu的情况下很糟糕,因为ram,外设等都没有.i-cache使用风险的方式除了jtag用于调试的时间外你可以缓解.

如果您在(外部)闪存中有疑虑或已确认读取干扰,那么我建议打开i-cache,使用紧密循环将应用程序复制到ram,分支到ram副本并在那里运行,关闭i-cache(或使用时自担风险)并且不要再次触摸闪存,当然也不会对较小区域进行大量读取访问.像命令行解析器一样的紧密uart轮询循环是一个非常好的地方,可以通过读取干扰来实现.