qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v2 00/10] target/arm: add support for MTE4
@ 2025-11-17  1:40 Gabriel Brookman
  2025-11-17  1:40 ` [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max Gabriel Brookman
                   ` (9 more replies)
  0 siblings, 10 replies; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

This patch implements 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 patch
handles all features except FEAT_MTE_PERM, with the plan to introduce
FEAT_MTE_PERM in the next iteration of the patch.

Testing:
  - To test this code, I used the tests included, plus modifications to
    enable the EL1 control bits for the features being tested. These
    features rely on EL1 control bits, which cannot be set in user-mode.
    Please advise on the preferred strategy for testing EL1-dependent
    behavior in user-mode tests.

The next version of this patch will include the MTE_PERM feature, since
MTE4 guarantees its existence.

Thanks,
Gabriel Brookman

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3116
---
Changes in v2:
- Added tests for STORE_ONLY.
- Refined commit messages.
- Added FEAT_MTE_CANONICAL_TAGS and FEAT_MTE_NO_ADDRESS_TAGS + tests.
- fixed TCSO bit macro names.
- Link to v1: https://lore.kernel.org/qemu-devel/20251111-feat-mte4-v1-0-72ef5cf276f9@gmail.com

---
Gabriel Brookman (10):
      target/arm: explicitly disable MTE4 for max
      tests/tcg: added test for MTE FAR
      target/arm: add TCSO bitmasks to SCTLR
      target/arm: add FEAT_MTE_STORE_ONLY logic
      tests/tcg: added test for MTE write-only
      target/arm: add canonical and no-address tag logic
      target/arm: ldg on canonical tag loads the tag
      target/arm: storing to canonical tags faults
      tests/tcg: added test for MTE canonical and NAT
      docs: added MTE4 features to docs

 docs/system/arm/emulation.rst     |  4 ++
 target/arm/cpu.h                  |  2 +
 target/arm/helper.c               |  4 +-
 target/arm/internals.h            | 40 +++++++++++++++++
 target/arm/tcg/cpu64.c            |  8 ++++
 target/arm/tcg/mte_helper.c       | 95 ++++++++++++++++++++++++++++++++++++++-
 tests/tcg/aarch64/Makefile.target |  2 +-
 tests/tcg/aarch64/mte-10.c        | 55 +++++++++++++++++++++++
 tests/tcg/aarch64/mte-11.c        | 46 +++++++++++++++++++
 tests/tcg/aarch64/mte-9.c         | 48 ++++++++++++++++++++
 10 files changed, 299 insertions(+), 5 deletions(-)
---
base-commit: 9febfa94b69b7146582c48a868bd2330ac45037f
change-id: 20251109-feat-mte4-6740a6202e83

Best regards,
-- 
Gabriel Brookman <brookmangabriel@gmail.com>



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17  9:48   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 02/10] tests/tcg: added test for MTE FAR Gabriel Brookman
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

Previously, the bits used to advertise the various MTE4 features were
not explicitly set for -cpu max. This commit calls out these bits and
explicitly unsets them. At the end of the patch series, a second commit
will explicitly set all of them.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/tcg/cpu64.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 6871956382..ca9557f4cf 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1281,8 +1281,16 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_3 */
     t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1);       /* FEAT_NMI */
     t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1);       /* FEAT_GCS */
+    t = FIELD_DP64(t, ID_AA64PFR1,
+            MTEX, 0);   /* FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */
     SET_IDREG(isar, ID_AA64PFR1, t);
 
+    t = GET_IDREG(isar, ID_AA64PFR2);
+    t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 0);    /* FEAT_MTE_TAGGED_FAR */
+    t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 0);   /* FEAT_MTE_STORE_ONLY */
+    t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 0);    /* FEAT_MTE_PERM */
+    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 */

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 02/10] tests/tcg: added test for MTE FAR
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
  2025-11-17  1:40 ` [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17  9:51   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 03/10] target/arm: add TCSO bitmasks to SCTLR Gabriel Brookman
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

This functionality was previously enabled but not advertised or tested.
This commit adds a new test, mte-9, that tests the code for proper
full-address reporting. FEAT_MTE_TAGGED_FAR requires that FAR_ELx
report the full logical address, including tag bits.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 tests/tcg/aarch64/Makefile.target |  2 +-
 tests/tcg/aarch64/mte-9.c         | 48 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 9fa8687453..b491cfb5e1 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -64,7 +64,7 @@ AARCH64_TESTS += bti-2
 
 # MTE Tests
 ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
-AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8
+AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9
 mte-%: CFLAGS += $(CROSS_CC_HAS_ARMV8_MTE)
 endif
 
diff --git a/tests/tcg/aarch64/mte-9.c b/tests/tcg/aarch64/mte-9.c
new file mode 100644
index 0000000000..9626a90c13
--- /dev/null
+++ b/tests/tcg/aarch64/mte-9.c
@@ -0,0 +1,48 @@
+/*
+ * Memory tagging, full-address reporting.
+ *
+ * Copyright (c) 2021 Linaro Ltd
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "mte.h"
+
+static void *faulting_ptr;
+
+void pass(int sig, siginfo_t *info, void *uc)
+{
+    assert(faulting_ptr == info->si_addr);
+    exit(0);
+}
+
+int main(int ac, char **av)
+{
+    struct sigaction sa;
+    int *p0, *p1, *p2;
+    long excl = 1;
+
+    enable_mte(PR_MTE_TCF_SYNC);
+    p0 = alloc_mte_mem(sizeof(*p0));
+
+    /* Create two differently tagged pointers. */
+    asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
+    asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1));
+    assert(excl != 1);
+    asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl));
+    assert(p1 != p2);
+
+    /* Store the tag from the first pointer.  */
+    asm("stg %0, [%0]" : : "r"(p1));
+
+    *p1 = 0;
+
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = pass;
+    sa.sa_flags = SA_SIGINFO;
+    sigaction(SIGSEGV, &sa, NULL);
+
+    faulting_ptr = p2;
+    *p2 = 0;
+
+    abort();
+}

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 03/10] target/arm: add TCSO bitmasks to SCTLR
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
  2025-11-17  1:40 ` [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max Gabriel Brookman
  2025-11-17  1:40 ` [PATCH RFC v2 02/10] tests/tcg: added test for MTE FAR Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17 15:14   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 04/10] target/arm: add FEAT_MTE_STORE_ONLY logic Gabriel Brookman
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

These are the bitmasks used to control the FEAT_MTE_STORE_ONLY feature.
They are now named and setting these fields of SCTLR is ignored if MTE
is disabled, as per convention.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/cpu.h    | 2 ++
 target/arm/helper.c | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 39f2b2e54d..6fe85b5e3a 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1424,6 +1424,8 @@ void pmu_init(ARMCPU *cpu);
 #define SCTLR_EnAS0   (1ULL << 55) /* FEAT_LS64_ACCDATA */
 #define SCTLR_EnALS   (1ULL << 56) /* FEAT_LS64 */
 #define SCTLR_EPAN    (1ULL << 57) /* FEAT_PAN3 */
+#define SCTLR_TCSO0    (1ULL << 58) /* FEAT_MTE_STORE_ONLY */
+#define SCTLR_TCSO    (1ULL << 59) /* FEAT_MTE_STORE_ONLY */
 #define SCTLR_EnTP2   (1ULL << 60) /* FEAT_SME */
 #define SCTLR_NMI     (1ULL << 61) /* FEAT_NMI */
 #define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 27ebc6f29b..17ddfaccf8 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3364,10 +3364,10 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
 
     if (ri->state == ARM_CP_STATE_AA64 && !cpu_isar_feature(aa64_mte, cpu)) {
         if (ri->opc1 == 6) { /* SCTLR_EL3 */
-            value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA);
+            value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA | SCTLR_TCSO);
         } else {
             value &= ~(SCTLR_ITFSB | SCTLR_TCF0 | SCTLR_TCF |
-                       SCTLR_ATA0 | SCTLR_ATA);
+                       SCTLR_ATA0 | SCTLR_ATA | SCTLR_TCSO | SCTLR_TCSO0);
         }
     }
 

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 04/10] target/arm: add FEAT_MTE_STORE_ONLY logic
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (2 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 03/10] target/arm: add TCSO bitmasks to SCTLR Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17 15:26   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 05/10] tests/tcg: added test for MTE write-only Gabriel Brookman
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

This feature automatically succeeds tag checks on load instructions when
the appropriate SCTLR_TCSO register for the current exception level is
set. Find information on this feature in the "Tag Checking" section of
the ARM ARM, Memory Tagging Extension chapter.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/tcg/mte_helper.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index bb48fe359b..f9fd6fd408 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -865,8 +865,30 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
     return 0;
 }
 
+static bool mte_store_only_active(CPUARMState *env)
+{
+    int el = arm_current_el(env);
+    if (el) {
+        if (SCTLR_TCSO & env->cp15.sctlr_el[el]) {
+            return true;
+        }
+    } else {
+        if ((HCR_E2H & env->cp15.hcr_el2) &&
+            (SCTLR_TCSO0 & env->cp15.sctlr_el[2])) {
+            return true;
+        } else if (SCTLR_TCSO0 & env->cp15.sctlr_el[1]) {
+            return true;
+        }
+    }
+    return false;
+}
+
 uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra)
 {
+    if (!FIELD_EX32(desc, MTEDESC, WRITE) && mte_store_only_active(env)) {
+        return useronly_clean_ptr(ptr);
+    }
+
     uint64_t fault;
     int ret = mte_probe_int(env, desc, ptr, ra, &fault);
 

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 05/10] tests/tcg: added test for MTE write-only
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (3 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 04/10] target/arm: add FEAT_MTE_STORE_ONLY logic Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17 15:39   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 06/10] target/arm: add canonical and no-address tag logic Gabriel Brookman
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

This test cannot be run in user-mode because the control bit that
enables this feature is only writable at EL1.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 tests/tcg/aarch64/Makefile.target |  2 +-
 tests/tcg/aarch64/mte-10.c        | 55 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index b491cfb5e1..6203ac9b51 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -64,7 +64,7 @@ AARCH64_TESTS += bti-2
 
 # MTE Tests
 ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
-AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9
+AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 mte-10
 mte-%: CFLAGS += $(CROSS_CC_HAS_ARMV8_MTE)
 endif
 
diff --git a/tests/tcg/aarch64/mte-10.c b/tests/tcg/aarch64/mte-10.c
new file mode 100644
index 0000000000..0fa3f97e1d
--- /dev/null
+++ b/tests/tcg/aarch64/mte-10.c
@@ -0,0 +1,55 @@
+/*
+ * Memory tagging, write-only tag checking
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "mte.h"
+
+void pass(int sig, siginfo_t *info, void *uc)
+{
+    exit(0);
+}
+
+int main(int ac, char **av)
+{
+    struct sigaction sa;
+    int *p0, *p1, *p2;
+    long excl = 1;
+
+    /*
+     * NOTE FOR REVIEWERS: to run this test locally, I modified
+     * enable_mte to also activate write-only tag checking by writing
+     * to ID_AA64PFR2_EL1. I am not sure how to modify the test so that
+     * it works without that modification. Input appreciated.
+     */
+    enable_mte(PR_MTE_TCF_SYNC);
+    p0 = alloc_mte_mem(sizeof(*p0));
+
+    /* Create two differently tagged pointers. */
+    asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
+    asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1));
+    assert(excl != 1);
+    asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl));
+    assert(p1 != p2);
+
+    /* Store the tag from the first pointer.  */
+    asm("stg %0, [%0]" : : "r"(p1));
+
+    /*
+     * We write to p1 (stg above makes this check pass) and read from
+     * p2 (improperly tagged, but since it's a read, we don't care).
+     */
+    *p1 = *p2;
+
+    /* enable handler */
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = pass;
+    sa.sa_flags = SA_SIGINFO;
+    sigaction(SIGSEGV, &sa, NULL);
+
+    /* now we write to badly checked p2, should fault. */
+    *p2 = 0;
+
+    abort();
+}

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 06/10] target/arm: add canonical and no-address tag logic
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (4 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 05/10] tests/tcg: added test for MTE write-only Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17 16:18   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag Gabriel Brookman
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

This feature causes tag checks to compare logical address tags against
their canonical form rather than against allocation tags. Described in
the ARM ARM section "Logical Address Tagging".

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/internals.h      | 40 ++++++++++++++++++++++++++++++++++++++++
 target/arm/tcg/mte_helper.c | 12 ++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index 75677945af..5f0bcdaaac 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1633,6 +1633,46 @@ static inline bool tcma_check(uint32_t desc, int bit55, int ptr_tag)
     return tcma && match;
 }
 
+/* Return whether or not the second nibble of a VA matches bit 55.  */
+static inline bool tag_is_canonical(int ptr_tag, int bit55)
+{
+    return ((ptr_tag + bit55) & 0xf) == 0;
+}
+
+/* Return true if mtx bits mean that the access is canonically checked.  */
+static inline bool mtx_check(CPUARMState *env, bool bit55)
+{
+    /*
+     * the MTX bits used in EL0 are those used in whichever EL is used
+     * for the supervisor. The EL that contains the supervisor uses
+     * bits 60 and 61 (MTX0 and MTX1), while the other ELs that aren't
+     * used by the supervisor.
+     */
+    int el = arm_current_el(env);
+    if (el == 0) {
+        if (HCR_E2H & env->cp15.hcr_el2) {
+            return (1l << (60 + bit55)) & env->cp15.tcr_el[2];
+        } else {
+            return (1l << (60 + bit55)) & env->cp15.tcr_el[1];
+        }
+    } else if (el == 1) {
+        if (HCR_E2H & env->cp15.hcr_el2) {
+            g_assert_not_reached();
+        } else {
+            return (1l << (60 + bit55)) & env->cp15.tcr_el[1];
+        }
+    } else if (el == 2) {
+        if (HCR_E2H & env->cp15.hcr_el2) {
+            return (1l << (60 + bit55)) & env->cp15.tcr_el[2];
+        } else {
+            return (1l << 33) & env->cp15.tcr_el[2];
+        }
+    } else if (el == 3) {
+        return (1l << 33) & env->cp15.tcr_el[3];
+    }
+    return false;
+}
+
 /*
  * For TBI, ideally, we would do nothing.  Proper behaviour on fault is
  * for the tag to be present in the FAR_ELx register.  But for user-only
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index f9fd6fd408..513ee8d6a1 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -799,6 +799,10 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
         return 1;
     }
 
+    if (mtx_check(env, bit55)) {
+        return tag_is_canonical(ptr_tag, bit55);
+    }
+
     mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX);
     type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD;
     sizem1 = FIELD_EX32(desc, MTEDESC, SIZEM1);
@@ -962,6 +966,14 @@ uint64_t HELPER(mte_check_zva)(CPUARMState *env, uint32_t desc, uint64_t ptr)
         goto done;
     }
 
+    if (mtx_check(env, bit55)) {
+        if (tag_is_canonical(ptr_tag, bit55)) {
+            goto done;
+        }
+        mte_check_fail(env, desc, ptr, ra);
+    }
+
+
     /*
      * In arm_cpu_realizefn, we asserted that dcz > LOG2_TAG_GRANULE+1,
      * i.e. 32 bytes, which is an unreasonably small dcz anyway, to make

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (5 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 06/10] target/arm: add canonical and no-address tag logic Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-17 16:26   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 08/10] target/arm: storing to canonical tags faults Gabriel Brookman
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

According to ARM ARM, section "Memory Tagging Region Types", loading
tags from canonically tagged regions should use the canonical tags, not
allocation tags.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/tcg/mte_helper.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index 513ee8d6a1..ddb68e11fc 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -279,9 +279,14 @@ uint64_t HELPER(ldg)(CPUARMState *env, uint64_t ptr, uint64_t xt)
     mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_LOAD, 1,
                              MMU_DATA_LOAD, GETPC());
 
-    /* Load if page supports tags. */
+    /* Load if page supports tags. Set to canonical value if MTX is set. */
     if (mem) {
-        rtag = load_tag1(ptr, mem);
+        uint64_t bit55 = extract64(ptr, 55, 1);
+        if (mtx_check(env, bit55)) {
+            rtag = 0xF * bit55;
+        } else {
+            rtag = load_tag1(ptr, mem);
+        }
     }
 
     return address_with_allocation_tag(xt, rtag);
@@ -444,6 +449,11 @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr)
         return 0;
     }
 
+    if (mtx_check(env, extract64(ptr, 55, 1))) {
+        shift = extract64(ptr, LOG2_TAG_GRANULE, 4) * 4;
+        return (~0) << shift;
+    }
+
     /*
      * The ordering of elements within the word corresponds to
      * a little-endian operation.  Computation of shift comes from

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 08/10] target/arm: storing to canonical tags faults
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (6 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-19  7:48   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 09/10] tests/tcg: added test for MTE canonical and NAT Gabriel Brookman
  2025-11-17  1:40 ` [PATCH RFC v2 10/10] docs: added MTE4 features to docs Gabriel Brookman
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

According to ARM ARM, section "Memory region tagging types", tag-store
instructions targeting canonically tagged regions cause a stage 1
permission fault.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/tcg/mte_helper.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index ddb68e11fc..9eb3777fe2 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -196,6 +196,23 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
 #endif
 }
 
+static void canonical_tag_write_fail(CPUARMState *env,
+                                uint64_t dirty_ptr, uintptr_t ra)
+{
+    uint64_t syn;
+
+    env->exception.vaddress = dirty_ptr;
+
+    /* bit 42 is TnD */
+    syn = (1l << 42) | syn_data_abort_no_iss(arm_current_el(env) != 0,
+            0, 0, 0, 0, 1, 0b1110);
+    raise_exception_ra(env, EXCP_DATA_ABORT, syn, exception_target_el(env), ra);
+    g_assert_not_reached();
+
+}
+
+
+
 static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
                                    uint64_t ptr, MMUAccessType ptr_access,
                                    int ptr_size, MMUAccessType tag_access,
@@ -332,6 +349,11 @@ static inline void do_stg(CPUARMState *env, uint64_t ptr, uint64_t xt,
     int mmu_idx = arm_env_mmu_index(env);
     uint8_t *mem;
 
+    if (mtx_check(env, 1 & (ptr >> 55))) {
+        canonical_tag_write_fail(env, ptr, ra);
+        return;
+    }
+
     check_tag_aligned(env, ptr, ra);
 
     /* Trap if accessing an invalid page.  */
@@ -359,6 +381,11 @@ void HELPER(stg_stub)(CPUARMState *env, uint64_t ptr)
     int mmu_idx = arm_env_mmu_index(env);
     uintptr_t ra = GETPC();
 
+    if (mtx_check(env, 1 & (ptr >> 55))) {
+        canonical_tag_write_fail(env, ptr, ra);
+        return;
+    }
+
     check_tag_aligned(env, ptr, ra);
     probe_write(env, ptr, TAG_GRANULE, mmu_idx, ra);
 }
@@ -370,6 +397,11 @@ static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt,
     int tag = allocation_tag_from_addr(xt);
     uint8_t *mem1, *mem2;
 
+    if (mtx_check(env, 1 & (ptr >> 55))) {
+        canonical_tag_write_fail(env, ptr, ra);
+        return;
+    }
+
     check_tag_aligned(env, ptr, ra);
 
     /*
@@ -418,6 +450,11 @@ void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr)
     uintptr_t ra = GETPC();
     int in_page = -(ptr | TARGET_PAGE_MASK);
 
+    if (mtx_check(env, 1 & (ptr >> 55))) {
+        canonical_tag_write_fail(env, ptr, ra);
+        return;
+    }
+
     check_tag_aligned(env, ptr, ra);
 
     if (likely(in_page >= 2 * TAG_GRANULE)) {
@@ -504,6 +541,11 @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val)
 
     ptr = QEMU_ALIGN_DOWN(ptr, gm_bs_bytes);
 
+    if (mtx_check(env, 1 & (ptr >> 55))) {
+        canonical_tag_write_fail(env, ptr, ra);
+        return;
+    }
+
     /* Trap if accessing an invalid page.  */
     tag_mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE,
                                  gm_bs_bytes, MMU_DATA_LOAD, ra);
@@ -550,6 +592,11 @@ void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val)
     intptr_t dcz_bytes, tag_bytes;
     uint8_t *mem;
 
+    if (mtx_check(env, 1 & (ptr >> 55))) {
+        canonical_tag_write_fail(env, ptr, ra);
+        return;
+    }
+
     /*
      * In arm_cpu_realizefn, we assert that dcz > LOG2_TAG_GRANULE+1,
      * i.e. 32 bytes, which is an unreasonably small dcz anyway,

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 09/10] tests/tcg: added test for MTE canonical and NAT
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (7 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 08/10] target/arm: storing to canonical tags faults Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-19  7:49   ` Richard Henderson
  2025-11-17  1:40 ` [PATCH RFC v2 10/10] docs: added MTE4 features to docs Gabriel Brookman
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

This test cannot run in user-mode because the control bit that enables
this feature is only writable at EL1.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 tests/tcg/aarch64/Makefile.target |  2 +-
 tests/tcg/aarch64/mte-11.c        | 46 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 6203ac9b51..141c9db9c4 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -64,7 +64,7 @@ AARCH64_TESTS += bti-2
 
 # MTE Tests
 ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
-AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 mte-10
+AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 mte-10 mte-11
 mte-%: CFLAGS += $(CROSS_CC_HAS_ARMV8_MTE)
 endif
 
diff --git a/tests/tcg/aarch64/mte-11.c b/tests/tcg/aarch64/mte-11.c
new file mode 100644
index 0000000000..86f2206e41
--- /dev/null
+++ b/tests/tcg/aarch64/mte-11.c
@@ -0,0 +1,46 @@
+/*
+ * Memory tagging, canonical tag checking
+ *
+ * Copyright (c) 2021 Linaro Ltd
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "mte.h"
+
+void pass(int sig, siginfo_t *info, void *uc)
+{
+    assert(info->si_code == SEGV_MTESERR);
+    exit(0);
+}
+
+int main(int ac, char **av)
+{
+    struct sigaction sa;
+    int *p0, *p1, *p2;
+    long excl = 1;
+
+    /*
+     * NOTE FOR REVIEWERS: to run this test locally, I modified
+     * enable_mte to also activate canonical tagging checking by writing
+     * to the appropriate MTX control bits. I am not sure how to modify
+     * the test so that it works without that modification. Input appreciated.
+     */
+    enable_mte(PR_MTE_TCF_SYNC);
+    p0 = alloc_mte_mem(sizeof(*p0));
+
+    /* shouldn't fault on a canonical ptr */
+    *p0 = 32;
+
+    /* decanonicalize ptr */
+    p0 = (int *) (((long) p0) | (1ll << 56));
+
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = pass;
+    sa.sa_flags = SA_SIGINFO;
+    sigaction(SIGSEGV, &sa, NULL);
+
+    /* should fault on our modified ptr */
+    *p0 = 64;
+
+    abort();
+}

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH RFC v2 10/10] docs: added MTE4 features to docs
  2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
                   ` (8 preceding siblings ...)
  2025-11-17  1:40 ` [PATCH RFC v2 09/10] tests/tcg: added test for MTE canonical and NAT Gabriel Brookman
@ 2025-11-17  1:40 ` Gabriel Brookman
  2025-11-19  7:51   ` Richard Henderson
  9 siblings, 1 reply; 22+ messages in thread
From: Gabriel Brookman @ 2025-11-17  1:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm, Gabriel Brookman

The implemented MTE4 features are now present in
docs/system/arm/emulation.rst

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 docs/system/arm/emulation.rst | 4 ++++
 target/arm/tcg/cpu64.c        | 8 ++++----
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 31a5878a8f..62b66b2227 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -106,6 +106,10 @@ the following architecture extensions:
 - FEAT_MTE3 (MTE Asymmetric Fault Handling)
 - FEAT_MTE_ASYM_FAULT (Memory tagging asymmetric faults)
 - FEAT_MTE_ASYNC (Asynchronous reporting of Tag Check Fault)
+- FEAT_MTE_TAGGED_FAR (Full address reporting of Tag Check Fault)
+- FEAT_MTE_STORE_ONLY (Store-only tag checking)
+- FEAT_MTE_CANONICAL_TAGS (Canonical tag checking)
+- FEAT_MTE_NO_ADDRESS_TAGS (Address tagging disabled)
 - FEAT_NMI (Non-maskable Interrupt)
 - FEAT_NV (Nested Virtualization)
 - FEAT_NV2 (Enhanced nested virtualization support)
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index ca9557f4cf..7d003706a0 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1282,13 +1282,13 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1);       /* FEAT_NMI */
     t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1);       /* FEAT_GCS */
     t = FIELD_DP64(t, ID_AA64PFR1,
-            MTEX, 0);   /* FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */
+            MTEX, 1);   /* FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */
     SET_IDREG(isar, ID_AA64PFR1, t);
 
     t = GET_IDREG(isar, ID_AA64PFR2);
-    t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 0);    /* FEAT_MTE_TAGGED_FAR */
-    t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 0);   /* FEAT_MTE_STORE_ONLY */
-    t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 0);    /* FEAT_MTE_PERM */
+    t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 1);    /* FEAT_MTE_TAGGED_FAR */
+    t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 1);   /* FEAT_MTE_STORE_ONLY */
+    t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 1);    /* FEAT_MTE_PERM */
     SET_IDREG(isar, ID_AA64PFR2, t);
 
     t = GET_IDREG(isar, ID_AA64MMFR0);

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max
  2025-11-17  1:40 ` [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max Gabriel Brookman
@ 2025-11-17  9:48   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-17  9:48 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> Previously, the bits used to advertise the various MTE4 features were
> not explicitly set for -cpu max. This commit calls out these bits and
> explicitly unsets them. At the end of the patch series, a second commit
> will explicitly set all of them.
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   target/arm/tcg/cpu64.c | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
> index 6871956382..ca9557f4cf 100644
> --- a/target/arm/tcg/cpu64.c
> +++ b/target/arm/tcg/cpu64.c
> @@ -1281,8 +1281,16 @@ void aarch64_max_tcg_initfn(Object *obj)
>       t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_3 */
>       t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1);       /* FEAT_NMI */
>       t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1);       /* FEAT_GCS */
> +    t = FIELD_DP64(t, ID_AA64PFR1,
> +            MTEX, 0);   /* FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */
>       SET_IDREG(isar, ID_AA64PFR1, t);
>   
> +    t = GET_IDREG(isar, ID_AA64PFR2);
> +    t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 0);    /* FEAT_MTE_TAGGED_FAR */
> +    t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 0);   /* FEAT_MTE_STORE_ONLY */
> +    t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 0);    /* FEAT_MTE_PERM */
> +    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 */
> 

They weren't explicitly set, but the whole ARMCPU structure, including the isar field, was 
zeroed upon object creation.  So I don't really see the point in this patch.

r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 02/10] tests/tcg: added test for MTE FAR
  2025-11-17  1:40 ` [PATCH RFC v2 02/10] tests/tcg: added test for MTE FAR Gabriel Brookman
@ 2025-11-17  9:51   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-17  9:51 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> This functionality was previously enabled but not advertised or tested.
> This commit adds a new test, mte-9, that tests the code for proper
> full-address reporting. FEAT_MTE_TAGGED_FAR requires that FAR_ELx
> report the full logical address, including tag bits.
> 
> Signed-off-by: Gabriel Brookman<brookmangabriel@gmail.com>
> ---
>   tests/tcg/aarch64/Makefile.target |  2 +-
>   tests/tcg/aarch64/mte-9.c         | 48 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 49 insertions(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 03/10] target/arm: add TCSO bitmasks to SCTLR
  2025-11-17  1:40 ` [PATCH RFC v2 03/10] target/arm: add TCSO bitmasks to SCTLR Gabriel Brookman
@ 2025-11-17 15:14   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-17 15:14 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> These are the bitmasks used to control the FEAT_MTE_STORE_ONLY feature.
> They are now named and setting these fields of SCTLR is ignored if MTE
> is disabled, as per convention.
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   target/arm/cpu.h    | 2 ++
>   target/arm/helper.c | 4 ++--
>   2 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 39f2b2e54d..6fe85b5e3a 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -1424,6 +1424,8 @@ void pmu_init(ARMCPU *cpu);
>   #define SCTLR_EnAS0   (1ULL << 55) /* FEAT_LS64_ACCDATA */
>   #define SCTLR_EnALS   (1ULL << 56) /* FEAT_LS64 */
>   #define SCTLR_EPAN    (1ULL << 57) /* FEAT_PAN3 */
> +#define SCTLR_TCSO0    (1ULL << 58) /* FEAT_MTE_STORE_ONLY */
> +#define SCTLR_TCSO    (1ULL << 59) /* FEAT_MTE_STORE_ONLY */
>   #define SCTLR_EnTP2   (1ULL << 60) /* FEAT_SME */

Indentation is off.

> @@ -3364,10 +3364,10 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>   
>       if (ri->state == ARM_CP_STATE_AA64 && !cpu_isar_feature(aa64_mte, cpu)) {
>           if (ri->opc1 == 6) { /* SCTLR_EL3 */
> -            value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA);
> +            value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA | SCTLR_TCSO);
>           } else {
>               value &= ~(SCTLR_ITFSB | SCTLR_TCF0 | SCTLR_TCF |
> -                       SCTLR_ATA0 | SCTLR_ATA);
> +                       SCTLR_ATA0 | SCTLR_ATA | SCTLR_TCSO | SCTLR_TCSO0);
>           }
>       }

You should be testing for FEAT_MTE_STORE_ONLY, not just plain MTE (since renamed MTE2).

Add the appropriate function to cpu-features.h.


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 04/10] target/arm: add FEAT_MTE_STORE_ONLY logic
  2025-11-17  1:40 ` [PATCH RFC v2 04/10] target/arm: add FEAT_MTE_STORE_ONLY logic Gabriel Brookman
@ 2025-11-17 15:26   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-17 15:26 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> This feature automatically succeeds tag checks on load instructions when
> the appropriate SCTLR_TCSO register for the current exception level is
> set. Find information on this feature in the "Tag Checking" section of
> the ARM ARM, Memory Tagging Extension chapter.
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   target/arm/tcg/mte_helper.c | 22 ++++++++++++++++++++++
>   1 file changed, 22 insertions(+)
> 
> diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
> index bb48fe359b..f9fd6fd408 100644
> --- a/target/arm/tcg/mte_helper.c
> +++ b/target/arm/tcg/mte_helper.c
> @@ -865,8 +865,30 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
>       return 0;
>   }
>   
> +static bool mte_store_only_active(CPUARMState *env)
> +{
> +    int el = arm_current_el(env);
> +    if (el) {
> +        if (SCTLR_TCSO & env->cp15.sctlr_el[el]) {
> +            return true;
> +        }
> +    } else {
> +        if ((HCR_E2H & env->cp15.hcr_el2) &&'

You can't test hcr_el2 directly, because SecEL2 might not exist when (Non-secure) EL2 
does.  However, this can be simplified using arm_sctlr():

     uint64_t sctlr = arm_sctlr(env, el);
     uint64_t test = el ? SCTLR_TCSO : SCTLR_TCSO0;
     return sctlr & test;


That said, we should cache this in TBFLAGS so that we don't generate the mte_check 
function call at runtime for reads.  See target/arm/tcg/hflags.c, s/MTE_ACTIVE/.


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 05/10] tests/tcg: added test for MTE write-only
  2025-11-17  1:40 ` [PATCH RFC v2 05/10] tests/tcg: added test for MTE write-only Gabriel Brookman
@ 2025-11-17 15:39   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-17 15:39 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> This test cannot be run in user-mode because the control bit that
> enables this feature is only writable at EL1.
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   tests/tcg/aarch64/Makefile.target |  2 +-
>   tests/tcg/aarch64/mte-10.c        | 55 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 56 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
> index b491cfb5e1..6203ac9b51 100644
> --- a/tests/tcg/aarch64/Makefile.target
> +++ b/tests/tcg/aarch64/Makefile.target
> @@ -64,7 +64,7 @@ AARCH64_TESTS += bti-2
>   
>   # MTE Tests
>   ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
> -AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9
> +AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 mte-10
>   mte-%: CFLAGS += $(CROSS_CC_HAS_ARMV8_MTE)
>   endif
>   
> diff --git a/tests/tcg/aarch64/mte-10.c b/tests/tcg/aarch64/mte-10.c
> new file mode 100644
> index 0000000000..0fa3f97e1d
> --- /dev/null
> +++ b/tests/tcg/aarch64/mte-10.c
> @@ -0,0 +1,55 @@
> +/*
> + * Memory tagging, write-only tag checking
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "mte.h"
> +
> +void pass(int sig, siginfo_t *info, void *uc)
> +{
> +    exit(0);
> +}
> +
> +int main(int ac, char **av)
> +{
> +    struct sigaction sa;
> +    int *p0, *p1, *p2;
> +    long excl = 1;
> +
> +    /*
> +     * NOTE FOR REVIEWERS: to run this test locally, I modified
> +     * enable_mte to also activate write-only tag checking by writing
> +     * to ID_AA64PFR2_EL1. I am not sure how to modify the test so that
> +     * it works without that modification. Input appreciated.
> +     */
> +    enable_mte(PR_MTE_TCF_SYNC);

You must

(1) Delay the patch adding the test case until after FEAT_MTE_STORE_ONLY is enabled 
(currently patch 10)

(2) Implement support for PR_MTE_STORE_ONLY in linux-user/.


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 06/10] target/arm: add canonical and no-address tag logic
  2025-11-17  1:40 ` [PATCH RFC v2 06/10] target/arm: add canonical and no-address tag logic Gabriel Brookman
@ 2025-11-17 16:18   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-17 16:18 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> This feature causes tag checks to compare logical address tags against
> their canonical form rather than against allocation tags. Described in
> the ARM ARM section "Logical Address Tagging".
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   target/arm/internals.h      | 40 ++++++++++++++++++++++++++++++++++++++++
>   target/arm/tcg/mte_helper.c | 12 ++++++++++++
>   2 files changed, 52 insertions(+)
> 
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 75677945af..5f0bcdaaac 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1633,6 +1633,46 @@ static inline bool tcma_check(uint32_t desc, int bit55, int ptr_tag)
>       return tcma && match;
>   }
>   
> +/* Return whether or not the second nibble of a VA matches bit 55.  */
> +static inline bool tag_is_canonical(int ptr_tag, int bit55)
> +{
> +    return ((ptr_tag + bit55) & 0xf) == 0;
> +}
> +
> +/* Return true if mtx bits mean that the access is canonically checked.  */
> +static inline bool mtx_check(CPUARMState *env, bool bit55)
> +{
> +    /*
> +     * the MTX bits used in EL0 are those used in whichever EL is used
> +     * for the supervisor. The EL that contains the supervisor uses
> +     * bits 60 and 61 (MTX0 and MTX1), while the other ELs that aren't
> +     * used by the supervisor.
> +     */
> +    int el = arm_current_el(env);
> +    if (el == 0) {
> +        if (HCR_E2H & env->cp15.hcr_el2) {
> +            return (1l << (60 + bit55)) & env->cp15.tcr_el[2];
> +        } else {
> +            return (1l << (60 + bit55)) & env->cp15.tcr_el[1];
> +        }
> +    } else if (el == 1) {
> +        if (HCR_E2H & env->cp15.hcr_el2) {
> +            g_assert_not_reached();
> +        } else {
> +            return (1l << (60 + bit55)) & env->cp15.tcr_el[1];
> +        }
> +    } else if (el == 2) {
> +        if (HCR_E2H & env->cp15.hcr_el2) {
> +            return (1l << (60 + bit55)) & env->cp15.tcr_el[2];
> +        } else {
> +            return (1l << 33) & env->cp15.tcr_el[2];
> +        }
> +    } else if (el == 3) {
> +        return (1l << 33) & env->cp15.tcr_el[3];
> +    }
> +    return false;
> +}

Again, you can't touch hcr_el2 directly.
In this case, you want to use regime_tcr, using the mmu_idx value from mte_probe_int.

Use arm_mmu_idx_to_el() instead of arm_current_el(), so that UNPRIV acceses are handled 
correctly.

Using "l" is always wrong; always ll or preferably ull.
Though really defines for

   bit55 ? TCR_MTX1 : TCR_MTX0

wouldn't go amiss.

You seam to be missing a check for FEAT_MTE_NO_ADDRESS_TAGS or FEAT_MTE_CANONICAL_TAGS.

> +
>   /*
>    * For TBI, ideally, we would do nothing.  Proper behaviour on fault is
>    * for the tag to be present in the FAR_ELx register.  But for user-only
> diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
> index f9fd6fd408..513ee8d6a1 100644
> --- a/target/arm/tcg/mte_helper.c
> +++ b/target/arm/tcg/mte_helper.c
> @@ -799,6 +799,10 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
>           return 1;
>       }
>   
> +    if (mtx_check(env, bit55)) {
> +        return tag_is_canonical(ptr_tag, bit55);
> +    }

This could use a comment like

     If mtx is enabled, then the access is MemTag_CanonicallyTagged,
     otherwise it is MemTag_AllocationTagged.  See AArch64.CheckTag.

> +    if (mtx_check(env, bit55)) {
> +        if (tag_is_canonical(ptr_tag, bit55)) {
> +            goto done;
> +        }
> +        mte_check_fail(env, desc, ptr, ra);
> +    }

Likewise.

In the pseudocode, walkparams.mtx is used in AArch64.VAIsOutOfRange, which is part of 
get_phys_addr_lpae() here:

     /*
      * We determined the region when collecting the parameters, but we
      * have not yet validated that the address is valid for the region.
      * Extract the top bits and verify that they all match select.
      *
      * For aa32, if inputsize == addrsize, then we have selected the
      * region by exclusion in aa32_va_parameters and there is no more
      * validation to do here.
      */
     if (inputsize < addrsize) {
         uint64_t top_bits = sextract64(address, inputsize,
                                            addrsize - inputsize);
         if (-top_bits != param.select) {
             /* The gap between the two regions is a Translation fault */
             goto do_translation_fault;
         }
     }

There is also a use in AArch64.S1DisabledOutput, which would correspond to 
get_phys_addr_disabled(), which is relevant before

             if (extract64(address, pamax, addrtop - pamax + 1) != 0) {
                 fi->type = ARMFault_AddressSize;


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag
  2025-11-17  1:40 ` [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag Gabriel Brookman
@ 2025-11-17 16:26   ` Richard Henderson
  2025-11-18 17:31     ` brookmangabriel
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Henderson @ 2025-11-17 16:26 UTC (permalink / raw)
  To: qemu-devel

On 11/17/25 02:40, Gabriel Brookman wrote:
> @@ -444,6 +449,11 @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr)
>           return 0;
>       }
>   
> +    if (mtx_check(env, extract64(ptr, 55, 1))) {
> +        shift = extract64(ptr, LOG2_TAG_GRANULE, 4) * 4;
> +        return (~0) << shift;
> +    }

This should load the canonical tag, which is 0 for bit55==0.

The ~0 is wrong because it's not 64-bit.
The field also needs to be bound by gm_bs.
Something like

   return MAKE_64BIT_MASK(shift, shift + (2 << gm_bs));


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag
  2025-11-17 16:26   ` Richard Henderson
@ 2025-11-18 17:31     ` brookmangabriel
  0 siblings, 0 replies; 22+ messages in thread
From: brookmangabriel @ 2025-11-18 17:31 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Mon, Nov 17, 2025 at 05:26:54PM +0100, Richard Henderson wrote:
> On 11/17/25 02:40, Gabriel Brookman wrote:
> > @@ -444,6 +449,11 @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr)
> >           return 0;
> >       }
> > +    if (mtx_check(env, extract64(ptr, 55, 1))) {
> > +        shift = extract64(ptr, LOG2_TAG_GRANULE, 4) * 4;
> > +        return (~0) << shift;
> > +    }
> 
> This should load the canonical tag, which is 0 for bit55==0.
> 
> The ~0 is wrong because it's not 64-bit.
> The field also needs to be bound by gm_bs.
> Something like
> 
>   return MAKE_64BIT_MASK(shift, shift + (2 << gm_bs));
> 
> 
> r~
> 

Hey Richard,

Thanks for the review! Expect v3 sometime soon.

Thanks,
Gabriel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 08/10] target/arm: storing to canonical tags faults
  2025-11-17  1:40 ` [PATCH RFC v2 08/10] target/arm: storing to canonical tags faults Gabriel Brookman
@ 2025-11-19  7:48   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-19  7:48 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> According to ARM ARM, section "Memory region tagging types", tag-store
> instructions targeting canonically tagged regions cause a stage 1
> permission fault.
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   target/arm/tcg/mte_helper.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 47 insertions(+)
> 
> diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
> index ddb68e11fc..9eb3777fe2 100644
> --- a/target/arm/tcg/mte_helper.c
> +++ b/target/arm/tcg/mte_helper.c
> @@ -196,6 +196,23 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
>   #endif
>   }
>   
> +static void canonical_tag_write_fail(CPUARMState *env,
> +                                uint64_t dirty_ptr, uintptr_t ra)
> +{
> +    uint64_t syn;
> +
> +    env->exception.vaddress = dirty_ptr;
> +
> +    /* bit 42 is TnD */
> +    syn = (1l << 42) | syn_data_abort_no_iss(arm_current_el(env) != 0,
> +            0, 0, 0, 0, 1, 0b1110);
> +    raise_exception_ra(env, EXCP_DATA_ABORT, syn, exception_target_el(env), ra);
> +    g_assert_not_reached();
> +
> +}
> +
> +
> +

"l" is wrong.

Better as

     syn = syn_data_abort_no_iss(...);
     syn |= BIT_ULL(42);

Watch the myriad newlines.


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 09/10] tests/tcg: added test for MTE canonical and NAT
  2025-11-17  1:40 ` [PATCH RFC v2 09/10] tests/tcg: added test for MTE canonical and NAT Gabriel Brookman
@ 2025-11-19  7:49   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-19  7:49 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> +    p0 = (int *) (((long) p0) | (1ll << 56));

mixing long and ll is sketchy.

Best to use uintptr_t anyway.


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH RFC v2 10/10] docs: added MTE4 features to docs
  2025-11-17  1:40 ` [PATCH RFC v2 10/10] docs: added MTE4 features to docs Gabriel Brookman
@ 2025-11-19  7:51   ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2025-11-19  7:51 UTC (permalink / raw)
  To: Gabriel Brookman, qemu-devel; +Cc: Peter Maydell, Gustavo Romero, qemu-arm

On 11/17/25 02:40, Gabriel Brookman wrote:
> The implemented MTE4 features are now present in
> docs/system/arm/emulation.rst
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   docs/system/arm/emulation.rst | 4 ++++
>   target/arm/tcg/cpu64.c        | 8 ++++----
>   2 files changed, 8 insertions(+), 4 deletions(-)

Best to merge with patch 1, as I said.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2025-11-19  7:52 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-17  1:40 [PATCH RFC v2 00/10] target/arm: add support for MTE4 Gabriel Brookman
2025-11-17  1:40 ` [PATCH RFC v2 01/10] target/arm: explicitly disable MTE4 for max Gabriel Brookman
2025-11-17  9:48   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 02/10] tests/tcg: added test for MTE FAR Gabriel Brookman
2025-11-17  9:51   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 03/10] target/arm: add TCSO bitmasks to SCTLR Gabriel Brookman
2025-11-17 15:14   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 04/10] target/arm: add FEAT_MTE_STORE_ONLY logic Gabriel Brookman
2025-11-17 15:26   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 05/10] tests/tcg: added test for MTE write-only Gabriel Brookman
2025-11-17 15:39   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 06/10] target/arm: add canonical and no-address tag logic Gabriel Brookman
2025-11-17 16:18   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 07/10] target/arm: ldg on canonical tag loads the tag Gabriel Brookman
2025-11-17 16:26   ` Richard Henderson
2025-11-18 17:31     ` brookmangabriel
2025-11-17  1:40 ` [PATCH RFC v2 08/10] target/arm: storing to canonical tags faults Gabriel Brookman
2025-11-19  7:48   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 09/10] tests/tcg: added test for MTE canonical and NAT Gabriel Brookman
2025-11-19  7:49   ` Richard Henderson
2025-11-17  1:40 ` [PATCH RFC v2 10/10] docs: added MTE4 features to docs Gabriel Brookman
2025-11-19  7:51   ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).