Virtual address canonicity checks should ignore mismatch in tag bits
during translation step if MTX is set.
Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
target/arm/helper.c | 6 +++++-
target/arm/internals.h | 1 +
target/arm/ptw.c | 28 +++++++++++++++++++++++++---
3 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 56858367fd..a61944dedd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9747,7 +9747,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
{
uint64_t tcr = regime_tcr(env, mmu_idx);
bool epd, hpd, tsz_oob, ds, ha, hd, pie = false;
- bool aie = false;
+ bool aie, mtx = false;
int select, tsz, tbi, max_tsz, min_tsz, ps, sh;
ARMGranuleSize gran;
ARMCPU *cpu = env_archcpu(env);
@@ -9784,6 +9784,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
ha = extract32(tcr, 21, 1) && cpu_isar_feature(aa64_hafs, cpu);
hd = extract32(tcr, 22, 1) && cpu_isar_feature(aa64_hdbs, cpu);
ds = extract64(tcr, 32, 1);
+ mtx = extract64(tcr, 33, 1) && cpu_isar_feature(aa64_mte_mtx, cpu);
} else {
bool e0pd;
@@ -9799,6 +9800,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
sh = extract32(tcr, 12, 2);
hpd = extract64(tcr, 41, 1);
e0pd = extract64(tcr, 55, 1);
+ mtx = extract64(tcr, 60, 1) && cpu_isar_feature(aa64_mte_mtx, cpu);
} else {
tsz = extract32(tcr, 16, 6);
gran = tg1_to_gran_size(extract32(tcr, 30, 2));
@@ -9806,6 +9808,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
sh = extract32(tcr, 28, 2);
hpd = extract64(tcr, 42, 1);
e0pd = extract64(tcr, 56, 1);
+ mtx = extract64(tcr, 61, 1) && cpu_isar_feature(aa64_mte_mtx, cpu);
}
ps = extract64(tcr, 32, 3);
ha = extract64(tcr, 39, 1) && cpu_isar_feature(aa64_hafs, cpu);
@@ -9905,6 +9908,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
.gran = gran,
.pie = pie,
.aie = aie,
+ .mtx = mtx,
};
}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 52597a351c..2c4369cc16 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1396,6 +1396,7 @@ typedef struct ARMVAParameters {
ARMGranuleSize gran : 2;
bool pie : 1;
bool aie : 1;
+ bool mtx : 1;
} ARMVAParameters;
/**
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index d381413ef7..e31b3085f8 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -1929,7 +1929,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
* validation to do here.
*/
if (inputsize < addrsize) {
- uint64_t top_bits = sextract64(address, inputsize,
+ /*
+ * If MTX is enabled, bits 56-59 aren't checked for canonicity
+ * during translation, since they will later be checked during
+ * the tag check step.
+ */
+ uint64_t masked_address = address;
+ if (param.mtx) {
+ masked_address = deposit64(address, 56, 4, param.select * 0xf);
+ }
+ uint64_t top_bits = sextract64(masked_address, inputsize,
addrsize - inputsize);
if (-top_bits != param.select) {
/* The gap between the two regions is a Translation fault */
@@ -3481,15 +3490,28 @@ static bool get_phys_addr_disabled(CPUARMState *env,
if (arm_el_is_aa64(env, r_el)) {
int pamax = arm_pamax(env_archcpu(env));
uint64_t tcr = env->cp15.tcr_el[r_el];
- int addrtop, tbi;
+ int addrtop, tbi, mtx;
+ bool bit55;
tbi = aa64_va_parameter_tbi(tcr, mmu_idx);
+ mtx = aa64_va_parameter_mtx(tcr, mmu_idx);
if (access_type == MMU_INST_FETCH) {
tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx);
}
- tbi = (tbi >> extract64(address, 55, 1)) & 1;
+ bit55 = extract64(address, 55, 1);
+ tbi = (tbi >> bit55) & 1;
+ mtx = (mtx >> bit55) & 1;
addrtop = (tbi ? 55 : 63);
+ /*
+ * With MTX enabled, bits 56-59 are not checked according to
+ * AArch64.S1DisabledOutput.
+ */
+ if (cpu_isar_feature(aa64_mte_mtx, env_archcpu(env)) && mtx &&
+ access_type != MMU_INST_FETCH) {
+ address = deposit64(address, 56, 4, ((mmu_idx) && bit55) * 0xF);
+ }
+
if (extract64(address, pamax, addrtop - pamax + 1) != 0) {
fi->type = ARMFault_AddressSize;
fi->level = 0;
--
2.52.0