diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 25895509be..12fcefe0c6 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -111,6 +111,10 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) #define ENV_OFFSET offsetof(ARMCPU, env) +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_arm_cpu; +#endif + void register_cp_regs_for_features(ARMCPU *cpu); void arm_cpu_do_interrupt(CPUState *cpu); diff --git a/target-arm/cpu.c b/target-arm/cpu.c index a1e90939d6..496a59f5c0 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -814,6 +814,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = arm_cpu_class_by_name; cc->do_interrupt = arm_cpu_do_interrupt; + cpu_class_set_vmsd(cc, &vmstate_arm_cpu); } static void cpu_register(const ARMCPUInfo *info) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 2b97221209..54384446b4 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -640,8 +640,6 @@ static inline CPUARMState *cpu_init(const char *cpu_model) #define cpu_signal_handler cpu_arm_signal_handler #define cpu_list arm_cpu_list -#define CPU_SAVE_VERSION 9 - /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _user diff --git a/target-arm/machine.c b/target-arm/machine.c index 68dca7ffb2..4dd057c488 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -1,237 +1,239 @@ #include "hw/hw.h" #include "hw/boards.h" -void cpu_save(QEMUFile *f, void *opaque) +static bool vfp_needed(void *opaque) { - int i; - CPUARMState *env = (CPUARMState *)opaque; + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; - for (i = 0; i < 16; i++) { - qemu_put_be32(f, env->regs[i]); - } - qemu_put_be32(f, cpsr_read(env)); - qemu_put_be32(f, env->spsr); - for (i = 0; i < 6; i++) { - qemu_put_be32(f, env->banked_spsr[i]); - qemu_put_be32(f, env->banked_r13[i]); - qemu_put_be32(f, env->banked_r14[i]); - } - for (i = 0; i < 5; i++) { - qemu_put_be32(f, env->usr_regs[i]); - qemu_put_be32(f, env->fiq_regs[i]); - } - qemu_put_be32(f, env->cp15.c0_cpuid); - qemu_put_be32(f, env->cp15.c0_cssel); - qemu_put_be32(f, env->cp15.c1_sys); - qemu_put_be32(f, env->cp15.c1_coproc); - qemu_put_be32(f, env->cp15.c1_xscaleauxcr); - qemu_put_be32(f, env->cp15.c1_scr); - qemu_put_be32(f, env->cp15.c2_base0); - qemu_put_be32(f, env->cp15.c2_base0_hi); - qemu_put_be32(f, env->cp15.c2_base1); - qemu_put_be32(f, env->cp15.c2_base1_hi); - qemu_put_be32(f, env->cp15.c2_control); - qemu_put_be32(f, env->cp15.c2_mask); - qemu_put_be32(f, env->cp15.c2_base_mask); - qemu_put_be32(f, env->cp15.c2_data); - qemu_put_be32(f, env->cp15.c2_insn); - qemu_put_be32(f, env->cp15.c3); - qemu_put_be32(f, env->cp15.c5_insn); - qemu_put_be32(f, env->cp15.c5_data); - for (i = 0; i < 8; i++) { - qemu_put_be32(f, env->cp15.c6_region[i]); - } - qemu_put_be32(f, env->cp15.c6_insn); - qemu_put_be32(f, env->cp15.c6_data); - qemu_put_be32(f, env->cp15.c7_par); - qemu_put_be32(f, env->cp15.c7_par_hi); - qemu_put_be32(f, env->cp15.c9_insn); - qemu_put_be32(f, env->cp15.c9_data); - qemu_put_be32(f, env->cp15.c9_pmcr); - qemu_put_be32(f, env->cp15.c9_pmcnten); - qemu_put_be32(f, env->cp15.c9_pmovsr); - qemu_put_be32(f, env->cp15.c9_pmxevtyper); - qemu_put_be32(f, env->cp15.c9_pmuserenr); - qemu_put_be32(f, env->cp15.c9_pminten); - qemu_put_be32(f, env->cp15.c13_fcse); - qemu_put_be32(f, env->cp15.c13_context); - qemu_put_be32(f, env->cp15.c13_tls1); - qemu_put_be32(f, env->cp15.c13_tls2); - qemu_put_be32(f, env->cp15.c13_tls3); - qemu_put_be32(f, env->cp15.c15_cpar); - qemu_put_be32(f, env->cp15.c15_power_control); - qemu_put_be32(f, env->cp15.c15_diagnostic); - qemu_put_be32(f, env->cp15.c15_power_diagnostic); - - qemu_put_be64(f, env->features); - - if (arm_feature(env, ARM_FEATURE_VFP)) { - for (i = 0; i < 16; i++) { - CPU_DoubleU u; - u.d = env->vfp.regs[i]; - qemu_put_be32(f, u.l.upper); - qemu_put_be32(f, u.l.lower); - } - for (i = 0; i < 16; i++) { - qemu_put_be32(f, env->vfp.xregs[i]); - } - - /* TODO: Should use proper FPSCR access functions. */ - qemu_put_be32(f, env->vfp.vec_len); - qemu_put_be32(f, env->vfp.vec_stride); - - if (arm_feature(env, ARM_FEATURE_VFP3)) { - for (i = 16; i < 32; i++) { - CPU_DoubleU u; - u.d = env->vfp.regs[i]; - qemu_put_be32(f, u.l.upper); - qemu_put_be32(f, u.l.lower); - } - } - } - - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - for (i = 0; i < 16; i++) { - qemu_put_be64(f, env->iwmmxt.regs[i]); - } - for (i = 0; i < 16; i++) { - qemu_put_be32(f, env->iwmmxt.cregs[i]); - } - } - - if (arm_feature(env, ARM_FEATURE_M)) { - qemu_put_be32(f, env->v7m.other_sp); - qemu_put_be32(f, env->v7m.vecbase); - qemu_put_be32(f, env->v7m.basepri); - qemu_put_be32(f, env->v7m.control); - qemu_put_be32(f, env->v7m.current_sp); - qemu_put_be32(f, env->v7m.exception); - } - - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { - qemu_put_be32(f, env->teecr); - qemu_put_be32(f, env->teehbr); - } + return arm_feature(env, ARM_FEATURE_VFP); } -int cpu_load(QEMUFile *f, void *opaque, int version_id) +static int get_fpscr(QEMUFile *f, void *opaque, size_t size) { - CPUARMState *env = (CPUARMState *)opaque; - int i; - uint32_t val; - - if (version_id != CPU_SAVE_VERSION) - return -EINVAL; - - for (i = 0; i < 16; i++) { - env->regs[i] = qemu_get_be32(f); - } - val = qemu_get_be32(f); - /* Avoid mode switch when restoring CPSR. */ - env->uncached_cpsr = val & CPSR_M; - cpsr_write(env, val, 0xffffffff); - env->spsr = qemu_get_be32(f); - for (i = 0; i < 6; i++) { - env->banked_spsr[i] = qemu_get_be32(f); - env->banked_r13[i] = qemu_get_be32(f); - env->banked_r14[i] = qemu_get_be32(f); - } - for (i = 0; i < 5; i++) { - env->usr_regs[i] = qemu_get_be32(f); - env->fiq_regs[i] = qemu_get_be32(f); - } - env->cp15.c0_cpuid = qemu_get_be32(f); - env->cp15.c0_cssel = qemu_get_be32(f); - env->cp15.c1_sys = qemu_get_be32(f); - env->cp15.c1_coproc = qemu_get_be32(f); - env->cp15.c1_xscaleauxcr = qemu_get_be32(f); - env->cp15.c1_scr = qemu_get_be32(f); - env->cp15.c2_base0 = qemu_get_be32(f); - env->cp15.c2_base0_hi = qemu_get_be32(f); - env->cp15.c2_base1 = qemu_get_be32(f); - env->cp15.c2_base1_hi = qemu_get_be32(f); - env->cp15.c2_control = qemu_get_be32(f); - env->cp15.c2_mask = qemu_get_be32(f); - env->cp15.c2_base_mask = qemu_get_be32(f); - env->cp15.c2_data = qemu_get_be32(f); - env->cp15.c2_insn = qemu_get_be32(f); - env->cp15.c3 = qemu_get_be32(f); - env->cp15.c5_insn = qemu_get_be32(f); - env->cp15.c5_data = qemu_get_be32(f); - for (i = 0; i < 8; i++) { - env->cp15.c6_region[i] = qemu_get_be32(f); - } - env->cp15.c6_insn = qemu_get_be32(f); - env->cp15.c6_data = qemu_get_be32(f); - env->cp15.c7_par = qemu_get_be32(f); - env->cp15.c7_par_hi = qemu_get_be32(f); - env->cp15.c9_insn = qemu_get_be32(f); - env->cp15.c9_data = qemu_get_be32(f); - env->cp15.c9_pmcr = qemu_get_be32(f); - env->cp15.c9_pmcnten = qemu_get_be32(f); - env->cp15.c9_pmovsr = qemu_get_be32(f); - env->cp15.c9_pmxevtyper = qemu_get_be32(f); - env->cp15.c9_pmuserenr = qemu_get_be32(f); - env->cp15.c9_pminten = qemu_get_be32(f); - env->cp15.c13_fcse = qemu_get_be32(f); - env->cp15.c13_context = qemu_get_be32(f); - env->cp15.c13_tls1 = qemu_get_be32(f); - env->cp15.c13_tls2 = qemu_get_be32(f); - env->cp15.c13_tls3 = qemu_get_be32(f); - env->cp15.c15_cpar = qemu_get_be32(f); - env->cp15.c15_power_control = qemu_get_be32(f); - env->cp15.c15_diagnostic = qemu_get_be32(f); - env->cp15.c15_power_diagnostic = qemu_get_be32(f); - - env->features = qemu_get_be64(f); - - if (arm_feature(env, ARM_FEATURE_VFP)) { - for (i = 0; i < 16; i++) { - CPU_DoubleU u; - u.l.upper = qemu_get_be32(f); - u.l.lower = qemu_get_be32(f); - env->vfp.regs[i] = u.d; - } - for (i = 0; i < 16; i++) { - env->vfp.xregs[i] = qemu_get_be32(f); - } - - /* TODO: Should use proper FPSCR access functions. */ - env->vfp.vec_len = qemu_get_be32(f); - env->vfp.vec_stride = qemu_get_be32(f); - - if (arm_feature(env, ARM_FEATURE_VFP3)) { - for (i = 16; i < 32; i++) { - CPU_DoubleU u; - u.l.upper = qemu_get_be32(f); - u.l.lower = qemu_get_be32(f); - env->vfp.regs[i] = u.d; - } - } - } - - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - for (i = 0; i < 16; i++) { - env->iwmmxt.regs[i] = qemu_get_be64(f); - } - for (i = 0; i < 16; i++) { - env->iwmmxt.cregs[i] = qemu_get_be32(f); - } - } - - if (arm_feature(env, ARM_FEATURE_M)) { - env->v7m.other_sp = qemu_get_be32(f); - env->v7m.vecbase = qemu_get_be32(f); - env->v7m.basepri = qemu_get_be32(f); - env->v7m.control = qemu_get_be32(f); - env->v7m.current_sp = qemu_get_be32(f); - env->v7m.exception = qemu_get_be32(f); - } - - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { - env->teecr = qemu_get_be32(f); - env->teehbr = qemu_get_be32(f); - } + 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 = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 32), + /* 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() + } +}; + +static bool iwmmxt_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + return arm_feature(env, ARM_FEATURE_IWMMXT); +} + +static const VMStateDescription vmstate_iwmmxt = { + .name = "cpu/iwmmxt", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16), + VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16), + VMSTATE_END_OF_LIST() + } +}; + +static bool m_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + return arm_feature(env, ARM_FEATURE_M); +} + +const VMStateDescription vmstate_m = { + .name = "cpu/m", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.v7m.other_sp, ARMCPU), + VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), + VMSTATE_UINT32(env.v7m.basepri, ARMCPU), + VMSTATE_UINT32(env.v7m.control, ARMCPU), + VMSTATE_INT32(env.v7m.current_sp, ARMCPU), + VMSTATE_INT32(env.v7m.exception, ARMCPU), + VMSTATE_END_OF_LIST() + } +}; + +static bool thumb2ee_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + return arm_feature(env, ARM_FEATURE_THUMB2EE); +} + +static const VMStateDescription vmstate_thumb2ee = { + .name = "cpu/thumb2ee", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.teecr, ARMCPU), + VMSTATE_UINT32(env.teehbr, ARMCPU), + VMSTATE_END_OF_LIST() + } +}; + +static int get_cpsr(QEMUFile *f, void *opaque, size_t size) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + uint32_t val = qemu_get_be32(f); + + /* Avoid mode switch when restoring CPSR */ + env->uncached_cpsr = val & CPSR_M; + cpsr_write(env, val, 0xffffffff); + return 0; +} + +static void put_cpsr(QEMUFile *f, void *opaque, size_t size) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + qemu_put_be32(f, cpsr_read(env)); +} + +static const VMStateInfo vmstate_cpsr = { + .name = "cpsr", + .get = get_cpsr, + .put = put_cpsr, +}; + +const VMStateDescription vmstate_arm_cpu = { + .name = "cpu", + .version_id = 11, + .minimum_version_id = 11, + .minimum_version_id_old = 11, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), + { + .name = "cpsr", + .version_id = 0, + .size = sizeof(uint32_t), + .info = &vmstate_cpsr, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_UINT32(env.spsr, ARMCPU), + VMSTATE_UINT32_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), + 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_ticonfig, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_i_max, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_i_min, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_threadid, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_power_control, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_diagnostic, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_power_diagnostic, ARMCPU), + 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() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_vfp, + .needed = vfp_needed, + } , { + .vmsd = &vmstate_iwmmxt, + .needed = iwmmxt_needed, + } , { + .vmsd = &vmstate_m, + .needed = m_needed, + } , { + .vmsd = &vmstate_thumb2ee, + .needed = thumb2ee_needed, + } , { + /* empty */ + } + } +}; diff --git a/target-arm/translate.c b/target-arm/translate.c index 35a21be931..a1b7b8c1a8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6762,6 +6762,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } ARCH(6); gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21)); + return; } else if ((insn & 0x0e50ffe0) == 0x08100a00) { /* rfe */ int32_t offset;