aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-arm/kvm64.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index d6c83b0fb2..93c1ca8b21 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -140,6 +140,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
uint64_t val;
int i;
int ret;
+ unsigned int el;
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -206,9 +207,22 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
+ /* Saved Program State Registers
+ *
+ * Before we restore from the banked_spsr[] array we need to
+ * ensure that any modifications to env->spsr are correctly
+ * reflected in the banks.
+ */
+ el = arm_current_el(env);
+ if (el > 0 && !is_a64(env)) {
+ i = bank_number(env->uncached_cpsr & CPSR_M);
+ env->banked_spsr[i] = env->spsr;
+ }
+
+ /* KVM 0-4 map to QEMU banks 1-5 */
for (i = 0; i < KVM_NR_SPSR; i++) {
reg.id = AARCH64_CORE_REG(spsr[i]);
- reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
+ reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret) {
return ret;
@@ -265,6 +279,7 @@ int kvm_arch_get_registers(CPUState *cs)
struct kvm_one_reg reg;
uint64_t val;
uint32_t fpr;
+ unsigned int el;
int i;
int ret;
@@ -337,15 +352,25 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
+ /* Fetch the SPSR registers
+ *
+ * KVM SPSRs 0-4 map to QEMU banks 1-5
+ */
for (i = 0; i < KVM_NR_SPSR; i++) {
reg.id = AARCH64_CORE_REG(spsr[i]);
- reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
+ reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret) {
return ret;
}
}
+ el = arm_current_el(env);
+ if (el > 0 && !is_a64(env)) {
+ i = bank_number(env->uncached_cpsr & CPSR_M);
+ env->spsr = env->banked_spsr[i];
+ }
+
/* Advanced SIMD and FP registers
* We map Qn = regs[2n+1]:regs[2n]
*/