diff options
Diffstat (limited to 'target/arm/translate-a64.c')
-rw-r--r-- | target/arm/translate-a64.c | 46 |
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; |