aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-12-22 20:56:05 -0500
committerH. Peter Anvin <hpa@zytor.com>2008-12-22 21:00:18 -0500
commitadf77bac052bb5bf0722b2ce2af9fefc5b2d2a71 (patch)
treeaceffee150411ffe1e93b4f78f4660028d44ecd8 /arch/x86/kernel/traps.c
parent55dac3a5553b13891f0ae4bbd11920619b5436d4 (diff)
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: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c34
1 files changed, 15 insertions, 19 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 04d242ab0161..c320c29255c2 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -664,7 +664,7 @@ void math_error(void __user *ip)
664{ 664{
665 struct task_struct *task; 665 struct task_struct *task;
666 siginfo_t info; 666 siginfo_t info;
667 unsigned short cwd, swd; 667 unsigned short cwd, swd, err;
668 668
669 /* 669 /*
670 * Save the info for the exception handler and clear the error. 670 * Save the info for the exception handler and clear the error.
@@ -675,7 +675,6 @@ void math_error(void __user *ip)
675 task->thread.error_code = 0; 675 task->thread.error_code = 0;
676 info.si_signo = SIGFPE; 676 info.si_signo = SIGFPE;
677 info.si_errno = 0; 677 info.si_errno = 0;
678 info.si_code = __SI_FAULT;
679 info.si_addr = ip; 678 info.si_addr = ip;
680 /* 679 /*
681 * (~cwd & swd) will mask out exceptions that are not set to unmasked 680 * (~cwd & swd) will mask out exceptions that are not set to unmasked
@@ -689,34 +688,31 @@ void math_error(void __user *ip)
689 */ 688 */
690 cwd = get_fpu_cwd(task); 689 cwd = get_fpu_cwd(task);
691 swd = get_fpu_swd(task); 690 swd = get_fpu_swd(task);
692 switch (swd & ~cwd & 0x3f) { 691
693 case 0x000: /* No unmasked exception */ 692 err = swd & ~cwd & 0x3f;
694#ifdef CONFIG_X86_32 693
694#if CONFIG_X86_32
695 if (!err)
695 return; 696 return;
696#endif 697#endif
697 default: /* Multiple exceptions */ 698
698 break; 699 if (err & 0x001) { /* Invalid op */
699 case 0x001: /* Invalid Op */
700 /* 700 /*
701 * swd & 0x240 == 0x040: Stack Underflow 701 * swd & 0x240 == 0x040: Stack Underflow
702 * swd & 0x240 == 0x240: Stack Overflow 702 * swd & 0x240 == 0x240: Stack Overflow
703 * User must clear the SF bit (0x40) if set 703 * User must clear the SF bit (0x40) if set
704 */ 704 */
705 info.si_code = FPE_FLTINV; 705 info.si_code = FPE_FLTINV;
706 break; 706 } else if (err & 0x004) { /* Divide by Zero */
707 case 0x002: /* Denormalize */
708 case 0x010: /* Underflow */
709 info.si_code = FPE_FLTUND;
710 break;
711 case 0x004: /* Zero Divide */
712 info.si_code = FPE_FLTDIV; 707 info.si_code = FPE_FLTDIV;
713 break; 708 } else if (err & 0x008) { /* Overflow */
714 case 0x008: /* Overflow */
715 info.si_code = FPE_FLTOVF; 709 info.si_code = FPE_FLTOVF;
716 break; 710 } else if (err & 0x012) { /* Denormal, Underflow */
717 case 0x020: /* Precision */ 711 info.si_code = FPE_FLTUND;
712 } else if (err & 0x020) { /* Precision */
718 info.si_code = FPE_FLTRES; 713 info.si_code = FPE_FLTRES;
719 break; 714 } else {
715 info.si_code = __SI_FAULT|SI_KERNEL; /* WTF? */
720 } 716 }
721 force_sig_info(SIGFPE, &info, task); 717 force_sig_info(SIGFPE, &info, task);
722} 718}