From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:33648) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RsZnd-0004Sw-6A for qemu-devel@nongnu.org; Wed, 01 Feb 2012 08:00:41 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RsZnE-0005Qt-3q for qemu-devel@nongnu.org; Wed, 01 Feb 2012 08:00:28 -0500 Received: from cantor2.suse.de ([195.135.220.15]:37186 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RsZnC-0005NM-PL for qemu-devel@nongnu.org; Wed, 01 Feb 2012 08:00:07 -0500 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 1 Feb 2012 13:57:25 +0100 Message-Id: <1328101045-10717-9-git-send-email-afaerber@suse.de> In-Reply-To: <1328101045-10717-1-git-send-email-afaerber@suse.de> References: <1328101045-10717-1-git-send-email-afaerber@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH RFC v2 8/8] target-arm: Move CPU feature flags out of CPUState List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Peter Maydell , =?UTF-8?q?Andreas=20F=C3=A4rber?= The internal CPU feature flags were only ever set in cpu_reset_model_id(). Therefore move their initialization into ARMCPUClass. We might want to tweak them in the future though (e.g., -cpu cortex-r4,+fpu), so keep a copy in ARMCPU. This in turn means we need to infer features for both ARMCPUClass and ARMCPU, so move feature inference to arm_infer_features() and use macros to simplify it. Since cpu.h defines ARMCPUState, which has been incorporated into ARMCPU, and tries to use arm_feature() in cpu_get_tb_cpu_state(), move arm_feature() to cpu-core.h and add a forward declaration. Signed-off-by: Andreas F=C3=A4rber Cc: Peter Maydell --- target-arm/cpu-core.c | 159 +++++++++++++++++++++++++++++++++++++++++++= ++++++ target-arm/cpu-core.h | 12 ++++ target-arm/cpu.h | 9 +-- target-arm/helper.c | 95 ----------------------------- target-arm/machine.c | 6 +- 5 files changed, 177 insertions(+), 104 deletions(-) diff --git a/target-arm/cpu-core.c b/target-arm/cpu-core.c index 8284418..3dac540 100644 --- a/target-arm/cpu-core.c +++ b/target-arm/cpu-core.c @@ -15,27 +15,126 @@ static void arm_cpu_reset(CPU *c) cpu_common_reset(c); } =20 +/* CPU feature flags */ + +#define ARM_FEATURE(x) (1u << ARM_FEATURE_ ## x) + +#define has_feature(x) ((*features & ARM_FEATURE(x)) !=3D 0) +#define set_feature(x) (*features |=3D ARM_FEATURE(x)) + +/** + * arm_infer_features: + * @features: Pointer to the feature flags of #ARMCPUClass or #ARMCPU. + * + * Some features automatically imply others. + */ +static void arm_infer_features(uint32_t *features) +{ + if (has_feature(V7)) { + set_feature(VAPA); + set_feature(THUMB2); + if (!has_feature(M)) { + set_feature(V6K); + } else { + set_feature(V6); + } + } + if (has_feature(V6K)) { + set_feature(V6); + } + if (has_feature(V6)) { + set_feature(V5); + if (!has_feature(M)) { + set_feature(AUXCR); + } + } + if (has_feature(V5)) { + set_feature(V4T); + } + if (has_feature(M)) { + set_feature(THUMB_DIV); + } + if (has_feature(ARM_DIV)) { + set_feature(THUMB_DIV); + } + if (has_feature(VFP4)) { + set_feature(VFP3); + } + if (has_feature(VFP3)) { + set_feature(VFP); + } +} + +#undef has_feature +#undef set_feature + +static inline void set_class_feature(ARMCPUClass *klass, int feature) +{ + klass->features |=3D 1u << feature; +} + +static inline void unset_class_feature(ARMCPUClass *klass, int feature) +{ + klass->features &=3D ~(1u << feature); +} + /* CPU models */ =20 typedef struct ARMCPUInfo { const char *name; const char *alias; uint32_t id; + uint32_t features; void (*class_init)(ARMCPUClass *klass, const struct ARMCPUInfo *info= ); } ARMCPUInfo; =20 +static void arm1136_r0_class_init(ARMCPUClass *k, const ARMCPUInfo *info= ) +{ + ARMCPUClass *r1_class; + + r1_class =3D ARM_CPU_CLASS(object_class_by_name("arm1136")); + + k->features =3D r1_class->features; + unset_class_feature(k, ARM_FEATURE_V6K); +} + +static void sa11xx_class_init(ARMCPUClass *k, const ARMCPUInfo *info) +{ + set_class_feature(k, ARM_FEATURE_STRONGARM); +} + +static void pxa25x_class_init(ARMCPUClass *k, const ARMCPUInfo *info) +{ + set_class_feature(k, ARM_FEATURE_V5); + set_class_feature(k, ARM_FEATURE_XSCALE); +} + +static void pxa270_class_init(ARMCPUClass *k, const ARMCPUInfo *info) +{ + set_class_feature(k, ARM_FEATURE_V5); + set_class_feature(k, ARM_FEATURE_XSCALE); + set_class_feature(k, ARM_FEATURE_IWMMXT); +} + static const ARMCPUInfo arm_cpus[] =3D { { .name =3D "arm926", .id =3D 0x41069265, + .features =3D ARM_FEATURE(V5) | + ARM_FEATURE(VFP), }, { .name =3D "arm946", .id =3D 0x41059461, + .features =3D ARM_FEATURE(V5) | + ARM_FEATURE(MPU), }, { .name =3D "arm1026", .id =3D 0x4106a262, + .features =3D ARM_FEATURE(V5) | + ARM_FEATURE(VFP) | + ARM_FEATURE(AUXCR), }, /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an * older core than plain "arm1136". In particular this does not @@ -44,95 +143,150 @@ static const ARMCPUInfo arm_cpus[] =3D { { .name =3D "arm1136-r2", .id =3D 0x4107b362, + .class_init =3D arm1136_r0_class_init, }, { .name =3D "arm1136", .id =3D 0x4117b363, + .features =3D ARM_FEATURE(V6) | + ARM_FEATURE(VFP), }, { .name =3D "arm1176", .id =3D 0x410fb767, + .features =3D ARM_FEATURE(V6K) | + ARM_FEATURE(VFP) | + ARM_FEATURE(VAPA), }, { .name =3D "arm11mpcore", .id =3D 0x410fb022, + .features =3D ARM_FEATURE(V6K) | + ARM_FEATURE(VFP) | + ARM_FEATURE(VAPA), }, { .name =3D "cortex-m3", .id =3D 0x410fc231, + .features =3D ARM_FEATURE(V7) | + ARM_FEATURE(M), }, { .name =3D "cortex-a8", .id =3D 0x410fc080, + .features =3D ARM_FEATURE(V7) | + ARM_FEATURE(VFP3) | + ARM_FEATURE(NEON) | + ARM_FEATURE(THUMB2EE), }, { .name =3D "cortex-a9", .id =3D 0x410fc090, + .features =3D ARM_FEATURE(V7) | + ARM_FEATURE(VFP3) | + ARM_FEATURE(VFP_FP16) | + ARM_FEATURE(NEON) | + ARM_FEATURE(THUMB2EE) | + /* Note that A9 supports the MP extensions even for + * A9UP and single-core A9MP (which are both differe= nt + * and valid configurations; we don't model A9UP). + */ + ARM_FEATURE(V7MP), }, { .name =3D "cortex-a15", .id =3D 0x412fc0f1, + .features =3D ARM_FEATURE(V7) | + ARM_FEATURE(VFP4) | + ARM_FEATURE(VFP_FP16) | + ARM_FEATURE(NEON) | + ARM_FEATURE(THUMB2EE) | + ARM_FEATURE(ARM_DIV) | + ARM_FEATURE(V7MP) | + ARM_FEATURE(GENERIC_TIMER), }, { .name =3D "ti925t", .id =3D 0x54029252, + .features =3D ARM_FEATURE(V4T) | + ARM_FEATURE(OMAPCP), }, { .name =3D "sa1100", .id =3D 0x4401A11B, + .class_init =3D sa11xx_class_init, }, { .name =3D "sa1110", .id =3D 0x6901B119, + .class_init =3D sa11xx_class_init, }, { .name =3D "pxa250", .id =3D 0x69052100, + .class_init =3D pxa25x_class_init, }, { .name =3D "pxa255", .id =3D 0x69052d00, + .class_init =3D pxa25x_class_init, }, { .name =3D "pxa260", .id =3D 0x69052903, + .class_init =3D pxa25x_class_init, }, { .name =3D "pxa261", .id =3D 0x69052d05, + .class_init =3D pxa25x_class_init, }, { .name =3D "pxa262", .id =3D 0x69052d06, + .class_init =3D pxa25x_class_init, }, { .name =3D "pxa270-a0", .alias =3D "pxa270", .id =3D 0x69054110, + .class_init =3D pxa270_class_init, }, { .name =3D "pxa270-a1", .id =3D 0x69054111, + .class_init =3D pxa270_class_init, }, { .name =3D "pxa270-b0", .id =3D 0x69054112, + .class_init =3D pxa270_class_init, }, { .name =3D "pxa270-b1", .id =3D 0x69054113, + .class_init =3D pxa270_class_init, }, { .name =3D "pxa270-c0", .id =3D 0x69054114, + .class_init =3D pxa270_class_init, }, { .name =3D "pxa270-c5", .id =3D 0x69054117, + .class_init =3D pxa270_class_init, }, { .name =3D "any", .id =3D 0xffffffff, + .features =3D ARM_FEATURE(V7) | + ARM_FEATURE(VFP4) | + ARM_FEATURE(VFP_FP16) | + ARM_FEATURE(NEON) | + ARM_FEATURE(THUMB2EE) | + ARM_FEATURE(ARM_DIV) | + ARM_FEATURE(V7MP), }, }; =20 @@ -141,6 +295,8 @@ static void arm_cpu_initfn(Object *obj) ARMCPU *cpu =3D ARM_CPU(obj); ARMCPUClass *cpu_class =3D ARM_CPU_GET_CLASS(obj); =20 + cpu->features =3D cpu_class->features; + memset(&cpu->env, 0, sizeof(CPUARMState)); cpu_exec_init(&cpu->env); =20 @@ -157,10 +313,13 @@ static void arm_cpu_class_init(ObjectClass *klass, = void *data) cpu_class->reset =3D arm_cpu_reset; =20 k->id =3D info->id; + k->features =3D info->features; =20 if (info->class_init !=3D NULL) { (*info->class_init)(k, info); } + + arm_infer_features(&k->features); } =20 static void cpu_register(const ARMCPUInfo *info) diff --git a/target-arm/cpu-core.h b/target-arm/cpu-core.h index cd3af77..4966dba 100644 --- a/target-arm/cpu-core.h +++ b/target-arm/cpu-core.h @@ -31,6 +31,9 @@ typedef struct ARMCPUClass { CPUClass parent_class; =20 uint32_t id; + + /* Internal CPU feature flags. */ + uint32_t features; } ARMCPUClass; =20 /** @@ -41,6 +44,9 @@ typedef struct ARMCPUClass { typedef struct ARMCPU { CPU parent_obj; =20 + /* Internal CPU feature flags. */ + uint32_t features; + /* TODO Inline this and split off common state */ CPUARMState env; } ARMCPU; @@ -52,5 +58,11 @@ static inline Object *arm_env_get_object(CPUARMState *= env) =20 #define ENV_GET_OBJECT(e) arm_env_get_object(e) =20 +static inline int arm_feature(CPUARMState *env, int feature) +{ + ARMCPU *cpu =3D ARM_CPU(ENV_GET_OBJECT(env)); + return (cpu->features & (1u << feature)) !=3D 0; +} + =20 #endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 0d9b39c..b595e48 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -170,9 +170,6 @@ typedef struct CPUARMState { uint32_t teecr; uint32_t teehbr; =20 - /* Internal CPU feature flags. */ - uint32_t features; - /* VFP coprocessor state. */ struct { float64 regs[32]; @@ -385,10 +382,7 @@ enum arm_features { ARM_FEATURE_GENERIC_TIMER, }; =20 -static inline int arm_feature(CPUARMState *env, int feature) -{ - return (env->features & (1u << feature)) !=3D 0; -} +static inline int arm_feature(CPUARMState *env, int feature); =20 void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); =20 @@ -476,6 +470,7 @@ static inline void cpu_clone_regs(CPUState *env, targ= et_ulong newsp) #endif =20 #include "cpu-all.h" +#include "cpu-core.h" =20 /* Bit usage in the TB flags field: */ #define ARM_TBFLAG_THUMB_SHIFT 0 diff --git a/target-arm/helper.c b/target-arm/helper.c index 34b1d24..f98eeae 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -52,47 +52,32 @@ static uint32_t arm1176_cp15_c0_c1[8] =3D static uint32_t arm1176_cp15_c0_c2[8] =3D { 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 }; =20 -static inline void set_feature(CPUARMState *env, int feature) -{ - env->features |=3D 1u << feature; -} - static void cpu_reset_model_id(CPUARMState *env, uint32_t id) { env->cp15.c0_cpuid =3D id; switch (id) { case ARM_CPUID_ARM926: - set_feature(env, ARM_FEATURE_V5); - set_feature(env, ARM_FEATURE_VFP); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x41011090; env->cp15.c0_cachetype =3D 0x1dd20d2; env->cp15.c1_sys =3D 0x00090078; break; case ARM_CPUID_ARM946: - set_feature(env, ARM_FEATURE_V5); - set_feature(env, ARM_FEATURE_MPU); env->cp15.c0_cachetype =3D 0x0f004006; env->cp15.c1_sys =3D 0x00000078; break; case ARM_CPUID_ARM1026: - set_feature(env, ARM_FEATURE_V5); - set_feature(env, ARM_FEATURE_VFP); - set_feature(env, ARM_FEATURE_AUXCR); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x410110a0; env->cp15.c0_cachetype =3D 0x1dd20d2; env->cp15.c1_sys =3D 0x00090078; break; case ARM_CPUID_ARM1136: /* This is the 1136 r1, which is a v6K core */ - set_feature(env, ARM_FEATURE_V6K); /* Fall through */ case ARM_CPUID_ARM1136_R2: /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an * older core than plain "arm1136". In particular this does not * have the v6K features. */ - set_feature(env, ARM_FEATURE_V6); - set_feature(env, ARM_FEATURE_VFP); /* These ID register values are correct for 1136 but may be wron= g * for 1136_r2 (in particular r0p2 does not actually implement m= ost * of the ID registers). @@ -106,9 +91,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint3= 2_t id) env->cp15.c1_sys =3D 0x00050078; break; case ARM_CPUID_ARM1176: - set_feature(env, ARM_FEATURE_V6K); - set_feature(env, ARM_FEATURE_VFP); - set_feature(env, ARM_FEATURE_VAPA); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x410120b5; env->vfp.xregs[ARM_VFP_MVFR0] =3D 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] =3D 0x00000000; @@ -118,9 +100,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint= 32_t id) env->cp15.c1_sys =3D 0x00050078; break; case ARM_CPUID_ARM11MPCORE: - set_feature(env, ARM_FEATURE_V6K); - set_feature(env, ARM_FEATURE_VFP); - set_feature(env, ARM_FEATURE_VAPA); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x410120b4; env->vfp.xregs[ARM_VFP_MVFR0] =3D 0x11111111; env->vfp.xregs[ARM_VFP_MVFR1] =3D 0x00000000; @@ -129,10 +108,6 @@ static void cpu_reset_model_id(CPUARMState *env, uin= t32_t id) env->cp15.c0_cachetype =3D 0x1dd20d2; break; case ARM_CPUID_CORTEXA8: - set_feature(env, ARM_FEATURE_V7); - set_feature(env, ARM_FEATURE_VFP3); - set_feature(env, ARM_FEATURE_NEON); - set_feature(env, ARM_FEATURE_THUMB2EE); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x410330c0; env->vfp.xregs[ARM_VFP_MVFR0] =3D 0x11110222; env->vfp.xregs[ARM_VFP_MVFR1] =3D 0x00011100; @@ -146,16 +121,6 @@ static void cpu_reset_model_id(CPUARMState *env, uin= t32_t id) env->cp15.c1_sys =3D 0x00c50078; break; case ARM_CPUID_CORTEXA9: - set_feature(env, ARM_FEATURE_V7); - set_feature(env, ARM_FEATURE_VFP3); - set_feature(env, ARM_FEATURE_VFP_FP16); - set_feature(env, ARM_FEATURE_NEON); - set_feature(env, ARM_FEATURE_THUMB2EE); - /* Note that A9 supports the MP extensions even for - * A9UP and single-core A9MP (which are both different - * and valid configurations; we don't model A9UP). - */ - set_feature(env, ARM_FEATURE_V7MP); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x41034000; /* Guess */ env->vfp.xregs[ARM_VFP_MVFR0] =3D 0x11110222; env->vfp.xregs[ARM_VFP_MVFR1] =3D 0x01111111; @@ -168,14 +133,6 @@ static void cpu_reset_model_id(CPUARMState *env, uin= t32_t id) env->cp15.c1_sys =3D 0x00c50078; break; case ARM_CPUID_CORTEXA15: - set_feature(env, ARM_FEATURE_V7); - set_feature(env, ARM_FEATURE_VFP4); - set_feature(env, ARM_FEATURE_VFP_FP16); - set_feature(env, ARM_FEATURE_NEON); - set_feature(env, ARM_FEATURE_THUMB2EE); - set_feature(env, ARM_FEATURE_ARM_DIV); - set_feature(env, ARM_FEATURE_V7MP); - set_feature(env, ARM_FEATURE_GENERIC_TIMER); env->vfp.xregs[ARM_VFP_FPSID] =3D 0x410430f0; env->vfp.xregs[ARM_VFP_MVFR0] =3D 0x10110222; env->vfp.xregs[ARM_VFP_MVFR1] =3D 0x11111111; @@ -189,22 +146,11 @@ static void cpu_reset_model_id(CPUARMState *env, ui= nt32_t id) env->cp15.c1_sys =3D 0x00c50078; break; case ARM_CPUID_CORTEXM3: - set_feature(env, ARM_FEATURE_V7); - set_feature(env, ARM_FEATURE_M); break; case ARM_CPUID_ANY: /* For userspace emulation. */ - set_feature(env, ARM_FEATURE_V7); - set_feature(env, ARM_FEATURE_VFP4); - set_feature(env, ARM_FEATURE_VFP_FP16); - set_feature(env, ARM_FEATURE_NEON); - set_feature(env, ARM_FEATURE_THUMB2EE); - set_feature(env, ARM_FEATURE_ARM_DIV); - set_feature(env, ARM_FEATURE_V7MP); break; case ARM_CPUID_TI915T: case ARM_CPUID_TI925T: - set_feature(env, ARM_FEATURE_V4T); - set_feature(env, ARM_FEATURE_OMAPCP); env->cp15.c0_cpuid =3D ARM_CPUID_TI925T; /* Depends on wiring. = */ env->cp15.c0_cachetype =3D 0x5109149; env->cp15.c1_sys =3D 0x00000070; @@ -216,8 +162,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint= 32_t id) case ARM_CPUID_PXA260: case ARM_CPUID_PXA261: case ARM_CPUID_PXA262: - set_feature(env, ARM_FEATURE_V5); - set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ env->cp15.c0_cachetype =3D 0xd172172; env->cp15.c1_sys =3D 0x00000078; @@ -228,58 +172,19 @@ static void cpu_reset_model_id(CPUARMState *env, ui= nt32_t id) case ARM_CPUID_PXA270_B1: case ARM_CPUID_PXA270_C0: case ARM_CPUID_PXA270_C5: - set_feature(env, ARM_FEATURE_V5); - set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ - set_feature(env, ARM_FEATURE_IWMMXT); env->iwmmxt.cregs[ARM_IWMMXT_wCID] =3D 0x69051000 | 'Q'; env->cp15.c0_cachetype =3D 0xd172172; env->cp15.c1_sys =3D 0x00000078; break; case ARM_CPUID_SA1100: case ARM_CPUID_SA1110: - set_feature(env, ARM_FEATURE_STRONGARM); env->cp15.c1_sys =3D 0x00000070; break; default: cpu_abort(env, "Bad CPU ID: %x\n", id); break; } - - /* Some features automatically imply others: */ - if (arm_feature(env, ARM_FEATURE_V7)) { - set_feature(env, ARM_FEATURE_VAPA); - set_feature(env, ARM_FEATURE_THUMB2); - if (!arm_feature(env, ARM_FEATURE_M)) { - set_feature(env, ARM_FEATURE_V6K); - } else { - set_feature(env, ARM_FEATURE_V6); - } - } - if (arm_feature(env, ARM_FEATURE_V6K)) { - set_feature(env, ARM_FEATURE_V6); - } - if (arm_feature(env, ARM_FEATURE_V6)) { - set_feature(env, ARM_FEATURE_V5); - if (!arm_feature(env, ARM_FEATURE_M)) { - set_feature(env, ARM_FEATURE_AUXCR); - } - } - if (arm_feature(env, ARM_FEATURE_V5)) { - set_feature(env, ARM_FEATURE_V4T); - } - if (arm_feature(env, ARM_FEATURE_M)) { - set_feature(env, ARM_FEATURE_THUMB_DIV); - } - if (arm_feature(env, ARM_FEATURE_ARM_DIV)) { - set_feature(env, ARM_FEATURE_THUMB_DIV); - } - if (arm_feature(env, ARM_FEATURE_VFP4)) { - set_feature(env, ARM_FEATURE_VFP3); - } - if (arm_feature(env, ARM_FEATURE_VFP3)) { - set_feature(env, ARM_FEATURE_VFP); - } } =20 void cpu_reset(CPUARMState *env) diff --git a/target-arm/machine.c b/target-arm/machine.c index f66b8df..c93fded 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -5,6 +5,7 @@ void cpu_save(QEMUFile *f, void *opaque) { int i; CPUARMState *env =3D (CPUARMState *)opaque; + ARMCPU *cpu =3D ARM_CPU(ENV_GET_OBJECT(env)); =20 for (i =3D 0; i < 16; i++) { qemu_put_be32(f, env->regs[i]); @@ -61,7 +62,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->cp15.c15_diagnostic); qemu_put_be32(f, env->cp15.c15_power_diagnostic); =20 - qemu_put_be32(f, env->features); + qemu_put_be32(f, cpu->features); =20 if (arm_feature(env, ARM_FEATURE_VFP)) { for (i =3D 0; i < 16; i++) { @@ -115,6 +116,7 @@ void cpu_save(QEMUFile *f, void *opaque) int cpu_load(QEMUFile *f, void *opaque, int version_id) { CPUARMState *env =3D (CPUARMState *)opaque; + ARMCPU *cpu =3D ARM_CPU(ENV_GET_OBJECT(env)); int i; uint32_t val; =20 @@ -179,7 +181,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_i= d) env->cp15.c15_diagnostic =3D qemu_get_be32(f); env->cp15.c15_power_diagnostic =3D qemu_get_be32(f); =20 - env->features =3D qemu_get_be32(f); + cpu->features =3D qemu_get_be32(f); =20 if (arm_feature(env, ARM_FEATURE_VFP)) { for (i =3D 0; i < 16; i++) { --=20 1.7.7