diff --git a/src/code/float-trap.lisp b/src/code/float-trap.lisp
index 7f27ffdc6be517cef816163128415eef4553da8b..d97d04e82326ce6375d113dba879c32113f8d3c2 100644
--- a/src/code/float-trap.lisp
+++ b/src/code/float-trap.lisp
@@ -64,17 +64,62 @@
 (defun (setf floating-point-modes) (new) (setf (floating-point-modes) new))
 )
 
+#+(and x86 (not sse2))
+(progn
+  (defun floating-point-modes ()
+    (let ((x87-modes (vm::x87-floating-point-modes)))
+      ;; Massage the bits from x87-floating-point-modes into the order
+      ;; that the rest of the system wants them to be.  (Must match
+      ;; format in the SSE2 mxcsr register.)
+      (logior (ash (logand #x3f x87-modes) 7) ; control
+	      (logand #x3f (ash x87-modes -16)))))
+  (defun (setf floating-point-modes) (new)
+    (let* ((rc (ldb float-rounding-mode new))
+	   (x87-modes
+	    (logior (ash (logand #x3f new) 16)
+		    (ash rc 10)
+		    (logand #x3f (ash new -7))
+		    ;; Set precision control to be 53-bit, always.
+		    ;; (The compiler takes care of handling
+		    ;; single-float precision, and we don't support
+		    ;; long-floats.)
+		    (ash 2 8))))
+    (setf (x87-floating-point-modes) x87-modes)))
+  )
+
 #+sse2
 (progn
   (defun floating-point-modes ()
-    ;; Get just the SSE2 mode bits.
-    (vm::sse2-floating-point-modes))
+    ;; Combine the modes from the FPU and SSE2 units.  Since the sse
+    ;; mode contains all of the common information we want, we massage
+    ;; the x87-modes to match, and then OR the x87 and sse2 modes
+    ;; together.  Note: We ignore the rounding control bits from the
+    ;; FPU and only use the SSE2 rounding control bits.
+    (let* ((x87-modes (vm::x87-floating-point-modes))
+	   (sse-modes (vm::sse2-floating-point-modes))
+	   (final-mode (logior sse-modes
+			       (ash (logand #x3f x87-modes) 7) ; control
+			       (logand #x3f (ash x87-modes -16)))))
+
+      final-mode))
   (defun (setf floating-point-modes) (new-mode)
     (declare (type (unsigned-byte 24) new-mode))
-    ;; Set the floating point modes for SSE2.
-    (setf (vm::sse2-floating-point-modes) new-mode)
+    ;; Set the floating point modes for both X87 and SSE2.  This
+    ;; include the rounding control bits.
+    (let* ((rc (ldb float-rounding-mode new-mode))
+	   (x87-modes
+	    (logior (ash (logand #x3f new-mode) 16)
+		    (ash rc 10)
+		    (logand #x3f (ash new-mode -7))
+		    ;; Set precision control to be 64-bit, always.  We
+		    ;; don't use the x87 registers with sse2, so this
+		    ;; is ok and would be the correct setting if we
+		    ;; ever support long-floats.
+		    (ash 3 8))))
+      (setf (vm::sse2-floating-point-modes) new-mode)
+      (setf (vm::x87-floating-point-modes) x87-modes))
     new-mode)
-  )
+)
 
 ;;; SET-FLOATING-POINT-MODES  --  Public
 ;;;
diff --git a/src/compiler/x86/float.lisp b/src/compiler/x86/float.lisp
index a515e402801d9fe347d6bf861975c3dbb05705e4..e61714948aea0f439dc4ca274344dfeb67dce8fe 100644
--- a/src/compiler/x86/float.lisp
+++ b/src/compiler/x86/float.lisp
@@ -2303,6 +2303,43 @@
 (defknown ((setf x87-floating-point-modes)) (float-modes)
   float-modes)
 
+;; For the record, here is the format of the x86 FPU status word
+;;
+;; Bit
+;; 15       FPU Busy
+;; 14       C3 (condition code)
+;; 13-11    Top of stack
+;; 10       C2 (condition code)
+;;  9       C1 (condition code)
+;;  8       C0 (condition code)
+;;  7       Error summary status
+;;  6       Stack fault
+;;  5       precision flag (inexact)
+;;  4       underflow flag
+;;  3       overflow flag
+;;  2       divide-by-zero flag
+;;  1       denormalized operand flag
+;;  0       invalid operation flag
+;;
+;; When one of the flag bits (0-5) is set, then that exception has
+;; been detected since the bits were last cleared.
+;;
+;; The control word:
+;;
+;; 15-13    reserved
+;; 12       infinity control
+;; 11-10    rounding control
+;; 9-8      precision control
+;; 7-6      reserved
+;;  5       precision masked
+;;  4       underflow masked
+;;  3       overflow masked
+;;  2       divide-by-zero masked
+;;  1       denormal operand masked
+;;  0       invalid operation masked
+;;
+;; When one of the mask bits (0-5) is set, then that exception is
+;; masked so that no exception is generated.
 (define-vop (x87-floating-point-modes)
   (:results (res :scs (unsigned-reg)))
   (:result-types unsigned-num)
diff --git a/src/lisp/Linux-os.c b/src/lisp/Linux-os.c
index 2da60fb59791eb574879c8eb2bca02a00ee2077e..7f7a4d7acd350c1ef5b443ef5a28cf848c2e368f 100644
--- a/src/lisp/Linux-os.c
+++ b/src/lisp/Linux-os.c
@@ -217,13 +217,16 @@ os_sigcontext_fpu_reg(ucontext_t *scp, int offset)
     if (fpregs) {
         if (offset < 8) {
             reg = (unsigned char *) &fpregs->_st[offset];
-        } else if (offset < 16) {
+        }
+#ifdef FEATURE_SSE2
+        else {
             struct _fpstate *fpstate;
             fpstate = (struct _fpstate*) scp->uc_mcontext.fpregs;
             if (fpstate->magic != 0xffff) {
                 reg = (unsigned char *) &fpstate->_xmm[offset - 8];
             }
         }
+#endif
     }
     return reg;
 }
@@ -231,27 +234,39 @@ os_sigcontext_fpu_reg(ucontext_t *scp, int offset)
 unsigned int
 os_sigcontext_fpu_modes(ucontext_t *scp)
 {
-    unsigned int modes = 0;
-
-    /*
-     * Get the SSE2 modes.  FIXME: What should we do if the magic
-     * value indicates that the mxcsr value is not in the context?
-     */
-    struct _fpstate *fpstate;
-    unsigned long mxcsr;
+    unsigned int modes;
+    unsigned short cw, sw;
 
-    fpstate = (struct _fpstate*) scp->uc_mcontext.fpregs;
-    if (fpstate->magic == 0xffff) {
-        mxcsr = 0;
+    if (scp->uc_mcontext.fpregs == NULL) {
+	cw = 0;
+	sw = 0x3f;
     } else {
-        mxcsr = fpstate->mxcsr;
-        DPRINTF(0, (stderr, "SSE2 modes = %08lx\n", mxcsr));
+	cw = scp->uc_mcontext.fpregs->cw & 0xffff;
+	sw = scp->uc_mcontext.fpregs->sw & 0xffff;
     }
 
-    modes |= mxcsr;
+    modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
+
+#ifdef FEATURE_SSE2
+    /*
+     * Add in the SSE2 part, if we're running the sse2 core.
+     */
+    if (fpu_mode == SSE2) {
+        struct _fpstate *fpstate;
+	unsigned long mxcsr;
+
+        fpstate = (struct _fpstate*) scp->uc_mcontext.fpregs;
+        if (fpstate->magic == 0xffff) {
+            mxcsr = 0;
+        } else {
+            mxcsr = fpstate->mxcsr;
+            DPRINTF(0, (stderr, "SSE2 modes = %08lx\n", mxcsr));
+        }
 
+	modes |= mxcsr;
+    }
+#endif
 
-    /* Convert exception mask to exception enable */
     modes ^= (0x3f << 7);
     return modes;
 }
@@ -528,19 +543,25 @@ void
 restore_fpu(ucontext_t *context)
 {
     if (context->uc_mcontext.fpregs) {
-        struct _fpstate *fpstate;
-        unsigned int mxcsr;
+	short cw = context->uc_mcontext.fpregs->cw;
+        DPRINTF(0, (stderr, "restore_fpu:  cw = %08x\n", cw));
+	__asm__ __volatile__ ("fldcw %0" : : "m" (*&cw));
+#ifdef FEATURE_SSE2
+        if (fpu_mode == SSE2) {
+            struct _fpstate *fpstate;
+            unsigned int mxcsr;
             
-        fpstate = (struct _fpstate*) context->uc_mcontext.fpregs;
-        if (fpstate->magic != 0xffff) {
-            mxcsr = fpstate->mxcsr;
-            DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
-            __asm__ __volatile__ ("ldmxcsr %0" :: "m" (*&mxcsr));
+            fpstate = (struct _fpstate*) context->uc_mcontext.fpregs;
+            if (fpstate->magic != 0xffff) {
+                mxcsr = fpstate->mxcsr;
+                DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
+                __asm__ __volatile__ ("ldmxcsr %0" :: "m" (*&mxcsr));
+            }
         }
+#endif        
     }
 }
 
-
 #ifdef i386
 boolean
 os_support_sse2()