FEAT_MTE_TAGGED_FAR is a feature required for MTE4. The feature
guarantees that the full address (including tag bits) is reported after
a SEGV_MTESERR, and advertises itself in the ID_AA64PFR2_EL1 system
register. QEMU was already reporting the full address, so this commit
simply advertises the feature by setting that register, and unsets the
register if MTE is disabled.

Signed-off-by: Gabriel Brookman <[email protected]>
---
This patch is the first step toward implementing ARM's Enhanced Memory
Tagging Extension (MTE4). MTE4 guarantees the presence of several
subfeatures: FEAT_MTE_CANONICAL_TAGS, FEAT_MTE_TAGGED_FAR,
FEAT_MTE_STORE_ONLY, FEAT_MTE_NO_ADDRESS_TAGS, and FEAT_MTE_PERM,
none of which are currently implemented in QEMU.

According to the ARM ARM, the presence of any of these features (except
FEAT_MTE_PERM) implies the presence of all the others. For simplicity
and ease of review, I plan to introduce them one at a time. This first
patch focuses on FEAT_MTE_TAGGED_FAR.

FEAT_MTE_TAGGED_FAR guarantees that the full fault address (including
tag bits) is reported after a SEGV_MTESERR, and exposes itself in the
ID_AA64PFR2_EL1 register. QEMU already reports the full address in this
case, so this change only advertises the feature by setting the
appropriate field in ID_AA64PFR2_EL1. The field is cleared when MTE
support is disabled or rolled back to instruction-only.

Testing:
- Verified in system mode that the MTEFAR field in ID_AA64PFR2_EL1
is set to 1 when running with mte=on and cleared with mte=off.
- Verified in user mode test that SEGV_MTESERR faults report the full
tagged address as expected.

I didn’t include these checks as formal tests since the functionality is
simple, but I can add them in follow-up versions if reviewers prefer.

Follow-up patches will implement the remaining MTE4 subfeatures listed
above.

Thanks,
Gabriel Brookman
---
 target/arm/cpu.c       | 4 +++-
 target/arm/tcg/cpu64.c | 4 ++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 39292fb9bc..804e70b235 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2020,6 +2020,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error 
**errp)
          */
         if (tcg_enabled() && cpu->tag_memory == NULL) {
             FIELD_DP64_IDREG(isar, ID_AA64PFR1, MTE, 1);
+            FIELD_DP64_IDREG(isar, ID_AA64PFR2, MTEFAR, 0);
         }
 
         /*
@@ -2027,7 +2028,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error 
**errp)
          * enabled on the guest (i.e mte=off), clear guest's MTE bits."
          */
         if (kvm_enabled() && !cpu->kvm_mte) {
-                FIELD_DP64_IDREG(isar, ID_AA64PFR1, MTE, 0);
+            FIELD_DP64_IDREG(isar, ID_AA64PFR1, MTE, 0);
+            FIELD_DP64_IDREG(isar, ID_AA64PFR2, MTEFAR, 0);
         }
 #endif
     }
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 6871956382..27f0b43256 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1283,6 +1283,10 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1);       /* FEAT_GCS */
     SET_IDREG(isar, ID_AA64PFR1, t);
 
+    t = GET_IDREG(isar, ID_AA64PFR2);
+    t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 1);    /* FEAT_MTE_TAGGED_FAR */
+    SET_IDREG(isar, ID_AA64PFR2, t);
+
     t = GET_IDREG(isar, ID_AA64MMFR0);
     t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */
     t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1);   /* 16k pages supported */

---
base-commit: e9c692eabbbb7f395347605a6ef33a32d398ea25
change-id: 20251104-feat-mte-tagged-far-c8d302a888ad

Best regards,
-- 
Gabriel Brookman <[email protected]>


Reply via email to