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
