aboutsummaryrefslogtreecommitdiff
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
commita65f1de982302f5c33f668ad25a120eba7993d37 (patch)
tree68af19a05242c14ebb938b889a9f5be3728fdb94
parentf502cfc207ff288ec1f3dac10024c51ffe64a65d (diff)
target-arm: Implement AArch64 SPSR_EL1
Implement the AArch64 SPSR_EL1. For compatibility with how KVM handles SPSRs and with the architectural mapping between AArch32 and AArch64, we put this in the banked_spsr[] array in the slot that is used for SVC in AArch32. This means we need to extend the array from uint32_t to uint64_t, which requires some reworking of the 32 bit KVM save/restore code. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Acked-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c4
-rw-r--r--target-arm/kvm32.c18
-rw-r--r--target-arm/kvm64.c19
-rw-r--r--target-arm/machine.c8
5 files changed, 40 insertions, 11 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 28b9bda218..0ce4c26d16 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -143,7 +143,7 @@ typedef struct CPUARMState {
uint32_t spsr;
/* Banked registers. */
- uint32_t banked_spsr[6];
+ uint64_t banked_spsr[6];
uint32_t banked_r13[6];
uint32_t banked_r14[6];
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 27a3dc2a75..68f8c6a832 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1936,6 +1936,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.type = ARM_CP_NO_MIGRATE,
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
+ { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
+ .type = ARM_CP_NO_MIGRATE,
+ .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
+ .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[0]) },
/* We rely on the access checks not allowing the guest to write to the
* state field when SPSel indicates that it's being used as the stack
* pointer.
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index b21f844096..a690d9935f 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -295,6 +295,14 @@ typedef struct Reg {
offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R]) \
}
+/* Like COREREG, but handle fields which are in a uint64_t in CPUARMState. */
+#define COREREG64(KERNELNAME, QEMUFIELD) \
+ { \
+ KVM_REG_ARM | KVM_REG_SIZE_U32 | \
+ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
+ offsetoflow32(CPUARMState, QEMUFIELD) \
+ }
+
static const Reg regs[] = {
/* R0_usr .. R14_usr */
COREREG(usr_regs.uregs[0], regs[0]),
@@ -315,16 +323,16 @@ static const Reg regs[] = {
/* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
COREREG(svc_regs[0], banked_r13[1]),
COREREG(svc_regs[1], banked_r14[1]),
- COREREG(svc_regs[2], banked_spsr[1]),
+ COREREG64(svc_regs[2], banked_spsr[1]),
COREREG(abt_regs[0], banked_r13[2]),
COREREG(abt_regs[1], banked_r14[2]),
- COREREG(abt_regs[2], banked_spsr[2]),
+ COREREG64(abt_regs[2], banked_spsr[2]),
COREREG(und_regs[0], banked_r13[3]),
COREREG(und_regs[1], banked_r14[3]),
- COREREG(und_regs[2], banked_spsr[3]),
+ COREREG64(und_regs[2], banked_spsr[3]),
COREREG(irq_regs[0], banked_r13[4]),
COREREG(irq_regs[1], banked_r14[4]),
- COREREG(irq_regs[2], banked_spsr[4]),
+ COREREG64(irq_regs[2], banked_spsr[4]),
/* R8_fiq .. R14_fiq and SPSR_fiq */
COREREG(fiq_regs[0], fiq_regs[0]),
COREREG(fiq_regs[1], fiq_regs[1]),
@@ -333,7 +341,7 @@ static const Reg regs[] = {
COREREG(fiq_regs[4], fiq_regs[4]),
COREREG(fiq_regs[5], banked_r13[5]),
COREREG(fiq_regs[6], banked_r14[5]),
- COREREG(fiq_regs[7], banked_spsr[5]),
+ COREREG64(fiq_regs[7], banked_spsr[5]),
/* R15 */
COREREG(usr_regs.uregs[15], regs[15]),
/* VFP system registers */
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 39c4364593..e115879d9a 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -167,8 +167,16 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
+ for (i = 0; i < KVM_NR_SPSR; i++) {
+ reg.id = AARCH64_CORE_REG(spsr[i]);
+ reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret) {
+ return ret;
+ }
+ }
+
/* TODO:
- * SPSR[]
* FP state
* system registers
*/
@@ -239,6 +247,15 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
+ for (i = 0; i < KVM_NR_SPSR; i++) {
+ reg.id = AARCH64_CORE_REG(spsr[i]);
+ reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (ret) {
+ return ret;
+ }
+ }
+
/* TODO: other registers */
return ret;
}
diff --git a/target-arm/machine.c b/target-arm/machine.c
index c2c0780d4f..b967223fc0 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
const VMStateDescription vmstate_arm_cpu = {
.name = "cpu",
- .version_id = 16,
- .minimum_version_id = 16,
- .minimum_version_id_old = 16,
+ .version_id = 17,
+ .minimum_version_id = 17,
+ .minimum_version_id_old = 17,
.pre_save = cpu_pre_save,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
@@ -238,7 +238,7 @@ const VMStateDescription vmstate_arm_cpu = {
.offset = 0,
},
VMSTATE_UINT32(env.spsr, ARMCPU),
- VMSTATE_UINT32_ARRAY(env.banked_spsr, ARMCPU, 6),
+ VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6),
VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6),
VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),