diff --git a/target/arm/helper.c b/target/arm/helper.c index 088956eecf..b5c8caafe8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11706,11 +11706,17 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, indexmask = indexmask_grainsize; continue; } - /* Block entry at level 1 or 2, or page entry at level 3. + /* + * Block entry at level 1 or 2, or page entry at level 3. * These are basically the same thing, although the number - * of bits we pull in from the vaddr varies. + * of bits we pull in from the vaddr varies. Note that although + * descaddrmask masks enough of the low bits of the descriptor + * to give a correct page or table address, the address field + * in a block descriptor is smaller; so we need to explicitly + * clear the lower bits here before ORing in the low vaddr bits. */ page_size = (1ULL << ((stride * (4 - level)) + 3)); + descaddr &= ~(page_size - 1); descaddr |= (address & (page_size - 1)); /* Extract attributes from the descriptor */ attrs = extract64(descriptor, 2, 10)