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

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);
+1 −1
Original line number Original line Diff line number Diff line
@@ -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;
}
}


+32 −68
Original line number Original line Diff line number Diff line
@@ -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)
		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)
		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)
		return;
		return;
#endif
#endif


	simd_math_error((void __user *)regs->ip);
	math_error(regs, error_code, 19);
}
}


dotraplinkage void
dotraplinkage void