[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 23/26] target/arm: Implement FEAT_LPA2
From: |
Peter Maydell |
Subject: |
[PULL 23/26] target/arm: Implement FEAT_LPA2 |
Date: |
Wed, 2 Mar 2022 20:52:27 +0000 |
From: Richard Henderson <richard.henderson@linaro.org>
This feature widens physical addresses (and intermediate physical
addresses for 2-stage translation) from 48 to 52 bits, when using
4k or 16k pages.
This introduces the DS bit to TCR_ELx, which is RES0 unless the
page size is enabled and supports LPA2, resulting in the effective
value of DS for a given table walk. The DS bit changes the format
of the page table descriptor slightly, moving the PS field out to
TCR so that all pages have the same sharability and repurposing
those bits of the page table descriptor for the highest bits of
the output address.
Do not yet enable FEAT_LPA2; we need extra plumbing to avoid
tickling an old kernel bug.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20220301215958.157011-17-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
docs/system/arm/emulation.rst | 1 +
target/arm/cpu.h | 22 ++++++++
target/arm/internals.h | 2 +
target/arm/helper.c | 102 +++++++++++++++++++++++++++++-----
4 files changed, 112 insertions(+), 15 deletions(-)
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 0053ddce208..520fd39071e 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -25,6 +25,7 @@ the following architecture extensions:
- FEAT_JSCVT (JavaScript conversion instructions)
- FEAT_LOR (Limited ordering regions)
- FEAT_LPA (Large Physical Address space)
+- FEAT_LPA2 (Large Physical and virtual Address space v2)
- FEAT_LRCPC (Load-acquire RCpc instructions)
- FEAT_LRCPC2 (Load-acquire RCpc instructions v2)
- FEAT_LSE (Large System Extensions)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index c52d56f6699..24d9fff1705 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -4284,6 +4284,28 @@ static inline bool isar_feature_aa64_i8mm(const
ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, I8MM) != 0;
}
+static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id)
+{
+ return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 1;
+}
+
+static inline bool isar_feature_aa64_tgran4_2_lpa2(const ARMISARegisters *id)
+{
+ unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2);
+ return t >= 3 || (t == 0 && isar_feature_aa64_tgran4_lpa2(id));
+}
+
+static inline bool isar_feature_aa64_tgran16_lpa2(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 2;
+}
+
+static inline bool isar_feature_aa64_tgran16_2_lpa2(const ARMISARegisters *id)
+{
+ unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2);
+ return t >= 3 || (t == 0 && isar_feature_aa64_tgran16_lpa2(id));
+}
+
static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 00af41d7925..a34be2e4595 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1056,6 +1056,7 @@ static inline uint32_t aarch64_pstate_valid_mask(const
ARMISARegisters *id)
typedef struct ARMVAParameters {
unsigned tsz : 8;
unsigned ps : 3;
+ unsigned sh : 2;
unsigned select : 1;
bool tbi : 1;
bool epd : 1;
@@ -1063,6 +1064,7 @@ typedef struct ARMVAParameters {
bool using16k : 1;
bool using64k : 1;
bool tsz_oob : 1; /* tsz has been clamped to legal range */
+ bool ds : 1;
} ARMVAParameters;
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3a7f5cf6f08..088956eecf0 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4546,6 +4546,14 @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env,
ARMMMUIdx mmuidx,
} else {
ret.base = extract64(value, 0, 37);
}
+ if (param.ds) {
+ /*
+ * With DS=1, BaseADDR is always shifted 16 so that it is able
+ * to address all 52 va bits. The input address is perforce
+ * aligned on a 64k boundary regardless of translation granule.
+ */
+ page_shift = 16;
+ }
ret.base <<= page_shift;
return ret;
@@ -11081,8 +11089,13 @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool
is_aa64, int level,
const int grainsize = stride + 3;
int startsizecheck;
- /* Negative levels are never allowed. */
- if (level < 0) {
+ /*
+ * Negative levels are usually not allowed...
+ * Except for FEAT_LPA2, 4k page table, 52-bit address space, which
+ * begins with level -1. Note that previous feature tests will have
+ * eliminated this combination if it is not enabled.
+ */
+ if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) {
return false;
}
@@ -11223,8 +11236,9 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env,
uint64_t va,
ARMMMUIdx mmu_idx, bool data)
{
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
- bool epd, hpd, using16k, using64k, tsz_oob;
- int select, tsz, tbi, max_tsz, min_tsz, ps;
+ bool epd, hpd, using16k, using64k, tsz_oob, ds;
+ int select, tsz, tbi, max_tsz, min_tsz, ps, sh;
+ ARMCPU *cpu = env_archcpu(env);
if (!regime_has_2_ranges(mmu_idx)) {
select = 0;
@@ -11238,7 +11252,9 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env,
uint64_t va,
hpd = extract32(tcr, 24, 1);
}
epd = false;
+ sh = extract32(tcr, 12, 2);
ps = extract32(tcr, 16, 3);
+ ds = extract64(tcr, 32, 1);
} else {
/*
* Bit 55 is always between the two regions, and is canonical for
@@ -11248,6 +11264,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env,
uint64_t va,
if (!select) {
tsz = extract32(tcr, 0, 6);
epd = extract32(tcr, 7, 1);
+ sh = extract32(tcr, 12, 2);
using64k = extract32(tcr, 14, 1);
using16k = extract32(tcr, 15, 1);
hpd = extract64(tcr, 41, 1);
@@ -11257,24 +11274,51 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env,
uint64_t va,
using64k = tg == 3;
tsz = extract32(tcr, 16, 6);
epd = extract32(tcr, 23, 1);
+ sh = extract32(tcr, 28, 2);
hpd = extract64(tcr, 42, 1);
}
ps = extract64(tcr, 32, 3);
+ ds = extract64(tcr, 59, 1);
}
- if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
+ if (cpu_isar_feature(aa64_st, cpu)) {
max_tsz = 48 - using64k;
} else {
max_tsz = 39;
}
+ /*
+ * DS is RES0 unless FEAT_LPA2 is supported for the given page size;
+ * adjust the effective value of DS, as documented.
+ */
min_tsz = 16;
if (using64k) {
- if (cpu_isar_feature(aa64_lva, env_archcpu(env))) {
+ if (cpu_isar_feature(aa64_lva, cpu)) {
+ min_tsz = 12;
+ }
+ ds = false;
+ } else if (ds) {
+ switch (mmu_idx) {
+ case ARMMMUIdx_Stage2:
+ case ARMMMUIdx_Stage2_S:
+ if (using16k) {
+ ds = cpu_isar_feature(aa64_tgran16_2_lpa2, cpu);
+ } else {
+ ds = cpu_isar_feature(aa64_tgran4_2_lpa2, cpu);
+ }
+ break;
+ default:
+ if (using16k) {
+ ds = cpu_isar_feature(aa64_tgran16_lpa2, cpu);
+ } else {
+ ds = cpu_isar_feature(aa64_tgran4_lpa2, cpu);
+ }
+ break;
+ }
+ if (ds) {
min_tsz = 12;
}
}
- /* TODO: FEAT_LPA2 */
if (tsz > max_tsz) {
tsz = max_tsz;
@@ -11296,6 +11340,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env,
uint64_t va,
return (ARMVAParameters) {
.tsz = tsz,
.ps = ps,
+ .sh = sh,
.select = select,
.tbi = tbi,
.epd = epd,
@@ -11303,6 +11348,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env,
uint64_t va,
.using16k = using16k,
.using64k = using64k,
.tsz_oob = tsz_oob,
+ .ds = ds,
};
}
@@ -11528,10 +11574,19 @@ static bool get_phys_addr_lpae(CPUARMState *env,
uint64_t address,
* VTCR_EL2.SL0 field (whose interpretation depends on the page size)
*/
uint32_t sl0 = extract32(tcr->raw_tcr, 6, 2);
+ uint32_t sl2 = extract64(tcr->raw_tcr, 33, 1);
uint32_t startlevel;
bool ok;
- if (!aarch64 || stride == 9) {
+ /* SL2 is RES0 unless DS=1 & 4kb granule. */
+ if (param.ds && stride == 9 && sl2) {
+ if (sl0 != 0) {
+ level = 0;
+ fault_type = ARMFault_Translation;
+ goto do_fault;
+ }
+ startlevel = -1;
+ } else if (!aarch64 || stride == 9) {
/* AArch32 or 4KB pages */
startlevel = 2 - sl0;
@@ -11585,10 +11640,12 @@ static bool get_phys_addr_lpae(CPUARMState *env,
uint64_t address,
* for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0
* or an AddressSize fault is raised. So for v8 we extract those SBZ
* bits as part of the address, which will be checked via outputsize.
- * For AArch64, the address field always goes up to bit 47 (with extra
- * bits for FEAT_LPA placed elsewhere). AArch64 implies v8.
+ * For AArch64, the address field goes up to bit 47, or 49 with FEAT_LPA2;
+ * the highest bits of a 52-bit output are placed elsewhere.
*/
- if (arm_feature(env, ARM_FEATURE_V8)) {
+ if (param.ds) {
+ descaddrmask = MAKE_64BIT_MASK(0, 50);
+ } else if (arm_feature(env, ARM_FEATURE_V8)) {
descaddrmask = MAKE_64BIT_MASK(0, 48);
} else {
descaddrmask = MAKE_64BIT_MASK(0, 40);
@@ -11623,11 +11680,16 @@ static bool get_phys_addr_lpae(CPUARMState *env,
uint64_t address,
/*
* 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.
+ * of descriptor. For FEAT_LPA2 and effective DS, bits [51:50] of
+ * descaddr are in [9:8]. Otherwise, if descaddr is out of range,
+ * raise AddressSizeFault.
*/
if (outputsize > 48) {
- descaddr |= extract64(descriptor, 12, 4) << 48;
+ if (param.ds) {
+ descaddr |= extract64(descriptor, 8, 2) << 50;
+ } else {
+ descaddr |= extract64(descriptor, 12, 4) << 48;
+ }
} else if (descaddr >> outputsize) {
fault_type = ARMFault_AddressSize;
goto do_fault;
@@ -11721,7 +11783,17 @@ static bool get_phys_addr_lpae(CPUARMState *env,
uint64_t address,
assert(attrindx <= 7);
cacheattrs->attrs = extract64(mair, attrindx * 8, 8);
}
- cacheattrs->shareability = extract32(attrs, 6, 2);
+
+ /*
+ * For FEAT_LPA2 and effective DS, the SH field in the attributes
+ * was re-purposed for output address bits. The SH attribute in
+ * that case comes from TCR_ELx, which we extracted earlier.
+ */
+ if (param.ds) {
+ cacheattrs->shareability = param.sh;
+ } else {
+ cacheattrs->shareability = extract32(attrs, 6, 2);
+ }
*phys_ptr = descaddr;
*page_size_ptr = page_size;
--
2.25.1
- [PULL 14/26] target/arm: Honor TCR_ELx.{I}PS, (continued)
- [PULL 14/26] target/arm: Honor TCR_ELx.{I}PS, Peter Maydell, 2022/03/02
- [PULL 11/26] target/arm: Move arm_pamax out of line, Peter Maydell, 2022/03/02
- [PULL 17/26] target/arm: Implement FEAT_LPA, Peter Maydell, 2022/03/02
- [PULL 04/26] hw/i2c: flatten pca954x mux device, Peter Maydell, 2022/03/02
- [PULL 06/26] target/arm: Fix early free of TCG temp in handle_simd_shift_fpint_conv(), Peter Maydell, 2022/03/02
- [PULL 01/26] mps3-an547: Add missing user ahb interfaces, Peter Maydell, 2022/03/02
- [PULL 05/26] target/arm: Support PSCI 1.1 and SMCCC 1.0, Peter Maydell, 2022/03/02
- [PULL 15/26] target/arm: Prepare DBGBVR and DBGWVR for FEAT_LVA, Peter Maydell, 2022/03/02
- [PULL 18/26] target/arm: Extend arm_fi_to_lfsc to level -1, Peter Maydell, 2022/03/02
- [PULL 22/26] target/arm: Advertise all page sizes for -cpu max, Peter Maydell, 2022/03/02
- [PULL 23/26] target/arm: Implement FEAT_LPA2,
Peter Maydell <=
- [PULL 25/26] ui/cocoa.m: Fix updateUIInfo threading issues, Peter Maydell, 2022/03/02
- [PULL 16/26] target/arm: Implement FEAT_LVA, Peter Maydell, 2022/03/02
- [PULL 19/26] target/arm: Introduce tlbi_aa64_get_range, Peter Maydell, 2022/03/02
- [PULL 24/26] target/arm: Report KVM's actual PSCI version to guest in dtb, Peter Maydell, 2022/03/02
- [PULL 13/26] target/arm: Use MAKE_64BIT_MASK to compute indexmask, Peter Maydell, 2022/03/02
- [PULL 20/26] target/arm: Fix TLBIRange.base for 16k and 64k pages, Peter Maydell, 2022/03/02
- [PULL 21/26] target/arm: Validate tlbi TG matches translation granule in use, Peter Maydell, 2022/03/02
- [PULL 26/26] ui/cocoa.m: Remove unnecessary NSAutoreleasePools, Peter Maydell, 2022/03/02
- Re: [PULL 00/26] target-arm queue, Peter Maydell, 2022/03/03