Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+15 −19
Original line number Original line Diff line number Diff line
@@ -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)
	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)
	 */
	 */
	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);
}
}