#include "hw/hw.h"
#include "hw/boards.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
static bool vfp_needed(void *opaque)
{
return arm_feature(env, ARM_FEATURE_VFP);
}
+static int get_fpscr(QEMUFile *f, void *opaque, size_t size)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+ uint32_t val = qemu_get_be32(f);
+
+ vfp_set_fpscr(env, val);
+ return 0;
+}
+
+static void put_fpscr(QEMUFile *f, void *opaque, size_t size)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+
+ qemu_put_be32(f, vfp_get_fpscr(env));
+}
+
+static const VMStateInfo vmstate_fpscr = {
+ .name = "fpscr",
+ .get = get_fpscr,
+ .put = put_fpscr,
+};
+
static const VMStateDescription vmstate_vfp = {
.name = "cpu/vfp",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
.fields = (VMStateField[]) {
VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 32),
- VMSTATE_UINT32_ARRAY(env.vfp.xregs, ARMCPU, 16),
- /* TODO: Should use proper FPSCR access functions. */
- VMSTATE_INT32(env.vfp.vec_len, ARMCPU),
- VMSTATE_INT32(env.vfp.vec_stride, ARMCPU),
+ /* The xregs array is a little awkward because element 1 (FPSCR)
+ * requires a specific accessor, so we have to split it up in
+ * the vmstate:
+ */
+ VMSTATE_UINT32(env.vfp.xregs[0], ARMCPU),
+ VMSTATE_UINT32_SUB_ARRAY(env.vfp.xregs, ARMCPU, 2, 14),
+ {
+ .name = "fpscr",
+ .version_id = 0,
+ .size = sizeof(uint32_t),
+ .info = &vmstate_fpscr,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
VMSTATE_END_OF_LIST()
}
};
.put = put_cpsr,
};
+static void cpu_pre_save(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ if (kvm_enabled()) {
+ if (!write_kvmstate_to_list(cpu)) {
+ /* This should never fail */
+ abort();
+ }
+ } else {
+ if (!write_cpustate_to_list(cpu)) {
+ /* This should never fail. */
+ abort();
+ }
+ }
+
+ cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
+ memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes,
+ cpu->cpreg_array_len * sizeof(uint64_t));
+ memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
+ cpu->cpreg_array_len * sizeof(uint64_t));
+}
+
+static int cpu_post_load(void *opaque, int version_id)
+{
+ ARMCPU *cpu = opaque;
+ int i, v;
+
+ /* Update the values list from the incoming migration data.
+ * Anything in the incoming data which we don't know about is
+ * a migration failure; anything we know about but the incoming
+ * data doesn't specify retains its current (reset) value.
+ * The indexes list remains untouched -- we only inspect the
+ * incoming migration index list so we can match the values array
+ * entries with the right slots in our own values array.
+ */
+
+ for (i = 0, v = 0; i < cpu->cpreg_array_len
+ && v < cpu->cpreg_vmstate_array_len; i++) {
+ if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
+ /* register in our list but not incoming : skip it */
+ continue;
+ }
+ if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
+ /* register in their list but not ours: fail migration */
+ return -1;
+ }
+ /* matching register, copy the value over */
+ cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v];
+ v++;
+ }
+
+ if (kvm_enabled()) {
+ if (!write_list_to_kvmstate(cpu)) {
+ return -1;
+ }
+ /* Note that it's OK for the TCG side not to know about
+ * every register in the list; KVM is authoritative if
+ * we're using it.
+ */
+ write_list_to_cpustate(cpu);
+ } else {
+ if (!write_list_to_cpustate(cpu)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
const VMStateDescription vmstate_arm_cpu = {
.name = "cpu",
- .version_id = 10,
- .minimum_version_id = 10,
- .minimum_version_id_old = 10,
+ .version_id = 12,
+ .minimum_version_id = 12,
+ .minimum_version_id_old = 12,
+ .pre_save = cpu_pre_save,
+ .post_load = cpu_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16),
{
VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
- VMSTATE_UINT32(env.cp15.c0_cpuid, ARMCPU),
- VMSTATE_UINT32(env.cp15.c0_cssel, ARMCPU),
- VMSTATE_UINT32(env.cp15.c1_sys, ARMCPU),
- VMSTATE_UINT32(env.cp15.c1_coproc, ARMCPU),
- VMSTATE_UINT32(env.cp15.c1_xscaleauxcr, ARMCPU),
- VMSTATE_UINT32(env.cp15.c1_scr, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_base0, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_base0_hi, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_base1, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_base1_hi, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_control, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_mask, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_base_mask, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_data, ARMCPU),
- VMSTATE_UINT32(env.cp15.c2_insn, ARMCPU),
- VMSTATE_UINT32(env.cp15.c3, ARMCPU),
- VMSTATE_UINT32(env.cp15.c5_insn, ARMCPU),
- VMSTATE_UINT32(env.cp15.c5_data, ARMCPU),
- VMSTATE_UINT32_ARRAY(env.cp15.c6_region, ARMCPU, 8),
- VMSTATE_UINT32(env.cp15.c6_insn, ARMCPU),
- VMSTATE_UINT32(env.cp15.c6_data, ARMCPU),
- VMSTATE_UINT32(env.cp15.c7_par, ARMCPU),
- VMSTATE_UINT32(env.cp15.c7_par_hi, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_insn, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_data, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_pmcr, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_pmcnten, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_pmovsr, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_pmxevtyper, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_pmuserenr, ARMCPU),
- VMSTATE_UINT32(env.cp15.c9_pminten, ARMCPU),
- VMSTATE_UINT32(env.cp15.c13_fcse, ARMCPU),
- VMSTATE_UINT32(env.cp15.c13_context, ARMCPU),
- VMSTATE_UINT32(env.cp15.c13_tls1, ARMCPU),
- VMSTATE_UINT32(env.cp15.c13_tls2, ARMCPU),
- VMSTATE_UINT32(env.cp15.c13_tls3, ARMCPU),
- VMSTATE_UINT32(env.cp15.c15_cpar, ARMCPU),
- VMSTATE_UINT32(env.cp15.c15_power_control, ARMCPU),
- VMSTATE_UINT32(env.cp15.c15_diagnostic, ARMCPU),
- VMSTATE_UINT32(env.cp15.c15_power_diagnostic, ARMCPU),
+ /* The length-check must come before the arrays to avoid
+ * incoming data possibly overflowing the array.
+ */
+ VMSTATE_INT32_LE(cpreg_vmstate_array_len, ARMCPU),
+ VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU,
+ cpreg_vmstate_array_len,
+ 0, vmstate_info_uint64, uint64_t),
+ VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU,
+ cpreg_vmstate_array_len,
+ 0, vmstate_info_uint64, uint64_t),
+ VMSTATE_UINT32(env.exclusive_addr, ARMCPU),
+ VMSTATE_UINT32(env.exclusive_val, ARMCPU),
+ VMSTATE_UINT32(env.exclusive_high, ARMCPU),
VMSTATE_UINT64(env.features, ARMCPU),
VMSTATE_END_OF_LIST()
},