According to ARM ARM, section "Memory region tagging types", tag-store instructions targeting canonically tagged regions cause a stage 1 permission fault with MTX enabled.
Signed-off-by: Gabriel Brookman <[email protected]> Reviewed-by: Richard Henderson <[email protected]> --- target/arm/tcg/helper-a64-defs.h | 12 ++++----- target/arm/tcg/mte_helper.c | 55 +++++++++++++++++++++++++++++++--------- target/arm/tcg/translate-a64.c | 26 +++++++++++-------- 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/target/arm/tcg/helper-a64-defs.h b/target/arm/tcg/helper-a64-defs.h index c08c8c3991..136d246a68 100644 --- a/target/arm/tcg/helper-a64-defs.h +++ b/target/arm/tcg/helper-a64-defs.h @@ -103,15 +103,15 @@ DEF_HELPER_FLAGS_3(mte_check_zva, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) DEF_HELPER_FLAGS_4(ldg, TCG_CALL_NO_WG, i64, env, i64, i64, i32) -DEF_HELPER_FLAGS_3(stg, TCG_CALL_NO_WG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(stg_parallel, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(stg, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(stg_parallel, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_2(stg_stub, TCG_CALL_NO_WG, void, env, i64) -DEF_HELPER_FLAGS_3(st2g, TCG_CALL_NO_WG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(st2g, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_2(st2g_stub, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ldgm, TCG_CALL_NO_WG, i64, env, i64, i32) -DEF_HELPER_FLAGS_3(stgm, TCG_CALL_NO_WG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(stgm, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(unaligned_access, TCG_CALL_NO_WG, noreturn, env, i64, i32, i32) diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index c382f0149f..dca4ef5a94 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -231,6 +231,19 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, #endif } +static G_NORETURN void canonical_tag_write_fail(CPUARMState *env, + uint64_t dirty_ptr, uintptr_t ra) +{ + uint64_t syn; + + env->exception.vaddress = dirty_ptr; + + syn = syn_data_abort_no_iss(arm_current_el(env) != 0, 0, 0, 0, 0, 1, 0); + syn |= BIT_ULL(42); /* TnD is bit 42 */ + + raise_exception_ra(env, EXCP_DATA_ABORT, syn, exception_target_el(env), ra); +} + static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, uint64_t ptr, MMUAccessType ptr_access, int ptr_size, MMUAccessType tag_access, @@ -360,7 +373,7 @@ static void store_tag1_parallel(uint64_t ptr, uint8_t *mem, int tag) typedef void stg_store1(uint64_t, uint8_t *, int); static inline void do_stg(CPUARMState *env, uint64_t ptr, uint64_t xt, - uintptr_t ra, stg_store1 store1) + uint32_t mtx, uintptr_t ra, stg_store1 store1) { int mmu_idx = arm_env_mmu_index(env); uint8_t *mem; @@ -374,17 +387,20 @@ static inline void do_stg(CPUARMState *env, uint64_t ptr, uint64_t xt, /* Store if page supports tags. */ if (mem) { store1(ptr, mem, allocation_tag_from_addr(xt)); + } else if (mtx) { + canonical_tag_write_fail(env, ptr, ra); } } -void HELPER(stg)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(stg)(CPUARMState *env, uint64_t ptr, uint64_t xt, uint32_t mtx) { - do_stg(env, ptr, xt, GETPC(), store_tag1); + do_stg(env, ptr, xt, mtx, GETPC(), store_tag1); } -void HELPER(stg_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(stg_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt, + uint32_t mtx) { - do_stg(env, ptr, xt, GETPC(), store_tag1_parallel); + do_stg(env, ptr, xt, mtx, GETPC(), store_tag1_parallel); } void HELPER(stg_stub)(CPUARMState *env, uint64_t ptr) @@ -397,7 +413,7 @@ void HELPER(stg_stub)(CPUARMState *env, uint64_t ptr) } static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, - uintptr_t ra, stg_store1 store1) + uint32_t mtx, uintptr_t ra, stg_store1 store1) { int mmu_idx = arm_env_mmu_index(env); int tag = allocation_tag_from_addr(xt); @@ -420,9 +436,13 @@ static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, /* Store if page(s) support tags. */ if (mem1) { store1(TAG_GRANULE, mem1, tag); + } else if (mtx) { + canonical_tag_write_fail(env, ptr, ra); } if (mem2) { store1(0, mem2, tag); + } else if (mtx) { + canonical_tag_write_fail(env, ptr + TAG_GRANULE, ra); } } else { /* Two stores aligned mod TAG_GRANULE*2 -- modify one byte. */ @@ -431,18 +451,22 @@ static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, if (mem1) { tag |= tag << 4; qatomic_set(mem1, tag); + } else if (mtx) { + /* Writing tags to canonically tagged memory region: faults */ + canonical_tag_write_fail(env, ptr, ra); } } } -void HELPER(st2g)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(st2g)(CPUARMState *env, uint64_t ptr, uint64_t xt, uint32_t mtx) { - do_st2g(env, ptr, xt, GETPC(), store_tag1); + do_st2g(env, ptr, xt, mtx, GETPC(), store_tag1); } -void HELPER(st2g_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(st2g_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt, + uint32_t mtx) { - do_st2g(env, ptr, xt, GETPC(), store_tag1_parallel); + do_st2g(env, ptr, xt, mtx, GETPC(), store_tag1_parallel); } void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr) @@ -528,7 +552,7 @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr, uint32_t mtx) return ret << shift; } -void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) +void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val, uint32_t mtx) { int mmu_idx = arm_env_mmu_index(env); uintptr_t ra = GETPC(); @@ -548,6 +572,10 @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) * and if the OS has enabled access to the tags. */ if (!tag_mem) { + /* Storing tags to canonically tagged region: fault. */ + if (mtx) { + canonical_tag_write_fail(env, ptr, ra); + } return; } @@ -577,7 +605,8 @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) } } -void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) +void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val, + uint32_t mtx) { uintptr_t ra = GETPC(); int mmu_idx = arm_env_mmu_index(env); @@ -601,6 +630,8 @@ void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) if (mem) { int tag_pair = (val & 0xf) * 0x11; memset(mem, tag_pair, tag_bytes); + } else if (mtx) { + canonical_tag_write_fail(env, ptr, ra); } } diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 5fbc54de4b..68f476621a 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -3031,7 +3031,8 @@ static void handle_sys(DisasContext *s, bool isread, /* Extract the tag from the register to match STZGM. */ tag = tcg_temp_new_i64(); tcg_gen_shri_i64(tag, tcg_rt, 56); - gen_helper_stzgm_tags(tcg_env, clean_addr, tag); + gen_helper_stzgm_tags(tcg_env, clean_addr, tag, + tcg_constant_i32(s->mtx)); } } return; @@ -3048,7 +3049,8 @@ static void handle_sys(DisasContext *s, bool isread, /* Extract the tag from the register to match STZGM. */ tag = tcg_temp_new_i64(); tcg_gen_shri_i64(tag, tcg_rt, 56); - gen_helper_stzgm_tags(tcg_env, clean_addr, tag); + gen_helper_stzgm_tags(tcg_env, clean_addr, tag, + tcg_constant_i32(s->mtx)); } } return; @@ -3865,9 +3867,11 @@ static bool trans_STGP(DisasContext *s, arg_ldstpair *a) /* Perform the tag store, if tag access enabled. */ if (s->ata[0]) { if (tb_cflags(s->base.tb) & CF_PARALLEL) { - gen_helper_stg_parallel(tcg_env, dirty_addr, dirty_addr); + gen_helper_stg_parallel(tcg_env, dirty_addr, dirty_addr, + tcg_constant_i32(s->mtx)); } else { - gen_helper_stg(tcg_env, dirty_addr, dirty_addr); + gen_helper_stg(tcg_env, dirty_addr, dirty_addr, + tcg_constant_i32(s->mtx)); } } @@ -4647,7 +4651,7 @@ static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_stzgm_tags(tcg_env, addr, tcg_rt); + gen_helper_stzgm_tags(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } /* * The non-tags portion of STZGM is mostly like DC_ZVA, @@ -4679,7 +4683,7 @@ static bool trans_STGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_stgm(tcg_env, addr, tcg_rt); + gen_helper_stgm(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } else { MMUAccessType acc = MMU_DATA_STORE; int size = 4 << s->gm_blocksize; @@ -4795,15 +4799,17 @@ static bool do_STG(DisasContext *s, arg_ldst_tag *a, bool is_zero, bool is_pair) } } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { if (is_pair) { - gen_helper_st2g_parallel(tcg_env, addr, tcg_rt); + gen_helper_st2g_parallel(tcg_env, addr, tcg_rt, + tcg_constant_i32(s->mtx)); } else { - gen_helper_stg_parallel(tcg_env, addr, tcg_rt); + gen_helper_stg_parallel(tcg_env, addr, tcg_rt, + tcg_constant_i32(s->mtx)); } } else { if (is_pair) { - gen_helper_st2g(tcg_env, addr, tcg_rt); + gen_helper_st2g(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } else { - gen_helper_stg(tcg_env, addr, tcg_rt); + gen_helper_stg(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } } -- 2.54.0
