aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/arm/helper.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2594faa9b8..4ed32c56b8 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8768,9 +8768,16 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
}
break;
case 20: /* CONTROL */
- switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
- env->v7m.control = val & (R_V7M_CONTROL_SPSEL_MASK |
- R_V7M_CONTROL_NPRIV_MASK);
+ /* Writing to the SPSEL bit only has an effect if we are in
+ * thread mode; other bits can be updated by any privileged code.
+ * switch_v7m_sp() deals with updating the SPSEL bit in
+ * env->v7m.control, so we only need update the others.
+ */
+ if (env->v7m.exception == 0) {
+ switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
+ }
+ env->v7m.control &= ~R_V7M_CONTROL_NPRIV_MASK;
+ env->v7m.control |= val & R_V7M_CONTROL_NPRIV_MASK;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"