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 <[email protected]>
---
 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


Reply via email to