With MTX active, address tag bits are checked for canonicity if the corresponding memory regions are not allocation tagged. See AArch64_CheckTag.
Signed-off-by: Gabriel Brookman <[email protected]> Reviewed-by: Richard Henderson <[email protected]> --- target/arm/internals.h | 6 ++++++ target/arm/tcg/mte_helper.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 192e6a2d47..779eafabc8 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1629,6 +1629,12 @@ static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) return deposit64(ptr, 56, 4, rtag); } +/* Return true if mtx bits mean that the access is canonically checked. */ +static inline bool mtx_check(uint32_t desc, int bit55) +{ + return (desc >> (R_MTEDESC_MTX_SHIFT + bit55)) & 1; +} + /* Return true if tbi or mtx bits mean that the access is tag checked. */ static inline bool tbi_or_mtx_check(uint32_t desc, int bit55) { diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 61cdf92c54..d35e3ef04d 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -858,6 +858,14 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, sizem1 + 1, MMU_DATA_LOAD, ra); if (!mem1) { + /* + * If mtx is enabled, then the access is MemTag_CanonicallyTagged, + * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and + * AArch64.S1DisabledOutput. + */ + if (mtx_check(desc, bit55)) { + return tag_is_canonical(ptr_tag, bit55); + } return 1; } /* Perform all of the comparisons. */ @@ -873,18 +881,24 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, /* * Perform all of the comparisons. - * Note the possible but unlikely case of the operation spanning - * two pages that do not both have tagging enabled. + * Note the possible but unlikely case of the operation spanning two + * pages that do not both have allocation tagging enabled. This can + * happen with or without mtx (canonical tagging) enabled. */ n = c = (next_page - tag_first) / TAG_GRANULE; if (mem1) { n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, c); + } else if (mtx_check(desc, bit55) && + !tag_is_canonical(ptr_tag, bit55)) { + return 0; } if (n == c) { - if (!mem2) { + if (mem2) { + n += checkN(mem2, 0, ptr_tag, tag_count - c); + } else if (!mtx_check(desc, bit55) || + tag_is_canonical(ptr_tag, bit55)) { return 1; } - n += checkN(mem2, 0, ptr_tag, tag_count - c); } } @@ -999,6 +1013,14 @@ uint64_t HELPER(mte_check_zva)(CPUARMState *env, uint32_t desc, uint64_t ptr) mem = allocation_tag_mem(env, mmu_idx, align_ptr, MMU_DATA_STORE, dcz_bytes, MMU_DATA_LOAD, ra); if (!mem) { + /* + * If mtx is enabled, then the access is MemTag_CanonicallyTagged, + * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and + * AArch64.S1DisabledOutput. + */ + if (mtx_check(desc, bit55) && !tag_is_canonical(ptr_tag, bit55)) { + mte_check_fail(env, desc, ptr, ra); + } goto done; } -- 2.54.0
