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 <brookmangabriel@gmail.com>
---
target/arm/cpu-features.h | 5 +++++
target/arm/ptw.c | 17 ++++++++++++++++-
target/arm/tcg/mte_helper.c | 31 +++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index c86a4e667d..48009b5a66 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1139,6 +1139,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 2e6b149b2d..9f864fe837 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -3393,7 +3393,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;
@@ -3403,6 +3403,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 */
@@ -3437,6 +3449,9 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
/* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */
if (tagged && ret.attrs == 0xff) {
ret.attrs = 0xf0;
+ if (notagaccess) {
+ ret.attrs = 0xe0;
+ }
}
return ret;
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index bb48fe359b..942bd4103d 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -57,6 +57,28 @@ static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude)
return tag;
}
+#ifdef CONFIG_USER_ONLY
+#else
+/*
+ * 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(42); /* TnD is bit 42 */
+
+ 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,
@@ -116,6 +138,15 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
}
assert(!(flags & TLB_INVALID_MASK));
+ /*
+ * If the virtual page MemAttr == Tagged NoTagAccess, throw S2 permission
+ * fault (conditional on mteperm being implemented and RA != 0).
+ */
+ if (ra && cpu_isar_feature(aa64_mteperm, env_archcpu(env))
+ && full->extra.arm.pte_attrs == 0xe0) {
+ mte_perm_check_fail(env, ptr, ra, tag_access == 1);
+ }
+
/* If the virtual page MemAttr != Tagged, access unchecked. */
if (full->extra.arm.pte_attrs != 0xf0) {
return NULL;
--
2.52.0