From patchwork Mon Apr 8 14:43:48 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 234806 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 06EBB2C0109 for ; Tue, 9 Apr 2013 01:13:27 +1000 (EST) Received: from localhost ([::1]:60187 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UPDl7-0005QW-13 for incoming@patchwork.ozlabs.org; Mon, 08 Apr 2013 11:13:25 -0400 Received: from eggs.gnu.org ([208.118.235.92]:52417) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UPDkW-00057f-EF for qemu-devel@nongnu.org; Mon, 08 Apr 2013 11:13:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UPDkJ-0003O7-IM for qemu-devel@nongnu.org; Mon, 08 Apr 2013 11:12:48 -0400 Received: from 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.1.0.0.b.8.0.1.0.0.2.ip6.arpa ([2001:8b0:1d0::1]:33681 helo=mnementh.archaic.org.uk) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UPDkI-0003Nv-Pk for qemu-devel@nongnu.org; Mon, 08 Apr 2013 11:12:35 -0400 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1UPDIV-0005DV-0Y; Mon, 08 Apr 2013 15:43:51 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Mon, 8 Apr 2013 15:43:48 +0100 Message-Id: <1365432230-20028-2-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1365432230-20028-1-git-send-email-peter.maydell@linaro.org> References: <1365432230-20028-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:8b0:1d0::1 Cc: Paolo Bonzini , Anthony Liguori , Juan Quintela , patches@linaro.org Subject: [Qemu-devel] [PATCH 1/3] target-arm: port ARM CPU save/load to use VMState X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Juan Quintela Port the ARM CPU save/load code to use VMState. Some state is saved in a slightly different order to simplify things -- for example arrays are saved one after the other rather than 'striped', and we always save all 32 VFP registers even if the CPU happens to only have 16. Use one subsection for each feature. This means that we don't need to bump the version field each time that a new feature gets introduced. Signed-off-by: Juan Quintela [PMM: fixed conflicts, updated to use cpu_class_set_vmsd(), updated with new/removed fields since original patch, changed to use custom VMStateInfo for cpsr rather than presave/postload hooks, corrected subsection names so vmload doesn't fail] Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 4 + target-arm/cpu.c | 1 + target-arm/cpu.h | 2 - target-arm/machine.c | 387 +++++++++++++++++++++++--------------------------- 4 files changed, 179 insertions(+), 215 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 2589550..12fcefe 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 a1e9093..496a59f 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 2b97221..5438444 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 68dca7f..3c41f06 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -1,237 +1,198 @@ #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]); - } + return arm_feature(env, ARM_FEATURE_VFP); +} +static const VMStateDescription vmstate_vfp = { + .name = "cpu/vfp", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .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. */ - 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); - } - } + VMSTATE_INT32(env.vfp.vec_len, ARMCPU), + VMSTATE_INT32(env.vfp.vec_stride, ARMCPU), + VMSTATE_END_OF_LIST() } +}; - 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]); - } - } +static bool iwmmxt_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; - 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); - } + return arm_feature(env, ARM_FEATURE_IWMMXT); +} - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { - qemu_put_be32(f, env->teecr); - qemu_put_be32(f, env->teehbr); +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); } -int cpu_load(QEMUFile *f, void *opaque, int version_id) +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) { - CPUARMState *env = (CPUARMState *)opaque; - int i; - uint32_t val; + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; - if (version_id != CPU_SAVE_VERSION) - return -EINVAL; + return arm_feature(env, ARM_FEATURE_THUMB2EE); +} - for (i = 0; i < 16; i++) { - env->regs[i] = qemu_get_be32(f); +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() } - val = qemu_get_be32(f); - /* Avoid mode switch when restoring CPSR. */ +}; + +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); - 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; - } - } - } + return 0; +} - 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); - } - } +static void put_cpsr(QEMUFile *f, void *opaque, size_t size) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; - 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); - } + qemu_put_be32(f, cpsr_read(env)); +} - if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { - env->teecr = qemu_get_be32(f); - env->teehbr = qemu_get_be32(f); +static const VMStateInfo vmstate_cpsr = { + .name = "cpsr", + .get = get_cpsr, + .put = put_cpsr, +}; + +const VMStateDescription vmstate_arm_cpu = { + .name = "cpu", + .version_id = 10, + .minimum_version_id = 10, + .minimum_version_id_old = 10, + .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_power_control, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_diagnostic, ARMCPU), + VMSTATE_UINT32(env.cp15.c15_power_diagnostic, 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 */ + } } - - return 0; -} +};