diff options
Diffstat (limited to 'target/arm/helper.c')
-rw-r--r-- | target/arm/helper.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index 28b4347213..950f56599e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11173,6 +11173,7 @@ static const uint8_t pamax_map[] = { [3] = 42, [4] = 44, [5] = 48, + [6] = 52, }; /* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */ @@ -11564,11 +11565,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, descaddr = extract64(ttbr, 0, 48); /* - * If the base address is out of range, raise AddressSizeFault. + * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [5:2] of TTBR. + * + * Otherwise, if the base address is out of range, raise AddressSizeFault. * In the pseudocode, this is !IsZero(baseregister<47:outputsize>), * but we've just cleared the bits above 47, so simplify the test. */ - if (descaddr >> outputsize) { + if (outputsize > 48) { + descaddr |= extract64(ttbr, 2, 4) << 48; + } else if (descaddr >> outputsize) { level = 0; fault_type = ARMFault_AddressSize; goto do_fault; @@ -11620,7 +11625,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, } descaddr = descriptor & descaddrmask; - if (descaddr >> outputsize) { + + /* + * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12] + * of descriptor. Otherwise, if descaddr is out of range, raise + * AddressSizeFault. + */ + if (outputsize > 48) { + descaddr |= extract64(descriptor, 12, 4) << 48; + } else if (descaddr >> outputsize) { fault_type = ARMFault_AddressSize; goto do_fault; } |