diff -ru linux-2.4.26/arch/i386/kernel/i387.c linux-2.4.26.new/arch/i386/kernel/i387.c
--- linux-2.4.26/arch/i386/kernel/i387.c	2003-08-25 19:44:39.000000000 +0800
+++ linux-2.4.26.new/arch/i386/kernel/i387.c	2004-06-14 23:36:36.000000000 +0800
@@ -73,8 +73,9 @@
 		asm volatile( "fxsave %0 ; fnclex"
 			      : "=m" (tsk->thread.i387.fxsave) );
 	} else {
-		asm volatile( "fnsave %0 ; fwait"
+		asm volatile( "fnsave %0"
 			      : "=m" (tsk->thread.i387.fsave) );
+		tolerant_fwait();
 	}
 	tsk->flags &= ~PF_USEDFPU;
 }
diff -ru linux-2.4.26/arch/i386/kernel/i8259.c linux-2.4.26.new/arch/i386/kernel/i8259.c
--- linux-2.4.26/arch/i386/kernel/i8259.c	2001-09-18 14:03:09.000000000 +0800
+++ linux-2.4.26.new/arch/i386/kernel/i8259.c	2004-06-14 23:37:28.000000000 +0800
@@ -390,11 +390,11 @@
  
 static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
 {
-	extern void math_error(void *);
+	extern void math_error(struct pt_regs *);
 	outb(0,0xF0);
 	if (ignore_irq13 || !boot_cpu_data.hard_math)
 		return;
-	math_error((void *)regs->eip);
+	math_error(regs);
 }
 
 /*
diff -ru linux-2.4.26/arch/i386/kernel/traps.c linux-2.4.26.new/arch/i386/kernel/traps.c
--- linux-2.4.26/arch/i386/kernel/traps.c	2002-11-29 07:53:09.000000000 +0800
+++ linux-2.4.26.new/arch/i386/kernel/traps.c	2004-06-15 00:09:42.000000000 +0800
@@ -602,12 +602,22 @@
  * the correct behaviour even in the presence of the asynchronous
  * IRQ13 behaviour
  */
-void math_error(void *eip)
+void math_error(struct pt_regs *regs)
 {
+	void *eip = (void *)regs->eip;
 	struct task_struct * task;
 	siginfo_t info;
 	unsigned short cwd, swd;
 
+	if ((regs->xcs & 3) == 0) {
+		unsigned long fixup = search_exception_table(regs->eip);
+		if (fixup) {
+			regs->eip = fixup;
+			return;
+		}
+		die("kernel math error", regs, 0);
+	}
+
 	/*
 	 * Save the info for the exception handler and clear the error.
 	 */
@@ -661,15 +671,25 @@
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
 	ignore_irq13 = 1;
-	math_error((void *)regs->eip);
+	math_error(regs);
 }
 
-void simd_math_error(void *eip)
+void simd_math_error(struct pt_regs *regs)
 {
+	void *eip = (void *)regs->eip;
 	struct task_struct * task;
 	siginfo_t info;
 	unsigned short mxcsr;
 
+	if ((regs->xcs & 3) == 0) {
+		unsigned long fixup = search_exception_table(regs->eip);
+		if (fixup) {
+			regs->eip = fixup;
+			return;
+		}
+		die("kernel math error", regs, 0);
+	}
+
 	/*
 	 * Save the info for the exception handler and clear the error.
 	 */
@@ -718,7 +738,7 @@
 	if (cpu_has_xmm) {
 		/* Handle SIMD FPU exceptions on PIII+ processors. */
 		ignore_irq13 = 1;
-		simd_math_error((void *)regs->eip);
+		simd_math_error(regs);
 	} else {
 		/*
 		 * Handle strange cache flush from user space exception
diff -ru linux-2.4.26/include/asm-i386/i387.h linux-2.4.26.new/include/asm-i386/i387.h
--- linux-2.4.26/include/asm-i386/i387.h	2002-08-03 08:39:45.000000000 +0800
+++ linux-2.4.26.new/include/asm-i386/i387.h	2004-06-15 00:14:10.000000000 +0800
@@ -26,6 +26,16 @@
 extern void kernel_fpu_begin(void);
 #define kernel_fpu_end() stts()
 
+/* Ignore delayed exceptions from user space */
+static inline void tolerant_fwait(void)
+{
+	asm volatile("1: fwait\n"
+			"2:\n"
+			"	.section __ex_table,\"a\"\n"
+			"	.align 4\n"
+			"	.long 1b,2b\n"
+			"	.previous\n");
+}
 
 #define unlazy_fpu( tsk ) do { \
 	if ( tsk->flags & PF_USEDFPU ) \
@@ -34,7 +44,7 @@
 
 #define clear_fpu( tsk ) do { \
 	if ( tsk->flags & PF_USEDFPU ) { \
-		asm volatile("fwait"); \
+		tolerant_fwait(); \
 		tsk->flags &= ~PF_USEDFPU; \
 		stts(); \
 	} \

