Commit adf77bac authored by H. Peter Anvin's avatar H. Peter Anvin

x86: prioritize the FPU traps for the error code

In the case of multiple FPU errors, prioritize the error codes,
instead of returning __SI_FAULT, which ends up pushing a 0 as the
error code to userspace, a POSIX violation.

For i386, we will simply return if there are no errors at all; for
x86-64 this is probably a "can't happen" (and the code should be
unified), but for this patch, return __SI_FAULT|SI_KERNEL if this ever
happens.
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent 55dac3a5
...@@ -664,7 +664,7 @@ void math_error(void __user *ip) ...@@ -664,7 +664,7 @@ void math_error(void __user *ip)
{ {
struct task_struct *task; struct task_struct *task;
siginfo_t info; siginfo_t info;
unsigned short cwd, swd; unsigned short cwd, swd, err;
/* /*
* Save the info for the exception handler and clear the error. * Save the info for the exception handler and clear the error.
...@@ -675,7 +675,6 @@ void math_error(void __user *ip) ...@@ -675,7 +675,6 @@ void math_error(void __user *ip)
task->thread.error_code = 0; task->thread.error_code = 0;
info.si_signo = SIGFPE; info.si_signo = SIGFPE;
info.si_errno = 0; info.si_errno = 0;
info.si_code = __SI_FAULT;
info.si_addr = ip; info.si_addr = ip;
/* /*
* (~cwd & swd) will mask out exceptions that are not set to unmasked * (~cwd & swd) will mask out exceptions that are not set to unmasked
...@@ -689,34 +688,31 @@ void math_error(void __user *ip) ...@@ -689,34 +688,31 @@ void math_error(void __user *ip)
*/ */
cwd = get_fpu_cwd(task); cwd = get_fpu_cwd(task);
swd = get_fpu_swd(task); swd = get_fpu_swd(task);
switch (swd & ~cwd & 0x3f) {
case 0x000: /* No unmasked exception */ err = swd & ~cwd & 0x3f;
#ifdef CONFIG_X86_32
#if CONFIG_X86_32
if (!err)
return; return;
#endif #endif
default: /* Multiple exceptions */
break; if (err & 0x001) { /* Invalid op */
case 0x001: /* Invalid Op */
/* /*
* swd & 0x240 == 0x040: Stack Underflow * swd & 0x240 == 0x040: Stack Underflow
* swd & 0x240 == 0x240: Stack Overflow * swd & 0x240 == 0x240: Stack Overflow
* User must clear the SF bit (0x40) if set * User must clear the SF bit (0x40) if set
*/ */
info.si_code = FPE_FLTINV; info.si_code = FPE_FLTINV;
break; } else if (err & 0x004) { /* Divide by Zero */
case 0x002: /* Denormalize */
case 0x010: /* Underflow */
info.si_code = FPE_FLTUND;
break;
case 0x004: /* Zero Divide */
info.si_code = FPE_FLTDIV; info.si_code = FPE_FLTDIV;
break; } else if (err & 0x008) { /* Overflow */
case 0x008: /* Overflow */
info.si_code = FPE_FLTOVF; info.si_code = FPE_FLTOVF;
break; } else if (err & 0x012) { /* Denormal, Underflow */
case 0x020: /* Precision */ info.si_code = FPE_FLTUND;
} else if (err & 0x020) { /* Precision */
info.si_code = FPE_FLTRES; info.si_code = FPE_FLTRES;
break; } else {
info.si_code = __SI_FAULT|SI_KERNEL; /* WTF? */
} }
force_sig_info(SIGFPE, &info, task); force_sig_info(SIGFPE, &info, task);
} }
......
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