Misaligned Physical Address in 2MB Block Mapping Configuration
The core issue revolves around the misconfiguration of the ARM Memory Management Unit (MMU) in AArch64 mode, specifically when attempting to map 2MB blocks. The user successfully mapped 4KB blocks but encountered unexpected behavior when transitioning to 2MB block mappings. The primary symptom is that virtual addresses (VAs) are not translating to the expected physical addresses (PAs) when using 2MB block entries in the Level 2 (L2) page table. Instead of mapping the VA range [0x201000, 0x203000) to the expected PA range [0x43898000, 0x4389A000), the MMU repeatedly maps the VAs to the same 4KB-aligned PA range starting at 0x43897000. This indicates a fundamental misunderstanding of how the MMU handles block mappings, particularly the alignment requirements for both virtual and physical addresses.
The user’s configuration involves a three-level page table hierarchy: Level 1 (L1) entries map 1GB blocks, Level 2 (L2) entries map 2MB blocks, and Level 3 (L3) entries map 4KB blocks. The Translation Control Register (TCR_EL1) is set to 0x120192019, and the Translation Table Base Register 0 (TTBR0_EL1) points to the base of the L1 page table at 0x43496000. The L1 table entry at index 0 points to an L2 table at 0x43497000, and the L2 table contains entries intended to map 2MB blocks. However, the observed behavior suggests that the MMU is not interpreting these entries as intended, leading to incorrect address translations.
Misunderstanding of MMU Block Mapping Alignment Requirements
The root cause of the issue lies in a misunderstanding of the alignment requirements for block mappings in the ARM MMU. Specifically, the user assumed that only the virtual address (VA) needed to be aligned to the block size (2MB in this case), while the physical address (PA) could be aligned to the granularity of the smallest page size (4KB). This assumption is incorrect. For block mappings, both the VA and PA must be aligned to the block size. The MMU does not perform arithmetic to adjust the PA based on the offset within the block; instead, it directly maps the least significant bits of the VA to the corresponding bits in the PA.
In the user’s example, the L2 table entry at index 1 is set to 0x43897649, which is intended to map a 2MB block starting at PA 0x43897000. However, this address is not 2MB-aligned; it is only 4KB-aligned. The MMU interprets this entry as a 2MB block mapping, but because the PA is not 2MB-aligned, the translation logic does not behave as expected. Instead of mapping the VA range [0x201000, 0x203000) to the PA range [0x43898000, 0x4389A000), the MMU maps all VAs within the 2MB block to the same 4KB-aligned PA range starting at 0x43897000. This results in the observed behavior where VAs like 0x201000, 0x202000, and 0x203000 all map to PAs within the 0x43897000-0x43897FFF range.
The MMU’s behavior is consistent with its design: when a block mapping is used, the least significant bits of the VA are directly copied to the PA. If the PA is not aligned to the block size, the resulting translations will not span the expected range. This is why the user observed that every 4KB within the 2MB block was mapped to the same 4KB-aligned PA range.
Correcting Block Mapping Alignment and MMU Configuration
To resolve this issue, the physical address (PA) used in the L2 table entry must be aligned to the block size (2MB in this case). This means that the PA must be a multiple of 2MB, such as 0x43800000 or 0x43A00000. The user’s current PA of 0x43897000 is not 2MB-aligned, which is why the MMU is not behaving as expected. To fix this, the L2 table entry should be updated to use a 2MB-aligned PA.
For example, if the desired PA range is [0x43800000, 0x43A00000), the L2 table entry at index 1 should be set to 0x43800049 (assuming the lower bits are used for attributes). This ensures that the PA is 2MB-aligned, allowing the MMU to correctly map the VA range [0x201000, 0x203000) to the PA range [0x43808000, 0x4380A000). The MMU will then correctly interpret the block mapping and perform the expected address translations.
Additionally, the user should verify that the Translation Control Register (TCR_EL1) is configured correctly for the desired page table hierarchy and block sizes. The current value of 0x120192019 appears to be valid for a three-level page table hierarchy with 4KB granule size, but it is always good practice to double-check the register settings against the ARM architecture reference manual. The TCR_EL1 register controls various aspects of the MMU, including the size of the address space, the granule size, and the attributes of the translation tables. Ensuring that this register is configured correctly is essential for proper MMU operation.
Finally, the user should ensure that the Translation Table Base Register 0 (TTBR0_EL1) points to the correct base address of the L1 page table. In this case, TTBR0_EL1 is set to 0x43496000, which appears to be correct based on the provided information. However, if the base address is incorrect, the MMU will not be able to locate the page tables, leading to translation faults or incorrect address translations.
In summary, the key to resolving this issue is to ensure that both the virtual and physical addresses are aligned to the block size when using block mappings in the ARM MMU. By correcting the alignment of the PA in the L2 table entry and verifying the configuration of the TCR_EL1 and TTBR0_EL1 registers, the user can achieve the desired address translations and avoid the unexpected behavior observed in QEMU.