target/arm: add canonical MTE check logic
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 <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-8-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Gabriel Brookman committed
May 29, 2026 at 12:52 UTC
5bd4fa5c6c202da0e5110674c4f0354decce551f
2 files changed
+32
-4
target/arm/internals.h
+6
@@ -1658,6 +1658,12 @@ static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag)
1658
return deposit64(ptr, 56, 4, rtag);
1659
}
1660
1661
+/* Return true if mtx bits mean that the access is canonically checked. */
1662
+static inline bool mtx_check(uint32_t desc, int bit55)
1663
+{
1664
+ return (desc >> (R_MTEDESC_MTX_SHIFT + bit55)) & 1;
1665
+}
1666
+
1667
/* Return true if tbi or mtx bits mean that the access is tag checked. */
1668
static inline bool tbi_or_mtx_check(uint32_t desc, int bit55)
1669
{
target/arm/tcg/mte_helper.c
+26
-4
@@ -858,6 +858,14 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
858
mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, sizem1 + 1,
859
MMU_DATA_LOAD, ra);
860
if (!mem1) {
861
+ /*
862
+ * If mtx is enabled, then the access is MemTag_CanonicallyTagged,
863
+ * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and
864
+ * AArch64.S1DisabledOutput.
865
+ */
866
+ if (mtx_check(desc, bit55)) {
867
+ return tag_is_canonical(ptr_tag, bit55);
868
+ }
869
return 1;
870
}
871
/* Perform all of the comparisons. */
@@ -873,18 +881,24 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
881
882
/*
883
* Perform all of the comparisons.
876
- * Note the possible but unlikely case of the operation spanning
877
- * two pages that do not both have tagging enabled.
884
+ * Note the possible but unlikely case of the operation spanning two
885
+ * pages that do not both have allocation tagging enabled. This can
886
+ * happen with or without mtx (canonical tagging) enabled.
887
*/
888
n = c = (next_page - tag_first) / TAG_GRANULE;
889
if (mem1) {
890
n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, c);
891
+ } else if (mtx_check(desc, bit55) &&
892
+ !tag_is_canonical(ptr_tag, bit55)) {
893
+ return 0;
894
}
895
if (n == c) {
884
- if (!mem2) {
896
+ if (mem2) {
897
+ n += checkN(mem2, 0, ptr_tag, tag_count - c);
898
+ } else if (!mtx_check(desc, bit55) ||
899
+ tag_is_canonical(ptr_tag, bit55)) {
900
return 1;
901
}
887
- n += checkN(mem2, 0, ptr_tag, tag_count - c);
902
}
903
}
904
@@ -999,6 +1013,14 @@ uint64_t HELPER(mte_check_zva)(CPUARMState *env, uint32_t desc, uint64_t ptr)
1013
mem = allocation_tag_mem(env, mmu_idx, align_ptr, MMU_DATA_STORE,
1014
dcz_bytes, MMU_DATA_LOAD, ra);
1015
if (!mem) {
1016
+ /*
1017
+ * If mtx is enabled, then the access is MemTag_CanonicallyTagged,
1018
+ * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and
1019
+ * AArch64.S1DisabledOutput.
1020
+ */
1021
+ if (mtx_check(desc, bit55) && !tag_is_canonical(ptr_tag, bit55)) {
1022
+ mte_check_fail(env, desc, ptr, ra);
1023
+ }
1024
goto done;
1025
}
1026