Trouble configuring MMU for 2MB block mapping

So I'm working with QEMU and AArch64 mode and using the MMU. I've succesfully mapped 4K blocks, but I'm having trouble mapping 2M blocks. My configuration is such that the L1 entries are 1GB blocks, L2 entries are 2M blocks, and L3 entries are 4K, or at least that's my understanding of how I've configured it. My assumption is that if I have a block entry in a L2 table that it will map that VA from [va, va+2M) starting at the given PA in the entry in the range [pa, pa+2M). See example below for what I'm expecting.

My configuration:

TCR_EL1 = 0x120192019

TTBR0_EL1 = 0x43496000

VA = 0x201000
--> L1 Index = 0
--> L2 Index = 1
--> L3 Index = 1 (not needed, unused)

First couple of entries:
0x43496000:     0x43497003
0x43496008:     0x0
0x43496010:     0x0


0x43497003 is value at L1_TABLE[0] and points to an L2 Table at 0x43497000.

First few entries at 0x43497000 which is the L2_TABLE:
0x43497000:     0x43498003
0x43497008:     0x43897649
0x43497010:     0x43a97649
0x43497018:     0x43c97649
0x43497020:     0x43e97649
0x43497028:     0x44097649
0x43497030:     0x44297649
0x43497038:     0x44497649
0x43497040:     0x44697649

Entry L2_TABLE[1] is 0x43897649 and represents a 2MB block at [0x43897000, 0x43a97000).


Given this configuration, I expect that VA 0x201000 maps to PA 0x43898000, but in QEMU I see that every 4K is mapped again starting at 0x43897000. See below for some examples.

(qemu) gva2gpa 0x200000
gpa: 0x43897000            ---> this is expected
(qemu) gva2gpa 0x200100
gpa: 0x43897100            ---> this is expected    
(qemu) gva2gpa 0x201000
gpa: 0x43897000            ---> this is NOT expected, expected 0x43898000
(qemu) gva2gpa 0x202000
gpa: 0x43897000            ---> this is NOT expected, expected 0x43899000
(qemu) gva2gpa 0x202500
gpa: 0x43897500            ---> this is NOT expected, expected 0x43899500
(qemu) gva2gpa 0x203000
gpa: 0x43897000            ---> this is NOT expected, expected 0x4389a000


What am I missing?

  • After a few days of searching, I've found my answer. I mistakenly thought only the VA had to be aligned to the block size (2M for example), but that the PA could be aligned to the granularity (4K). For example, I mistakenly believed that a 2MB entry such as 0x43897649 would map from [0x43897000, 0x43A97000), which is 2MB aligned to a 4K boundary. This is not how the MMU operates. It does not add to the base address, it takes the least N sig-bits and "copies" them directly to the output address.

More questions in this forum