Attribute bits in stage 1/stage 2 block descriptors are not fully masked during AArch64 page table walks
In the aarch64 LPAE page table walk implemented in get_phys_addr_lpae
once a non-table descriptor is reached (block descriptor for levels 1/2 or a page descriptor at level 3) the final physical address is calculated by extracting the descriptor address from the descriptor by masking it off with descaddrmask
and then combining it with the vaddr offset.
This is incorrect however, as descaddrmask
is based only on the translation granule size, which is correct for table descriptors and page descriptors, but not for block descriptors, for which the final address bits are determined based on the walk level. (See section D5.3.1
in the armv8 arm)
As a result, page table walks with a granule size of 4KB or 16KB which end on a block descriptor do not mask off enough attribute bits, meaning some RES0
bits are used as part of the final physical address, this is especially problematic as the nT
bit is defined at bit 16, which is included in the final address as well.
A pseudocode implementation of correct block-descriptor base address extraction is available in the armv8 arm under aarch64/translation/vmsa_addrcalc/AArch64.BlockBase
for reference.