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;



Reply via email to