Commit 9b6dba9e authored by Brian Gerst's avatar Brian Gerst Committed by H. Peter Anvin

x86: Merge simd_math_error() into math_error()

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: default avatarBrian Gerst <brgerst@gmail.com>
LKML-Reference: <1269176446-2489-3-git-send-email-brgerst@gmail.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent 40d2e763
...@@ -79,7 +79,7 @@ static inline int get_si_code(unsigned long condition) ...@@ -79,7 +79,7 @@ static inline int get_si_code(unsigned long condition)
extern int panic_on_unrecovered_nmi; 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 *); void math_emulate(struct math_emu_info *);
#ifndef CONFIG_X86_32 #ifndef CONFIG_X86_32
asmlinkage void smp_thermal_interrupt(void); asmlinkage void smp_thermal_interrupt(void);
......
...@@ -60,7 +60,7 @@ static irqreturn_t math_error_irq(int cpl, void *dev_id) ...@@ -60,7 +60,7 @@ static irqreturn_t math_error_irq(int cpl, void *dev_id)
outb(0, 0xF0); outb(0, 0xF0);
if (ignore_fpu_irq || !boot_cpu_data.hard_math) if (ignore_fpu_irq || !boot_cpu_data.hard_math)
return IRQ_NONE; return IRQ_NONE;
math_error((void __user *)get_irq_regs()->ip); math_error(get_irq_regs(), 0, 16);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -595,22 +595,24 @@ static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) ...@@ -595,22 +595,24 @@ static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
* the correct behaviour even in the presence of the asynchronous * the correct behaviour even in the presence of the asynchronous
* IRQ13 behaviour * IRQ13 behaviour
*/ */
void math_error(void __user *ip) void math_error(struct pt_regs *regs, int error_code, int trapnr)
{ {
struct task_struct *task; struct task_struct *task;
siginfo_t info; siginfo_t info;
unsigned short cwd, swd, err; unsigned short err;
/* /*
* Save the info for the exception handler and clear the error. * Save the info for the exception handler and clear the error.
*/ */
task = current; task = current;
save_init_fpu(task); save_init_fpu(task);
task->thread.trap_no = 16; task->thread.trap_no = trapnr;
task->thread.error_code = 0; task->thread.error_code = error_code;
info.si_signo = SIGFPE; info.si_signo = SIGFPE;
info.si_errno = 0; info.si_errno = 0;
info.si_addr = ip; 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 * (~cwd & swd) will mask out exceptions that are not set to unmasked
* status. 0x3f is the exception bits in these regs, 0x200 is the * status. 0x3f is the exception bits in these regs, 0x200 is the
...@@ -625,6 +627,16 @@ void math_error(void __user *ip) ...@@ -625,6 +627,16 @@ void math_error(void __user *ip)
swd = get_fpu_swd(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 */ if (err & 0x001) { /* Invalid op */
/* /*
...@@ -663,55 +675,7 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) ...@@ -663,55 +675,7 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
return; return;
#endif #endif
math_error((void __user *)regs->ip); math_error(regs, error_code, 16);
}
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);
} }
dotraplinkage void dotraplinkage void
...@@ -727,7 +691,7 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code) ...@@ -727,7 +691,7 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
return; return;
#endif #endif
simd_math_error((void __user *)regs->ip); math_error(regs, error_code, 19);
} }
dotraplinkage void dotraplinkage void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment