]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
x86: Merge simd_math_error() into math_error()
authorBrian Gerst <brgerst@gmail.com>
Sun, 21 Mar 2010 13:00:44 +0000 (09:00 -0400)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 3 May 2010 20:39:29 +0000 (13:39 -0700)
The only difference between FPU and SIMD exceptions is where the
status bits are read from (cwd/swd vs. mxcsr).  This also fixes
the discrepency introduced by commit adf77bac, which fixed FPU
but not SIMD.

Signed-off-by: Brian Gerst <brgerst@gmail.com>
LKML-Reference: <1269176446-2489-3-git-send-email-brgerst@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/traps.h
arch/x86/kernel/irqinit.c
arch/x86/kernel/traps.c

index 4da91ad69e0d6abbd717a1fafcd0bfe3221ede54..f66cda56781dddd9dc29dffd56944c596976a0ad 100644 (file)
@@ -79,7 +79,7 @@ static inline int get_si_code(unsigned long condition)
 
 extern int panic_on_unrecovered_nmi;
 
-void math_error(void __user *);
+void math_error(struct pt_regs *, int, int);
 void math_emulate(struct math_emu_info *);
 #ifndef CONFIG_X86_32
 asmlinkage void smp_thermal_interrupt(void);
index 0ed2d300cd4601dbbf23e15e32eae363d5058a5a..990ae7cfc5783f131df476506bc9341574a466c2 100644 (file)
@@ -60,7 +60,7 @@ static irqreturn_t math_error_irq(int cpl, void *dev_id)
        outb(0, 0xF0);
        if (ignore_fpu_irq || !boot_cpu_data.hard_math)
                return IRQ_NONE;
-       math_error((void __user *)get_irq_regs()->ip);
+       math_error(get_irq_regs(), 0, 16);
        return IRQ_HANDLED;
 }
 
index a16c9dfe6b70ffd117090bb8a37b2dcfe8e9cd90..a472992cecdcc35b94f9781436aa2c42acb04a42 100644 (file)
@@ -595,36 +595,48 @@ static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
  * the correct behaviour even in the presence of the asynchronous
  * IRQ13 behaviour
  */
-void math_error(void __user *ip)
+void math_error(struct pt_regs *regs, int error_code, int trapnr)
 {
        struct task_struct *task;
        siginfo_t info;
-       unsigned short cwd, swd, err;
+       unsigned short err;
 
        /*
         * Save the info for the exception handler and clear the error.
         */
        task = current;
        save_init_fpu(task);
-       task->thread.trap_no = 16;
-       task->thread.error_code = 0;
+       task->thread.trap_no = trapnr;
+       task->thread.error_code = error_code;
        info.si_signo = SIGFPE;
        info.si_errno = 0;
-       info.si_addr = ip;
-       /*
-        * (~cwd & swd) will mask out exceptions that are not set to unmasked
-        * status.  0x3f is the exception bits in these regs, 0x200 is the
-        * C1 reg you need in case of a stack fault, 0x040 is the stack
-        * fault bit.  We should only be taking one exception at a time,
-        * so if this combination doesn't produce any single exception,
-        * then we have a bad program that isn't synchronizing its FPU usage
-        * and it will suffer the consequences since we won't be able to
-        * fully reproduce the context of the exception
-        */
-       cwd = get_fpu_cwd(task);
-       swd = get_fpu_swd(task);
+       info.si_addr = (void __user *)regs->ip;
+       if (trapnr == 16) {
+               unsigned short cwd, swd;
+               /*
+                * (~cwd & swd) will mask out exceptions that are not set to unmasked
+                * status.  0x3f is the exception bits in these regs, 0x200 is the
+                * C1 reg you need in case of a stack fault, 0x040 is the stack
+                * fault bit.  We should only be taking one exception at a time,
+                * so if this combination doesn't produce any single exception,
+                * then we have a bad program that isn't synchronizing its FPU usage
+                * and it will suffer the consequences since we won't be able to
+                * fully reproduce the context of the exception
+                */
+               cwd = get_fpu_cwd(task);
+               swd = get_fpu_swd(task);
 
-       err = swd & ~cwd;
+               err = swd & ~cwd;
+       } else {
+               /*
+                * The SIMD FPU exceptions are handled a little differently, as there
+                * is only a single status/control register.  Thus, to determine which
+                * unmasked exception was caught we must mask the exception mask bits
+                * at 0x1f80, and then use these to mask the exception bits at 0x3f.
+                */
+               unsigned short mxcsr = get_fpu_mxcsr(task);
+               err = ~(mxcsr >> 7) & mxcsr;
+       }
 
        if (err & 0x001) {      /* Invalid op */
                /*
@@ -663,55 +675,7 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
                return;
 #endif
 
-       math_error((void __user *)regs->ip);
-}
-
-static void simd_math_error(void __user *ip)
-{
-       struct task_struct *task;
-       siginfo_t info;
-       unsigned short mxcsr;
-
-       /*
-        * Save the info for the exception handler and clear the error.
-        */
-       task = current;
-       save_init_fpu(task);
-       task->thread.trap_no = 19;
-       task->thread.error_code = 0;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = __SI_FAULT;
-       info.si_addr = ip;
-       /*
-        * The SIMD FPU exceptions are handled a little differently, as there
-        * is only a single status/control register.  Thus, to determine which
-        * unmasked exception was caught we must mask the exception mask bits
-        * at 0x1f80, and then use these to mask the exception bits at 0x3f.
-        */
-       mxcsr = get_fpu_mxcsr(task);
-       switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
-       case 0x000:
-       default:
-               break;
-       case 0x001: /* Invalid Op */
-               info.si_code = FPE_FLTINV;
-               break;
-       case 0x002: /* Denormalize */
-       case 0x010: /* Underflow */
-               info.si_code = FPE_FLTUND;
-               break;
-       case 0x004: /* Zero Divide */
-               info.si_code = FPE_FLTDIV;
-               break;
-       case 0x008: /* Overflow */
-               info.si_code = FPE_FLTOVF;
-               break;
-       case 0x020: /* Precision */
-               info.si_code = FPE_FLTRES;
-               break;
-       }
-       force_sig_info(SIGFPE, &info, task);
+       math_error(regs, error_code, 16);
 }
 
 dotraplinkage void
@@ -727,7 +691,7 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
                return;
 #endif
 
-       simd_math_error((void __user *)regs->ip);
+       math_error(regs, error_code, 19);
 }
 
 dotraplinkage void