Introduces a new stage 2 memory attribute, NoTagAccess, that raises a stage 2 data abort on a tag check, tag read, or tag write.
Signed-off-by: Gabriel Brookman <[email protected]> Reviewed-by: Richard Henderson <[email protected]> --- target/arm/cpu-features.h | 5 +++++ target/arm/ptw.c | 25 ++++++++++++++++++++++--- target/arm/tcg/mte_helper.c | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 88fe3ed287..adfbdb9da5 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -1157,6 +1157,11 @@ static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) >= 3; } +static inline bool isar_feature_aa64_mteperm(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTEPERM) >= 1; +} + static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64PFR1, SME) != 0; diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 316e201cfe..467d815e0d 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -3414,7 +3414,7 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, ARMCacheAttrs s1, ARMCacheAttrs s2) { ARMCacheAttrs ret; - bool tagged = false; + bool tagged, notagaccess = false; assert(!s1.is_s2_format); ret.is_s2_format = false; @@ -3424,6 +3424,18 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, s1.attrs = 0xff; } + if (hcr & HCR_FWB) { + if (s2.attrs >= 0xe) { + notagaccess = true; + s2.attrs = 0x7; + } + } else { + if (s2.attrs == 0x4) { + notagaccess = true; + s2.attrs = 0xf; + } + } + /* Combine shareability attributes (table D4-43) */ if (s1.shareability == 2 || s2.shareability == 2) { /* if either are outer-shareable, the result is outer-shareable */ @@ -3455,9 +3467,16 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, ret.shareability = 2; } - /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ + /* + * The attr encoding 0xe0 corresponds to Tagged NoTagAccess and is only + * valid with FEAT_MTE_PERM (otherwise RESERVED, constrained + * unpredictable)). The presence of this feature is checked in + * allocation_tag_mem_probe, where Tagged NoTagAccess has its effect. See + * J1.3.5.2 EncodePARAttrs. + * TODO: CombineS1S2Desc does not consider transient, only WB, RWA. + */ if (tagged && ret.attrs == 0xff) { - ret.attrs = 0xf0; + ret.attrs = notagaccess ? 0xe0 : 0xf0; } return ret; diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index a9fb979f63..bf35dc10ce 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -58,6 +58,27 @@ static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) return tag; } +#ifndef CONFIG_USER_ONLY +/* + * Constructs S2 Permission Fault as described in ARM ARM "Stage 2 Memory + * Tagging Attributes". + */ +static void mte_perm_check_fail(CPUARMState *env, uint64_t dirty_ptr, + uintptr_t ra, bool is_write) +{ + uint64_t syn; + + env->exception.vaddress = dirty_ptr; + + syn = syn_data_abort_no_iss(0, 0, 0, 0, 0, is_write, 0); + + syn |= BIT_ULL(41); /* TagAccess is bit 41 */ + + raise_exception_ra(env, EXCP_DATA_ABORT, syn, 2, ra); + g_assert_not_reached(); +} +#endif + uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, uint64_t ptr, MMUAccessType ptr_access, int ptr_size, MMUAccessType tag_access, @@ -117,8 +138,21 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, } assert(!(flags & TLB_INVALID_MASK)); - /* If the virtual page MemAttr != Tagged, access unchecked. */ - if (full->extra.arm.pte_attrs != 0xf0) { + switch (full->extra.arm.pte_attrs) { + case 0xf0: /* Tagged */ + break; + + case 0xe0: /* NoTagAccess */ + if (cpu_isar_feature(aa64_mteperm, env_archcpu(env))) { + if (probe) { + return NULL; + } + assert(ra); + mte_perm_check_fail(env, ptr, ra, tag_access == MMU_DATA_STORE); + } + /* fall through */ + + default: /* Not Tagged */ return NULL; } -- 2.54.0
