Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: x86, fpu: Use static_cpu_has() to implement use_xsave() x86: Add new static_cpu_has() function using alternatives x86, fpu: Use the proper asm constraint in use_xsave() x86, fpu: Unbreak FPU emulation x86: Introduce 'struct fpu' and related API x86: Eliminate TS_XSAVE x86-32: Don't set ignore_fpu_irq in simd exception x86: Merge kernel_math_error() into math_error() x86: Merge simd_math_error() into math_error() x86-32: Rework cache flush denied handler Fix trivial conflict in arch/x86/kernel/process.c
This commit is contained in:
@@ -108,15 +108,6 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
|
||||
dec_preempt_count();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
static inline void
|
||||
die_if_kernel(const char *str, struct pt_regs *regs, long err)
|
||||
{
|
||||
if (!user_mode_vm(regs))
|
||||
die(str, regs, err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __kprobes
|
||||
do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
|
||||
long error_code, siginfo_t *info)
|
||||
@@ -585,55 +576,67 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
|
||||
{
|
||||
if (fixup_exception(regs))
|
||||
return 1;
|
||||
|
||||
notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
|
||||
/* Illegal floating point operation in the kernel */
|
||||
current->thread.trap_no = trapnr;
|
||||
die(str, regs, 0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note that we play around with the 'TS' bit in an attempt to get
|
||||
* the correct behaviour even in the presence of the asynchronous
|
||||
* 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 = current;
|
||||
siginfo_t info;
|
||||
unsigned short cwd, swd, err;
|
||||
unsigned short err;
|
||||
char *str = (trapnr == 16) ? "fpu exception" : "simd exception";
|
||||
|
||||
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, SIGFPE) == NOTIFY_STOP)
|
||||
return;
|
||||
conditional_sti(regs);
|
||||
|
||||
if (!user_mode_vm(regs))
|
||||
{
|
||||
if (!fixup_exception(regs)) {
|
||||
task->thread.error_code = error_code;
|
||||
task->thread.trap_no = trapnr;
|
||||
die(str, regs, error_code);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the info for the exception handler and clear the error.
|
||||
*/
|
||||
task = current;
|
||||
save_init_fpu(task);
|
||||
task->thread.trap_no = 16;
|
||||
task->thread.error_code = 0;
|
||||
task->thread.trap_no = trapnr;
|
||||
task->thread.error_code = error_code;
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = ip;
|
||||
/*
|
||||
* (~cwd & swd) will mask out exceptions that are not set to unmasked
|
||||
* status. 0x3f is the exception bits in these regs, 0x200 is the
|
||||
* C1 reg you need in case of a stack fault, 0x040 is the stack
|
||||
* fault bit. We should only be taking one exception at a time,
|
||||
* so if this combination doesn't produce any single exception,
|
||||
* then we have a bad program that isn't synchronizing its FPU usage
|
||||
* and it will suffer the consequences since we won't be able to
|
||||
* fully reproduce the context of the exception
|
||||
*/
|
||||
cwd = get_fpu_cwd(task);
|
||||
swd = get_fpu_swd(task);
|
||||
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
|
||||
* status. 0x3f is the exception bits in these regs, 0x200 is the
|
||||
* C1 reg you need in case of a stack fault, 0x040 is the stack
|
||||
* fault bit. We should only be taking one exception at a time,
|
||||
* so if this combination doesn't produce any single exception,
|
||||
* then we have a bad program that isn't synchronizing its FPU usage
|
||||
* and it will suffer the consequences since we won't be able to
|
||||
* fully reproduce the context of the exception
|
||||
*/
|
||||
cwd = get_fpu_cwd(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 */
|
||||
/*
|
||||
@@ -662,97 +665,17 @@ void math_error(void __user *ip)
|
||||
|
||||
dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
|
||||
{
|
||||
conditional_sti(regs);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
ignore_fpu_irq = 1;
|
||||
#else
|
||||
if (!user_mode(regs) &&
|
||||
kernel_math_error(regs, "kernel x87 math error", 16))
|
||||
return;
|
||||
#endif
|
||||
|
||||
math_error((void __user *)regs->ip);
|
||||
}
|
||||
|
||||
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);
|
||||
math_error(regs, error_code, 16);
|
||||
}
|
||||
|
||||
dotraplinkage void
|
||||
do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
|
||||
{
|
||||
conditional_sti(regs);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
if (cpu_has_xmm) {
|
||||
/* Handle SIMD FPU exceptions on PIII+ processors. */
|
||||
ignore_fpu_irq = 1;
|
||||
simd_math_error((void __user *)regs->ip);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Handle strange cache flush from user space exception
|
||||
* in all other cases. This is undocumented behaviour.
|
||||
*/
|
||||
if (regs->flags & X86_VM_MASK) {
|
||||
handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code);
|
||||
return;
|
||||
}
|
||||
current->thread.trap_no = 19;
|
||||
current->thread.error_code = error_code;
|
||||
die_if_kernel("cache flush denied", regs, error_code);
|
||||
force_sig(SIGSEGV, current);
|
||||
#else
|
||||
if (!user_mode(regs) &&
|
||||
kernel_math_error(regs, "kernel simd math error", 19))
|
||||
return;
|
||||
simd_math_error((void __user *)regs->ip);
|
||||
#endif
|
||||
math_error(regs, error_code, 19);
|
||||
}
|
||||
|
||||
dotraplinkage void
|
||||
|
Reference in New Issue
Block a user