@@ -194,3 +194,16 @@ SB 1101 0101 0000 0011 0011 0000 111 11111
CFINV 1101 0101 0000 0 000 0100 0000 000 11111
XAFLAG 1101 0101 0000 0 000 0100 0000 001 11111
AXFLAG 1101 0101 0000 0 000 0100 0000 010 11111
+
+# These are architecturally all "MSR (immediate)"; we decode the destination
+# register too because there is no commonality in our implementation.
+@msr_i .... .... .... . ... .... imm:4 ... .....
+MSR_i_UAO 1101 0101 0000 0 000 0100 .... 011 11111 @msr_i
+MSR_i_PAN 1101 0101 0000 0 000 0100 .... 100 11111 @msr_i
+MSR_i_SPSEL 1101 0101 0000 0 000 0100 .... 101 11111 @msr_i
+MSR_i_SBSS 1101 0101 0000 0 011 0100 .... 001 11111 @msr_i
+MSR_i_DIT 1101 0101 0000 0 011 0100 .... 010 11111 @msr_i
+MSR_i_TCO 1101 0101 0000 0 011 0100 .... 100 11111 @msr_i
+MSR_i_DAIFSET 1101 0101 0000 0 011 0100 .... 110 11111 @msr_i
+MSR_i_DAIFCLEAR 1101 0101 0000 0 011 0100 .... 111 11111 @msr_i
+MSR_i_SVCR 1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111
@@ -1927,124 +1927,130 @@ static bool trans_AXFLAG(DisasContext *s, arg_AXFLAG *a)
return true;
}
-/* MSR (immediate) - move immediate to processor state field */
-static void handle_msr_i(DisasContext *s, uint32_t insn,
- unsigned int op1, unsigned int op2, unsigned int crm)
+static bool trans_MSR_i_UAO(DisasContext *s, arg_i *a)
{
- int op = op1 << 3 | op2;
-
- /* End the TB by default, chaining is ok. */
- s->base.is_jmp = DISAS_TOO_MANY;
-
- switch (op) {
- case 0x03: /* UAO */
- if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
- goto do_unallocated;
- }
- if (crm & 1) {
- set_pstate_bits(PSTATE_UAO);
- } else {
- clear_pstate_bits(PSTATE_UAO);
- }
- gen_rebuild_hflags(s);
- break;
-
- case 0x04: /* PAN */
- if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
- goto do_unallocated;
- }
- if (crm & 1) {
- set_pstate_bits(PSTATE_PAN);
- } else {
- clear_pstate_bits(PSTATE_PAN);
- }
- gen_rebuild_hflags(s);
- break;
-
- case 0x05: /* SPSel */
- if (s->current_el == 0) {
- goto do_unallocated;
- }
- gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(crm & PSTATE_SP));
- break;
-
- case 0x19: /* SSBS */
- if (!dc_isar_feature(aa64_ssbs, s)) {
- goto do_unallocated;
- }
- if (crm & 1) {
- set_pstate_bits(PSTATE_SSBS);
- } else {
- clear_pstate_bits(PSTATE_SSBS);
- }
- /* Don't need to rebuild hflags since SSBS is a nop */
- break;
-
- case 0x1a: /* DIT */
- if (!dc_isar_feature(aa64_dit, s)) {
- goto do_unallocated;
- }
- if (crm & 1) {
- set_pstate_bits(PSTATE_DIT);
- } else {
- clear_pstate_bits(PSTATE_DIT);
- }
- /* There's no need to rebuild hflags because DIT is a nop */
- break;
-
- case 0x1e: /* DAIFSet */
- gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(crm));
- break;
-
- case 0x1f: /* DAIFClear */
- gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(crm));
- /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
- s->base.is_jmp = DISAS_UPDATE_EXIT;
- break;
-
- case 0x1c: /* TCO */
- if (dc_isar_feature(aa64_mte, s)) {
- /* Full MTE is enabled -- set the TCO bit as directed. */
- if (crm & 1) {
- set_pstate_bits(PSTATE_TCO);
- } else {
- clear_pstate_bits(PSTATE_TCO);
- }
- gen_rebuild_hflags(s);
- /* Many factors, including TCO, go into MTE_ACTIVE. */
- s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
- } else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
- /* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
- s->base.is_jmp = DISAS_NEXT;
- } else {
- goto do_unallocated;
- }
- break;
-
- case 0x1b: /* SVCR* */
- if (!dc_isar_feature(aa64_sme, s) || crm < 2 || crm > 7) {
- goto do_unallocated;
- }
- if (sme_access_check(s)) {
- int old = s->pstate_sm | (s->pstate_za << 1);
- int new = (crm & 1) * 3;
- int msk = (crm >> 1) & 3;
-
- if ((old ^ new) & msk) {
- /* At least one bit changes. */
- gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
- tcg_constant_i32(msk));
- } else {
- s->base.is_jmp = DISAS_NEXT;
- }
- }
- break;
-
- default:
- do_unallocated:
- unallocated_encoding(s);
- return;
+ if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
+ return false;
}
+ if (a->imm & 1) {
+ set_pstate_bits(PSTATE_UAO);
+ } else {
+ clear_pstate_bits(PSTATE_UAO);
+ }
+ gen_rebuild_hflags(s);
+ s->base.is_jmp = DISAS_TOO_MANY;
+ return true;
+}
+
+static bool trans_MSR_i_PAN(DisasContext *s, arg_i *a)
+{
+ if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
+ return false;
+ }
+ if (a->imm & 1) {
+ set_pstate_bits(PSTATE_PAN);
+ } else {
+ clear_pstate_bits(PSTATE_PAN);
+ }
+ gen_rebuild_hflags(s);
+ s->base.is_jmp = DISAS_TOO_MANY;
+ return true;
+}
+
+static bool trans_MSR_i_SPSEL(DisasContext *s, arg_i *a)
+{
+ if (s->current_el == 0) {
+ return false;
+ }
+ gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(a->imm & PSTATE_SP));
+ s->base.is_jmp = DISAS_TOO_MANY;
+ return true;
+}
+
+static bool trans_MSR_i_SBSS(DisasContext *s, arg_i *a)
+{
+ if (!dc_isar_feature(aa64_ssbs, s)) {
+ return false;
+ }
+ if (a->imm & 1) {
+ set_pstate_bits(PSTATE_SSBS);
+ } else {
+ clear_pstate_bits(PSTATE_SSBS);
+ }
+ /* Don't need to rebuild hflags since SSBS is a nop */
+ s->base.is_jmp = DISAS_TOO_MANY;
+ return true;
+}
+
+static bool trans_MSR_i_DIT(DisasContext *s, arg_i *a)
+{
+ if (!dc_isar_feature(aa64_dit, s)) {
+ return false;
+ }
+ if (a->imm & 1) {
+ set_pstate_bits(PSTATE_DIT);
+ } else {
+ clear_pstate_bits(PSTATE_DIT);
+ }
+ /* There's no need to rebuild hflags because DIT is a nop */
+ s->base.is_jmp = DISAS_TOO_MANY;
+ return true;
+}
+
+static bool trans_MSR_i_TCO(DisasContext *s, arg_i *a)
+{
+ if (dc_isar_feature(aa64_mte, s)) {
+ /* Full MTE is enabled -- set the TCO bit as directed. */
+ if (a->imm & 1) {
+ set_pstate_bits(PSTATE_TCO);
+ } else {
+ clear_pstate_bits(PSTATE_TCO);
+ }
+ gen_rebuild_hflags(s);
+ /* Many factors, including TCO, go into MTE_ACTIVE. */
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
+ return true;
+ } else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
+ /* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
+ return true;
+ } else {
+ /* Insn not present */
+ return false;
+ }
+}
+
+static bool trans_MSR_i_DAIFSET(DisasContext *s, arg_i *a)
+{
+ gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(a->imm));
+ s->base.is_jmp = DISAS_TOO_MANY;
+ return true;
+}
+
+static bool trans_MSR_i_DAIFCLEAR(DisasContext *s, arg_i *a)
+{
+ gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(a->imm));
+ /* Exit the cpu loop to re-evaluate pending IRQs. */
+ s->base.is_jmp = DISAS_UPDATE_EXIT;
+ return true;
+}
+
+static bool trans_MSR_i_SVCR(DisasContext *s, arg_MSR_i_SVCR *a)
+{
+ if (!dc_isar_feature(aa64_sme, s) || a->mask == 0) {
+ return false;
+ }
+ if (sme_access_check(s)) {
+ int old = s->pstate_sm | (s->pstate_za << 1);
+ int new = a->imm * 3;
+
+ if ((old ^ new) & a->mask) {
+ /* At least one bit changes. */
+ gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
+ tcg_constant_i32(a->mask));
+ s->base.is_jmp = DISAS_TOO_MANY;
+ }
+ }
+ return true;
}
static void gen_get_nzcv(TCGv_i64 tcg_rt)
@@ -2319,18 +2325,7 @@ static void disas_system(DisasContext *s, uint32_t insn)
rt = extract32(insn, 0, 5);
if (op0 == 0) {
- if (l || rt != 31) {
- unallocated_encoding(s);
- return;
- }
- switch (crn) {
- case 4: /* MSR (immediate) */
- handle_msr_i(s, insn, op1, op2, crm);
- break;
- default:
- unallocated_encoding(s);
- break;
- }
+ unallocated_encoding(s);
return;
}
handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);