summaryrefslogtreecommitdiff
path: root/target-arm/kvm64.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-04-15 19:18:43 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-04-17 21:34:04 +0100
commitf502cfc207ff288ec1f3dac10024c51ffe64a65d (patch)
tree077d1d264d00c01eee62a9de83cd0a87bc525c83 /target-arm/kvm64.c
parenta0618a1990e4df30a76cf5b441b4aa7f002b0d64 (diff)
downloadqemu-f502cfc207ff288ec1f3dac10024c51ffe64a65d.tar.gz
target-arm: Implement SP_EL0, SP_EL1
Implement handling for the AArch64 SP_EL0 system register. This holds the EL0 stack pointer, and is only accessible when it's not being used as the stack pointer, ie when we're in EL1 and EL1 is using its own stack pointer. We also provide a definition of the SP_EL1 register; this isn't guest visible as a system register for an implementation like QEMU which doesn't provide EL2 or EL3; however it is useful for ensuring the underlying state is migrated. We need to update the state fields in the CPU state whenever we switch stack pointers; this happens when we take an exception and also when SPSEL is used to change the bit in PSTATE which indicates which stack pointer EL1 should use. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Diffstat (limited to 'target-arm/kvm64.c')
-rw-r--r--target-arm/kvm64.c37
1 files changed, 34 insertions, 3 deletions
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index ee727487b8..39c4364593 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -121,8 +121,24 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
}
+ /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+ * QEMU side we keep the current SP in xregs[31] as well.
+ */
+ if (env->pstate & PSTATE_SP) {
+ env->sp_el[1] = env->xregs[31];
+ } else {
+ env->sp_el[0] = env->xregs[31];
+ }
+
reg.id = AARCH64_CORE_REG(regs.sp);
- reg.addr = (uintptr_t) &env->xregs[31];
+ reg.addr = (uintptr_t) &env->sp_el[0];
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret) {
+ return ret;
+ }
+
+ reg.id = AARCH64_CORE_REG(sp_el1);
+ reg.addr = (uintptr_t) &env->sp_el[1];
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret) {
return ret;
@@ -152,7 +168,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
/* TODO:
- * SP_EL1
* SPSR[]
* FP state
* system registers
@@ -180,7 +195,14 @@ int kvm_arch_get_registers(CPUState *cs)
}
reg.id = AARCH64_CORE_REG(regs.sp);
- reg.addr = (uintptr_t) &env->xregs[31];
+ reg.addr = (uintptr_t) &env->sp_el[0];
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (ret) {
+ return ret;
+ }
+
+ reg.id = AARCH64_CORE_REG(sp_el1);
+ reg.addr = (uintptr_t) &env->sp_el[1];
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret) {
return ret;
@@ -194,6 +216,15 @@ int kvm_arch_get_registers(CPUState *cs)
}
pstate_write(env, val);
+ /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+ * QEMU side we keep the current SP in xregs[31] as well.
+ */
+ if (env->pstate & PSTATE_SP) {
+ env->xregs[31] = env->sp_el[1];
+ } else {
+ env->xregs[31] = env->sp_el[0];
+ }
+
reg.id = AARCH64_CORE_REG(regs.pc);
reg.addr = (uintptr_t) &env->pc;
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);