aboutsummaryrefslogtreecommitdiff
path: root/target/arm/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/machine.c')
-rw-r--r--target/arm/machine.c113
1 files changed, 112 insertions, 1 deletions
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 6666a0c..44a0cf8 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -816,6 +816,80 @@ static const VMStateInfo vmstate_cpsr = {
.put = put_cpsr,
};
+static int get_pstate64(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+ uint64_t val = qemu_get_be64(f);
+
+ env->aarch64 = ((val & PSTATE_nRW) == 0);
+ if (is_a64(env)) {
+ pstate_write(env, val);
+ } else {
+ cpsr_write_from_spsr_elx(env, val);
+ }
+ return 0;
+}
+
+static int put_pstate64(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field, JSONWriter *vmdesc)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+ uint64_t val;
+
+ if (is_a64(env)) {
+ val = pstate_read(env);
+ } else {
+ val = cpsr_read_for_spsr_elx(env);
+ }
+ qemu_put_be64(f, val);
+ return 0;
+}
+
+static bool pstate64_needed(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+ uint64_t val;
+
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (is_a64(env)) {
+ val = pstate_read(env);
+ } else {
+ val = cpsr_read_for_spsr_elx(env);
+ if (val & PSTATE_SS) {
+ return true;
+ }
+ }
+ return val > UINT32_MAX;
+}
+
+static const VMStateDescription vmstate_pstate64 = {
+ .name = "cpu/pstate64",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pstate64_needed,
+ .fields = (const VMStateField[]) {
+ {
+ .name = "pstate64",
+ .version_id = 0,
+ .size = sizeof(uint64_t),
+ .info = &(const VMStateInfo) {
+ .name = "pstate64",
+ .get = get_pstate64,
+ .put = put_pstate64,
+ },
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static int get_power(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field)
{
@@ -848,6 +922,23 @@ static const VMStateInfo vmstate_powered_off = {
.put = put_power,
};
+static bool syndrome64_needed(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+ return cpu->env.exception.syndrome > UINT32_MAX;
+}
+
+static const VMStateDescription vmstate_syndrome64 = {
+ .name = "cpu/syndrome64",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = syndrome64_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(env.exception.syndrome, ARMCPU),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static int cpu_pre_save(void *opaque)
{
ARMCPU *cpu = opaque;
@@ -1035,6 +1126,12 @@ const VMStateDescription vmstate_arm_cpu = {
VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16),
VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32),
VMSTATE_UINT64(env.pc, ARMCPU),
+ /*
+ * If any bits are set in the upper 32 bits of cpsr/pstate,
+ * or if the cpu is in aa32 mode and PSTATE.SS is set, then
+ * the cpu/pstate64 subsection will override this with the
+ * full 64 bit state.
+ */
{
.name = "cpsr",
.version_id = 0,
@@ -1065,7 +1162,19 @@ const VMStateDescription vmstate_arm_cpu = {
VMSTATE_UINT64(env.exclusive_val, ARMCPU),
VMSTATE_UINT64(env.exclusive_high, ARMCPU),
VMSTATE_UNUSED(sizeof(uint64_t)),
- VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
+ /*
+ * If any bits are set in the upper 32 bits of syndrome,
+ * then the cpu/syndrome64 subsection will override this
+ * with the full 64 bit state.
+ */
+ {
+ .name = "env.exception.syndrome",
+ .version_id = 0,
+ .size = sizeof(uint32_t),
+ .info = &vmstate_info_uint32,
+ .flags = VMS_SINGLE,
+ .offset = offsetoflow32(ARMCPU, env.exception.syndrome),
+ },
VMSTATE_UINT32(env.exception.fsr, ARMCPU),
VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU),
@@ -1098,6 +1207,8 @@ const VMStateDescription vmstate_arm_cpu = {
&vmstate_serror,
&vmstate_irq_line_state,
&vmstate_wfxt_timer,
+ &vmstate_syndrome64,
+ &vmstate_pstate64,
NULL
}
};