diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index d9b678c2f1..d30758ee71 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -113,6 +113,11 @@ enum { ARM_CP_EL3_NO_EL2_UNDEF = 1 << 16, ARM_CP_EL3_NO_EL2_KEEP = 1 << 17, ARM_CP_EL3_NO_EL2_C_NZ = 1 << 18, + /* + * Flag: Access check for this sysreg is constrained by the + * ARM pseudocode function CheckSMEAccess(). + */ + ARM_CP_SME = 1 << 19, }; /* diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 9a285dd177..8f609f46b6 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1187,6 +1187,22 @@ bool sve_access_check(DisasContext *s) return fp_access_check(s); } +/* + * Check that SME access is enabled, raise an exception if not. + * Note that this function corresponds to CheckSMEAccess and is + * only used directly for cpregs. + */ +static bool sme_access_check(DisasContext *s) +{ + if (s->sme_excp_el) { + gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF, + syn_smetrap(SME_ET_AccessTrap, false), + s->sme_excp_el); + return false; + } + return true; +} + /* * This utility function is for doing register extension with an * optional shift. You will likely want to pass a temporary for the @@ -1958,6 +1974,8 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, return; } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { return; + } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { + return; } if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {