diff options
-rw-r--r-- | target/arm/helper.c | 26 | ||||
-rw-r--r-- | target/arm/translate.c | 26 |
2 files changed, 45 insertions, 7 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index 8646a7a119..8cb7a9451c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8548,8 +8548,18 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) } } -void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) -{ +void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) +{ + /* We're passed bits [11..0] of the instruction; extract + * SYSm and the mask bits. + * Invalid combinations of SYSm and mask are UNPREDICTABLE; + * we choose to treat them as if the mask bits were valid. + * NB that the pseudocode 'mask' variable is bits [11..10], + * whereas ours is [11..8]. + */ + uint32_t mask = extract32(maskreg, 8, 4); + uint32_t reg = extract32(maskreg, 0, 8); + if (arm_current_el(env) == 0 && reg > 7) { /* only xPSR sub-fields may be written by unprivileged */ return; @@ -8558,8 +8568,16 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) switch (reg) { case 0 ... 7: /* xPSR sub-fields */ /* only APSR is actually writable */ - if (reg & 4) { - xpsr_write(env, val, 0xf8000000); /* APSR */ + if (!(reg & 4)) { + uint32_t apsrmask = 0; + + if (mask & 8) { + apsrmask |= 0xf8000000; /* APSR NZCVQ */ + } + if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) { + apsrmask |= 0x000f0000; /* APSR GE[3:0] */ + } + xpsr_write(env, val, apsrmask); } break; case 8: /* MSP */ diff --git a/target/arm/translate.c b/target/arm/translate.c index b859f10755..e32e38cadd 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -10377,6 +10377,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw goto illegal_op; if (insn & (1 << 26)) { + if (arm_dc_feature(s, ARM_FEATURE_M)) { + goto illegal_op; + } if (!(insn & (1 << 20))) { /* Hypervisor call (v7) */ int imm16 = extract32(insn, 16, 4) << 12 @@ -10400,7 +10403,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw case 0: /* msr cpsr. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { tmp = load_reg(s, rn); - addr = tcg_const_i32(insn & 0xff); + /* the constant is the mask and SYSm fields */ + addr = tcg_const_i32(insn & 0xfff); gen_helper_v7m_msr(cpu_env, addr, tmp); tcg_temp_free_i32(addr); tcg_temp_free_i32(tmp); @@ -10497,7 +10501,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw gen_exception_return(s, tmp); break; case 6: /* MRS */ - if (extract32(insn, 5, 1)) { + if (extract32(insn, 5, 1) && + !arm_dc_feature(s, ARM_FEATURE_M)) { /* MRS (banked) */ int sysm = extract32(insn, 16, 4) | (extract32(insn, 4, 1) << 4); @@ -10506,6 +10511,14 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw break; } + if (extract32(insn, 16, 4) != 0xf) { + goto illegal_op; + } + if (!arm_dc_feature(s, ARM_FEATURE_M) && + extract32(insn, 0, 8) != 0) { + goto illegal_op; + } + /* mrs cpsr */ tmp = tcg_temp_new_i32(); if (arm_dc_feature(s, ARM_FEATURE_M)) { @@ -10518,7 +10531,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw store_reg(s, rd, tmp); break; case 7: /* MRS */ - if (extract32(insn, 5, 1)) { + if (extract32(insn, 5, 1) && + !arm_dc_feature(s, ARM_FEATURE_M)) { /* MRS (banked) */ int sysm = extract32(insn, 16, 4) | (extract32(insn, 4, 1) << 4); @@ -10532,6 +10546,12 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) { goto illegal_op; } + + if (extract32(insn, 16, 4) != 0xf || + extract32(insn, 0, 8) != 0) { + goto illegal_op; + } + tmp = load_cpu_field(spsr); store_reg(s, rd, tmp); break; |