[PATCH RFC v3 01/12] target/arm: implement MTE_PERM

Gabriel Brookman posted 12 patches 1 month ago
Maintainers: Laurent Vivier <laurent@vivier.eu>, Peter Maydell <peter.maydell@linaro.org>
[PATCH RFC v3 01/12] target/arm: implement MTE_PERM
Posted by Gabriel Brookman 1 month ago
Introduces a new stage 2 memory attribute, NoTagAccess, that raises a
stage 2 data abort on a tag check, tag read, or tag write.

Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
---
 target/arm/cpu-features.h   |  5 +++++
 target/arm/ptw.c            | 17 ++++++++++++++++-
 target/arm/tcg/mte_helper.c | 31 +++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index c86a4e667d..48009b5a66 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1139,6 +1139,11 @@ static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id)
     return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) >= 3;
 }
 
+static inline bool isar_feature_aa64_mteperm(const ARMISARegisters *id)
+{
+    return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTEPERM) == 1;
+}
+
 static inline bool isar_feature_aa64_sme(const ARMISARegisters *id)
 {
     return FIELD_EX64_IDREG(id, ID_AA64PFR1, SME) != 0;
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 2e6b149b2d..9f864fe837 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -3393,7 +3393,7 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
                                         ARMCacheAttrs s1, ARMCacheAttrs s2)
 {
     ARMCacheAttrs ret;
-    bool tagged = false;
+    bool tagged, notagaccess = false;
 
     assert(!s1.is_s2_format);
     ret.is_s2_format = false;
@@ -3403,6 +3403,18 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
         s1.attrs = 0xff;
     }
 
+    if (hcr & HCR_FWB) {
+        if (s2.attrs >= 0xe) {
+            notagaccess = true;
+            s2.attrs = 0x7;
+        }
+    } else {
+        if (s2.attrs == 0x4) {
+            notagaccess = true;
+            s2.attrs = 0xf;
+        }
+    }
+
     /* Combine shareability attributes (table D4-43) */
     if (s1.shareability == 2 || s2.shareability == 2) {
         /* if either are outer-shareable, the result is outer-shareable */
@@ -3437,6 +3449,9 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
     /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */
     if (tagged && ret.attrs == 0xff) {
         ret.attrs = 0xf0;
+        if (notagaccess) {
+            ret.attrs = 0xe0;
+        }
     }
 
     return ret;
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index bb48fe359b..942bd4103d 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -57,6 +57,28 @@ static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude)
     return tag;
 }
 
+#ifdef CONFIG_USER_ONLY
+#else
+/*
+ * Constructs S2 Permission Fault as described in ARM ARM "Stage 2 Memory
+ * Tagging Attributes".
+ */
+static void mte_perm_check_fail(CPUARMState *env, uint64_t dirty_ptr,
+                                uintptr_t ra, bool is_write)
+{
+    uint64_t syn;
+
+    env->exception.vaddress = dirty_ptr;
+
+    syn = syn_data_abort_no_iss(0, 0, 0, 0, 0, is_write, 0);
+
+    syn |= BIT_ULL(42); /* TnD is bit 42 */
+
+    raise_exception_ra(env, EXCP_DATA_ABORT, syn, 2, ra);
+    g_assert_not_reached();
+}
+#endif
+
 uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
                                   uint64_t ptr, MMUAccessType ptr_access,
                                   int ptr_size, MMUAccessType tag_access,
@@ -116,6 +138,15 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
     }
     assert(!(flags & TLB_INVALID_MASK));
 
+    /*
+     * If the virtual page MemAttr == Tagged NoTagAccess, throw S2 permission
+     * fault (conditional on mteperm being implemented and RA != 0).
+     */
+    if (ra && cpu_isar_feature(aa64_mteperm, env_archcpu(env))
+        && full->extra.arm.pte_attrs == 0xe0) {
+        mte_perm_check_fail(env, ptr, ra, tag_access == 1);
+    }
+
     /* If the virtual page MemAttr != Tagged, access unchecked. */
     if (full->extra.arm.pte_attrs != 0xf0) {
         return NULL;

-- 
2.52.0
Re: [PATCH RFC v3 01/12] target/arm: implement MTE_PERM
Posted by Richard Henderson 1 month ago
On 1/6/26 05:14, Gabriel Brookman wrote:
> Introduces a new stage 2 memory attribute, NoTagAccess, that raises a
> stage 2 data abort on a tag check, tag read, or tag write.
> 
> Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com>
> ---
>   target/arm/cpu-features.h   |  5 +++++
>   target/arm/ptw.c            | 17 ++++++++++++++++-
>   target/arm/tcg/mte_helper.c | 31 +++++++++++++++++++++++++++++++
>   3 files changed, 52 insertions(+), 1 deletion(-)
> 
> diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
> index c86a4e667d..48009b5a66 100644
> --- a/target/arm/cpu-features.h
> +++ b/target/arm/cpu-features.h
> @@ -1139,6 +1139,11 @@ static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id)
>       return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) >= 3;
>   }
>   
> +static inline bool isar_feature_aa64_mteperm(const ARMISARegisters *id)
> +{
> +    return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTEPERM) == 1;
> +}

Per the Arm ARM re future expansion, this should be true for any non-zero value.
See "D24.1.3 Principles of the ID scheme for fields in ID registers".

> @@ -3403,6 +3403,18 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
>           s1.attrs = 0xff;
>       }
>   
> +    if (hcr & HCR_FWB) {
> +        if (s2.attrs >= 0xe) {
> +            notagaccess = true;
> +            s2.attrs = 0x7;
> +        }
> +    } else {
> +        if (s2.attrs == 0x4) {
> +            notagaccess = true;
> +            s2.attrs = 0xf;
> +        }
> +    }
> +
>       /* Combine shareability attributes (table D4-43) */
>       if (s1.shareability == 2 || s2.shareability == 2) {
>           /* if either are outer-shareable, the result is outer-shareable */
> @@ -3437,6 +3449,9 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
>       /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */
>       if (tagged && ret.attrs == 0xff) {
>           ret.attrs = 0xf0;
> +        if (notagaccess) {
> +            ret.attrs = 0xe0;
> +        }
>       }

Better as

     ret.attrs = notagaccess ? 0xe0 : 0xf0;

Given that this hunk corresponds to J1.3.5.2 EncodePARAttrs, I think it would be worth a 
comment that FEAT_MTE_PERM is checked in allocation_tag_mem_probe and that the attr 
encoding is otherwise RESERVED.


> diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
> index bb48fe359b..942bd4103d 100644
> --- a/target/arm/tcg/mte_helper.c
> +++ b/target/arm/tcg/mte_helper.c
> @@ -57,6 +57,28 @@ static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude)
>       return tag;
>   }
>   
> +#ifdef CONFIG_USER_ONLY
> +#else

#ifndef


> +/*
> + * Constructs S2 Permission Fault as described in ARM ARM "Stage 2 Memory
> + * Tagging Attributes".
> + */
> +static void mte_perm_check_fail(CPUARMState *env, uint64_t dirty_ptr,
> +                                uintptr_t ra, bool is_write)
> +{
> +    uint64_t syn;
> +
> +    env->exception.vaddress = dirty_ptr;
> +
> +    syn = syn_data_abort_no_iss(0, 0, 0, 0, 0, is_write, 0);
> +
> +    syn |= BIT_ULL(42); /* TnD is bit 42 */

Surely (32 + 9) == 41 for the TagAccess bit.

> +
> +    raise_exception_ra(env, EXCP_DATA_ABORT, syn, 2, ra);
> +    g_assert_not_reached();
> +}
> +#endif
> +
>   uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
>                                     uint64_t ptr, MMUAccessType ptr_access,
>                                     int ptr_size, MMUAccessType tag_access,
> @@ -116,6 +138,15 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
>       }
>       assert(!(flags & TLB_INVALID_MASK));
>   
> +    /*
> +     * If the virtual page MemAttr == Tagged NoTagAccess, throw S2 permission
> +     * fault (conditional on mteperm being implemented and RA != 0).
> +     */
> +    if (ra && cpu_isar_feature(aa64_mteperm, env_archcpu(env))
> +        && full->extra.arm.pte_attrs == 0xe0) {
> +        mte_perm_check_fail(env, ptr, ra, tag_access == 1);
> +    }
> +
>       /* If the virtual page MemAttr != Tagged, access unchecked. */
>       if (full->extra.arm.pte_attrs != 0xf0) {
>           return NULL;
> 


r~