diff options
Diffstat (limited to 'target-arm/cpu.c')
-rw-r--r-- | target-arm/cpu.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 35253481f4..3c84f72928 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -79,6 +79,27 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) } } +static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) +{ + /* Purely an assertion check: we've already done reset once, + * so now check that running the reset for the cpreg doesn't + * change its value. This traps bugs where two different cpregs + * both try to reset the same state field but to different values. + */ + ARMCPRegInfo *ri = value; + ARMCPU *cpu = opaque; + uint64_t oldvalue, newvalue; + + if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) { + return; + } + + oldvalue = read_raw_cp_reg(&cpu->env, ri); + cp_reg_reset(key, value, opaque); + newvalue = read_raw_cp_reg(&cpu->env, ri); + assert(oldvalue == newvalue); +} + /* CPUClass::reset() */ static void arm_cpu_reset(CPUState *s) { @@ -90,6 +111,8 @@ static void arm_cpu_reset(CPUState *s) memset(env, 0, offsetof(CPUARMState, features)); g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu); + g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu); + env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1; |