So, basically, I want to enable the memory management unit on an ARMv7 core. The actual procedure is pretty much trivial. I just need to load the address of the translation table into TTBR0
and enable the MMU using the control register.
/* enable mmu */
mcr p15, 0, r0, c2, c0, 0
mrc p15, 0, r12, c1, c0, 0
orr r12, r12, #0x1
mcr p15, 0, r12, c1, c0, 0
Now, the problem arises as soon as the MMU is enabled, because on ARMv7 (unlike on some other versions of the ARM architecture), the CPU begins fetching from the virtual address immediately. So, if the bootloader is running at 0x10000000
and then enables the MMU, unless it enters an identity mapping first, the next fetch at 0x10000004
will cause a prefetch abort. Now, I'm aware that it's possible to do this using an identity mapping during the initial enabling of the MMU. However, the same problem will also occur when switching translation tables (loading new values into TTBR0
).
So, essentially, I'm looking for a more or less straightforward way of loading a new value into TTBR0
(or just turning the MMU on) and then, immediately jumping to a new address, which will be valid in the new map. This was possible on earlier architectures because at least 4 instructions following the instruction that enabled the MMU or changed the state were fetched from the old address. Ideally, I want to be able to do that without relying on incredibly ugly hacks where you have to create an identity mapping every time you want to switch page tables or turn the MMU on.
To clarify what I meant when I was talking about older architectures, here is a link to the ARM infocenter page explaining how to turn on the MMU on ARM720T: 7.16.1. Enabling the MMU