Restore FPU round state after loading the VM state. This patch fixes different behavior after loading VM state with different FPU flags set.
Signed-off-by: Pavel Dovgalyuk<pavel.dovga...@gmail.com> --- target-i386/cpu.c | 1 + target-i386/cpu.h | 2 ++ target-i386/machine.c | 2 +- target-i386/op_helper.c | 16 ++++++++++------ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index fdd95be..68d10ba 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1675,6 +1675,7 @@ static void x86_cpu_reset(CPUState *s) env->fptags[i] = 1; } env->fpuc = 0x37f; + update_fp_status(env); env->mxcsr = 0x1f80; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index bcf663e..6500cc8 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1086,4 +1086,6 @@ uint32_t cpu_cc_compute_all(CPUX86State *env1, int op); void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); +void update_fp_status(CPUState *env1); + #endif /* CPU_I386_H */ diff --git a/target-i386/machine.c b/target-i386/machine.c index a8be058..e79d98d 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -255,7 +255,7 @@ static int cpu_post_load(void *opaque, int version_id) CPUX86State *env = opaque; int i; - /* XXX: restore FPU round state */ + update_fp_status(env); env->fpstt = (env->fpus_vmstate >> 11) & 7; env->fpus = env->fpus_vmstate & ~0x3800; env->fptag_vmstate ^= 0xff; diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index bc3b94e..552f089 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4018,12 +4018,12 @@ uint32_t helper_fnstcw(void) return env->fpuc; } -static void update_fp_status(void) +void update_fp_status(CPUState *env1) { int rnd_type; /* set rounding mode */ - switch(env->fpuc & FPU_RC_MASK) { + switch (env1->fpuc & FPU_RC_MASK) { default: case FPU_RC_NEAR: rnd_type = float_round_nearest_even; @@ -4038,8 +4038,8 @@ static void update_fp_status(void) rnd_type = float_round_to_zero; break; } - set_float_rounding_mode(rnd_type, &env->fp_status); - switch((env->fpuc >> 8) & 3) { + set_float_rounding_mode(rnd_type, &env1->fp_status); + switch ((env1->fpuc >> 8) & 3) { case 0: rnd_type = 32; break; @@ -4051,13 +4051,13 @@ static void update_fp_status(void) rnd_type = 80; break; } - set_floatx80_rounding_precision(rnd_type, &env->fp_status); + set_floatx80_rounding_precision(rnd_type, &env1->fp_status); } void helper_fldcw(uint32_t val) { env->fpuc = val; - update_fp_status(); + update_fp_status(env); } void helper_fclex(void) @@ -4076,6 +4076,7 @@ void helper_fninit(void) env->fpus = 0; env->fpstt = 0; env->fpuc = 0x37f; + update_fp_status(env); env->fptags[0] = 1; env->fptags[1] = 1; env->fptags[2] = 1; @@ -4494,6 +4495,7 @@ void helper_fldenv(target_ulong ptr, int data32) fpus = lduw(ptr + 2); fptag = lduw(ptr + 4); } + update_fp_status(env); env->fpstt = (fpus >> 11) & 7; env->fpus = fpus & ~0x3800; for(i = 0;i < 8; i++) { @@ -4520,6 +4522,7 @@ void helper_fsave(target_ulong ptr, int data32) env->fpus = 0; env->fpstt = 0; env->fpuc = 0x37f; + update_fp_status(env); env->fptags[0] = 1; env->fptags[1] = 1; env->fptags[2] = 1; @@ -4661,6 +4664,7 @@ void helper_fxrstor(target_ulong ptr, int data64) } env->fpuc = lduw(ptr); + update_fp_status(env); fpus = lduw(ptr + 2); fptag = lduw(ptr + 4); env->fpstt = (fpus >> 11) & 7;