Fixes x86 SW context FP restore
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 24 Apr 2013 01:49:35 +0000 (18:49 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 24 Apr 2013 22:19:10 +0000 (15:19 -0700)
The FPU stack could have registers in it, either due to old FP loads, or
due to MMX usage (which marks the entire stack as full).  The ABI
expects an empty stack.  Conveniently enough emms clears it, even though
8.1.7 doesn't mention it.

user/parlib/include/i686/vcore.h

index 1c8a7dd..ef4397e 100644 (file)
@@ -123,9 +123,17 @@ static inline void pop_sw_tf(struct sw_trapframe *sw_tf, uint32_t vcoreid)
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
 
        /* Restore callee-saved FPU state.  We need to clear exceptions before
-        * reloading the FP CW, in case the new CW unmasks any. */
+        * reloading the FP CW, in case the new CW unmasks any.  We also need to
+        * reset the tag word to clear out the stack.
+        *
+        * The main issue here is that while our context was saved in an
+        * ABI-complaint manner, we may be starting up on a somewhat random FPU
+        * state.  Having gibberish in registers isn't a big deal, but some of the
+        * FP environment settings could cause trouble.  If fnclex; emms isn't
+        * enough, we could also save/restore the entire FP env with fldenv, or do
+        * an fninit before fldcw. */
        asm volatile ("ldmxcsr %0" : : "m"(sw_tf->tf_mxcsr));
-       asm volatile ("fnclex; fldcw %0" : : "m"(sw_tf->tf_fpucw));
+       asm volatile ("fnclex; emms; fldcw %0" : : "m"(sw_tf->tf_fpucw));
        /* Basic plan: restore all regs, off ecx as the sw_tf.  Switch to the new
         * stack, push the PC so we can pop it later.  Use eax and edx for the
         * locations of sysc and vcpd.  Once on the new stack, we enable notifs,