summaryrefslogtreecommitdiffstats
path: root/target/arm/translate-a64.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/translate-a64.c')
-rw-r--r--target/arm/translate-a64.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 4c64546090..c86b97b1d4 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -1188,6 +1188,22 @@ bool sve_access_check(DisasContext *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
* destination register. See DecodeRegExtend() in the ARM ARM.
@@ -1746,6 +1762,30 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
}
break;
+ case 0x1b: /* SVCR* */
+ if (!dc_isar_feature(aa64_sme, s) || crm < 2 || crm > 7) {
+ goto do_unallocated;
+ }
+ if (sme_access_check(s)) {
+ bool i = crm & 1;
+ bool changed = false;
+
+ if ((crm & 2) && i != s->pstate_sm) {
+ gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i));
+ changed = true;
+ }
+ if ((crm & 4) && i != s->pstate_za) {
+ gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i));
+ changed = true;
+ }
+ if (changed) {
+ gen_rebuild_hflags(s);
+ } else {
+ s->base.is_jmp = DISAS_NEXT;
+ }
+ }
+ break;
+
default:
do_unallocated:
unallocated_encoding(s);
@@ -1958,6 +1998,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)) {
@@ -14603,7 +14645,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
+ dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL);
dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;
+ dc->svl = (EX_TBFLAG_A64(tb_flags, SVL) + 1) * 16;
dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
dc->bt = EX_TBFLAG_A64(tb_flags, BT);
dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);
@@ -14611,6 +14655,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->ata = EX_TBFLAG_A64(tb_flags, ATA);
dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE);
dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE);
+ dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM);
+ dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA);
dc->vec_len = 0;
dc->vec_stride = 0;
dc->cp_regs = arm_cpu->cp_regs;