summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target-arm/helper.c5
-rw-r--r--target-arm/kvm64.c1
-rw-r--r--target-arm/machine.c2
-rw-r--r--target-arm/op_helper.c5
4 files changed, 7 insertions, 6 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 014bb80d85..c491cd80ab 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5268,7 +5268,7 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
      * In a V8 implementation, it is permitted for privileged software to
      * change the CPSR A/F bits regardless of the SCR.AW/FW bits.
      */
-    if (!arm_feature(env, ARM_FEATURE_V8) &&
+    if (write_type != CPSRWriteRaw && !arm_feature(env, ARM_FEATURE_V8) &&
         arm_feature(env, ARM_FEATURE_EL3) &&
         !arm_feature(env, ARM_FEATURE_EL2) &&
         !arm_is_secure(env)) {
@@ -5315,7 +5315,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
     env->daif &= ~(CPSR_AIF & mask);
     env->daif |= val & CPSR_AIF & mask;
 
-    if ((env->uncached_cpsr ^ val) & mask & CPSR_M) {
+    if (write_type != CPSRWriteRaw &&
+        ((env->uncached_cpsr ^ val) & mask & CPSR_M)) {
         if (bad_mode_switch(env, val & CPSR_M)) {
             /* Attempt to switch to an invalid mode: this is UNPREDICTABLE.
              * We choose to ignore the attempt and leave the CPSR M field
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 08c2c81479..e8527bf0cc 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -722,7 +722,6 @@ int kvm_arch_get_registers(CPUState *cs)
     if (is_a64(env)) {
         pstate_write(env, val);
     } else {
-        env->uncached_cpsr = val & CPSR_M;
         cpsr_write(env, val, 0xffffffff, CPSRWriteRaw);
     }
 
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 0fc7df0ee2..03a73d950e 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -173,8 +173,6 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size)
         return 0;
     }
 
-    /* Avoid mode switch when restoring CPSR */
-    env->uncached_cpsr = val & CPSR_M;
     cpsr_write(env, val, 0xffffffff, CPSRWriteRaw);
     return 0;
 }
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 543d33aad2..4881e34177 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -779,7 +779,10 @@ void HELPER(exception_return)(CPUARMState *env)
 
     if (!return_to_aa64) {
         env->aarch64 = 0;
-        env->uncached_cpsr = spsr & CPSR_M;
+        /* We do a raw CPSR write because aarch64_sync_64_to_32()
+         * will sort the register banks out for us, and we've already
+         * caught all the bad-mode cases in el_from_spsr().
+         */
         cpsr_write(env, spsr, ~0, CPSRWriteRaw);
         if (!arm_singlestep_active(env)) {
             env->uncached_cpsr &= ~PSTATE_SS;