]> Git Repo - linux.git/commitdiff
Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Tue, 18 May 2010 15:58:16 +0000 (08:58 -0700)
committerLinus Torvalds <[email protected]>
Tue, 18 May 2010 15:58:16 +0000 (08:58 -0700)
* '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

1  2 
arch/x86/Kconfig.cpu
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/thread_info.h
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/traps.c

diff --combined arch/x86/Kconfig.cpu
index 918fbb1855cc027bb2fb7b6a77daeb2a21fda9cd,6f6792c56015301067f0f706d9459aa8c1c9ffbb..2ac9069890cdf594610e19424c54626bb1f051aa
@@@ -338,6 -338,10 +338,10 @@@ config X86_F00F_BU
        def_bool y
        depends on M586MMX || M586TSC || M586 || M486 || M386
  
+ config X86_INVD_BUG
+       def_bool y
+       depends on M486 || M386
  config X86_WP_WORKS_OK
        def_bool y
        depends on !M386
@@@ -502,3 -506,23 +506,3 @@@ config CPU_SUP_UMC_3
          CPU might render the kernel unbootable.
  
          If unsure, say N.
 -
 -config X86_DS
 -      def_bool X86_PTRACE_BTS
 -      depends on X86_DEBUGCTLMSR
 -      select HAVE_HW_BRANCH_TRACER
 -
 -config X86_PTRACE_BTS
 -      bool "Branch Trace Store"
 -      default y
 -      depends on X86_DEBUGCTLMSR
 -      depends on BROKEN
 -      ---help---
 -        This adds a ptrace interface to the hardware's branch trace store.
 -
 -        Debuggers may use it to collect an execution trace of the debugged
 -        application in order to answer the question 'how did I get here?'.
 -        Debuggers may trace user mode as well as kernel mode.
 -
 -        Say Y unless there is no application development on this machine
 -        and you want to save a small amount of code size.
index 630e623f61e0defb51a51c7e07aa5340cde4d465,9b11a5cc666268d68f16ed840546d408e3699dbe..dca9c545f44e6be7105f85c3a5f17ac16020d9fa
   */
  #define X86_FEATURE_IDA               (7*32+ 0) /* Intel Dynamic Acceleration */
  #define X86_FEATURE_ARAT      (7*32+ 1) /* Always Running APIC Timer */
 +#define X86_FEATURE_CPB               (7*32+ 2) /* AMD Core Performance Boost */
  
  /* Virtualization flags: Linux defined */
  #define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
  
  #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
  
+ #include <asm/asm.h>
  #include <linux/bitops.h>
  
  extern const char * const x86_cap_flags[NCAPINTS*32];
@@@ -284,6 -284,62 +285,62 @@@ extern const char * const x86_power_fla
  
  #endif /* CONFIG_X86_64 */
  
+ /*
+  * Static testing of CPU features.  Used the same as boot_cpu_has().
+  * These are only valid after alternatives have run, but will statically
+  * patch the target code for additional performance.
+  *
+  */
+ static __always_inline __pure bool __static_cpu_has(u8 bit)
+ {
+ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+               asm goto("1: jmp %l[t_no]\n"
+                        "2:\n"
+                        ".section .altinstructions,\"a\"\n"
+                        _ASM_ALIGN "\n"
+                        _ASM_PTR "1b\n"
+                        _ASM_PTR "0\n"         /* no replacement */
+                        " .byte %P0\n"         /* feature bit */
+                        " .byte 2b - 1b\n"     /* source len */
+                        " .byte 0\n"           /* replacement len */
+                        " .byte 0xff + 0 - (2b-1b)\n"  /* padding */
+                        ".previous\n"
+                        : : "i" (bit) : : t_no);
+               return true;
+       t_no:
+               return false;
+ #else
+               u8 flag;
+               /* Open-coded due to __stringify() in ALTERNATIVE() */
+               asm volatile("1: movb $0,%0\n"
+                            "2:\n"
+                            ".section .altinstructions,\"a\"\n"
+                            _ASM_ALIGN "\n"
+                            _ASM_PTR "1b\n"
+                            _ASM_PTR "3f\n"
+                            " .byte %P1\n"             /* feature bit */
+                            " .byte 2b - 1b\n"         /* source len */
+                            " .byte 4f - 3f\n"         /* replacement len */
+                            " .byte 0xff + (4f-3f) - (2b-1b)\n" /* padding */
+                            ".previous\n"
+                            ".section .altinstr_replacement,\"ax\"\n"
+                            "3: movb $1,%0\n"
+                            "4:\n"
+                            ".previous\n"
+                            : "=qm" (flag) : "i" (bit));
+               return flag;
+ #endif
+ }
+ #define static_cpu_has(bit)                                   \
+ (                                                             \
+       __builtin_constant_p(boot_cpu_has(bit)) ?               \
+               boot_cpu_has(bit) :                             \
+       (__builtin_constant_p(bit) && !((bit) & ~0xff)) ?       \
+               __static_cpu_has(bit) :                         \
+               boot_cpu_has(bit)                               \
+ )
  #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
  
  #endif /* _ASM_X86_CPUFEATURE_H */
index c71a12d960d48159f35ba47e83867e561912ce11,b684f587647c13529216bb3ca367cc1fdb9a3bc9..5a51379dcbe4a7c3dab91a157f752d4c58889117
@@@ -21,6 -21,7 +21,6 @@@ struct mm_struct
  #include <asm/msr.h>
  #include <asm/desc_defs.h>
  #include <asm/nops.h>
 -#include <asm/ds.h>
  
  #include <linux/personality.h>
  #include <linux/cpumask.h>
@@@ -28,7 -29,6 +28,7 @@@
  #include <linux/threads.h>
  #include <linux/math64.h>
  #include <linux/init.h>
 +#include <linux/err.h>
  
  #define HBP_NUM 4
  /*
@@@ -113,6 -113,7 +113,6 @@@ struct cpuinfo_x86 
        /* Index into per_cpu list: */
        u16                     cpu_index;
  #endif
 -      unsigned int            x86_hyper_vendor;
  } __attribute__((__aligned__(SMP_CACHE_BYTES)));
  
  #define X86_VENDOR_INTEL      0
  
  #define X86_VENDOR_UNKNOWN    0xff
  
 -#define X86_HYPER_VENDOR_NONE  0
 -#define X86_HYPER_VENDOR_VMWARE 1
 -
  /*
   * capabilities of CPUs
   */
@@@ -376,6 -380,10 +376,10 @@@ union thread_xstate 
        struct xsave_struct             xsave;
  };
  
+ struct fpu {
+       union thread_xstate *state;
+ };
  #ifdef CONFIG_X86_64
  DECLARE_PER_CPU(struct orig_ist, orig_ist);
  
@@@ -453,7 -461,7 +457,7 @@@ struct thread_struct 
        unsigned long           trap_no;
        unsigned long           error_code;
        /* floating point and extended processor state */
-       union thread_xstate     *xstate;
+       struct fpu              fpu;
  #ifdef CONFIG_X86_32
        /* Virtual 86 mode info */
        struct vm86_struct __user *vm86_info;
        unsigned long           iopl;
        /* Max allowed port in the bitmap, in bytes: */
        unsigned                io_bitmap_max;
 -/* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set.  */
 -      unsigned long   debugctlmsr;
 -      /* Debug Store context; see asm/ds.h */
 -      struct ds_context       *ds_ctx;
  };
  
  static inline unsigned long native_get_debugreg(int regno)
@@@ -795,7 -807,7 +799,7 @@@ extern void cpu_init(void)
  
  static inline unsigned long get_debugctlmsr(void)
  {
 -    unsigned long debugctlmsr = 0;
 +      unsigned long debugctlmsr = 0;
  
  #ifndef CONFIG_X86_DEBUGCTLMSR
        if (boot_cpu_data.x86 < 6)
  #endif
        rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
  
 -    return debugctlmsr;
 -}
 -
 -static inline unsigned long get_debugctlmsr_on_cpu(int cpu)
 -{
 -      u64 debugctlmsr = 0;
 -      u32 val1, val2;
 -
 -#ifndef CONFIG_X86_DEBUGCTLMSR
 -      if (boot_cpu_data.x86 < 6)
 -              return 0;
 -#endif
 -      rdmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, &val1, &val2);
 -      debugctlmsr = val1 | ((u64)val2 << 32);
 -
        return debugctlmsr;
  }
  
@@@ -815,6 -842,18 +819,6 @@@ static inline void update_debugctlmsr(u
        wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
  }
  
 -static inline void update_debugctlmsr_on_cpu(int cpu,
 -                                           unsigned long debugctlmsr)
 -{
 -#ifndef CONFIG_X86_DEBUGCTLMSR
 -      if (boot_cpu_data.x86 < 6)
 -              return;
 -#endif
 -      wrmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR,
 -                   (u32)((u64)debugctlmsr),
 -                   (u32)((u64)debugctlmsr >> 32));
 -}
 -
  /*
   * from system description table in BIOS. Mostly for MCA use, but
   * others may find it useful:
index d017ed5502e27d747a99e048884e28c3316f0bd0,e9e341505ab3ce78a743aeb2e2e305a11e06a98e..d4092fac226b75249493e3fcc2ed0a4287abac10
@@@ -92,7 -92,8 +92,7 @@@ struct thread_info 
  #define TIF_IO_BITMAP         22      /* uses I/O bitmap */
  #define TIF_FREEZE            23      /* is freezing for suspend */
  #define TIF_FORCED_TF         24      /* true if TF in eflags artificially */
 -#define TIF_DEBUGCTLMSR               25      /* uses thread_struct.debugctlmsr */
 -#define TIF_DS_AREA_MSR               26      /* uses thread_struct.ds_area_msr */
 +#define TIF_BLOCKSTEP         25      /* set when we want DEBUGCTLMSR_BTF */
  #define TIF_LAZY_MMU_UPDATES  27      /* task is updating the mmu lazily */
  #define TIF_SYSCALL_TRACEPOINT        28      /* syscall tracepoint instrumentation */
  
  #define _TIF_IO_BITMAP                (1 << TIF_IO_BITMAP)
  #define _TIF_FREEZE           (1 << TIF_FREEZE)
  #define _TIF_FORCED_TF                (1 << TIF_FORCED_TF)
 -#define _TIF_DEBUGCTLMSR      (1 << TIF_DEBUGCTLMSR)
 -#define _TIF_DS_AREA_MSR      (1 << TIF_DS_AREA_MSR)
 +#define _TIF_BLOCKSTEP                (1 << TIF_BLOCKSTEP)
  #define _TIF_LAZY_MMU_UPDATES (1 << TIF_LAZY_MMU_UPDATES)
  #define _TIF_SYSCALL_TRACEPOINT       (1 << TIF_SYSCALL_TRACEPOINT)
  
  
  /* flags to check in __switch_to() */
  #define _TIF_WORK_CTXSW                                                       \
 -      (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC)
 +      (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP)
  
  #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
  #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
@@@ -242,7 -244,6 +242,6 @@@ static inline struct thread_info *curre
  #define TS_POLLING            0x0004  /* true if in idle loop
                                           and not sleeping */
  #define TS_RESTORE_SIGMASK    0x0008  /* restore signal mask in do_signal() */
- #define TS_XSAVE              0x0010  /* Use xsave/xrstor */
  
  #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
  
index cc6877535ef49919f7f8d207d68f6e57d73489ea,f18fd9c152479fec37af088d2b980f029961e074..e7e35219b32f23e115c23846d06c07b0128e26ae
@@@ -20,6 -20,7 +20,6 @@@
  #include <asm/idle.h>
  #include <asm/uaccess.h>
  #include <asm/i387.h>
 -#include <asm/ds.h>
  #include <asm/debugreg.h>
  
  unsigned long idle_halt;
@@@ -31,24 -32,23 +31,22 @@@ struct kmem_cache *task_xstate_cachep
  
  int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
  {
+       int ret;
        *dst = *src;
-       if (src->thread.xstate) {
-               dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
-                                                     GFP_KERNEL);
-               if (!dst->thread.xstate)
-                       return -ENOMEM;
-               WARN_ON((unsigned long)dst->thread.xstate & 15);
-               memcpy(dst->thread.xstate, src->thread.xstate, xstate_size);
+       if (fpu_allocated(&src->thread.fpu)) {
+               memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
+               ret = fpu_alloc(&dst->thread.fpu);
+               if (ret)
+                       return ret;
+               fpu_copy(&dst->thread.fpu, &src->thread.fpu);
        }
        return 0;
  }
  
  void free_thread_xstate(struct task_struct *tsk)
  {
-       if (tsk->thread.xstate) {
-               kmem_cache_free(task_xstate_cachep, tsk->thread.xstate);
-               tsk->thread.xstate = NULL;
-       }
+       fpu_free(&tsk->thread.fpu);
 -      WARN(tsk->thread.ds_ctx, "leaking DS context\n");
  }
  
  void free_thread_info(struct thread_info *ti)
@@@ -195,16 -195,11 +193,16 @@@ void __switch_to_xtra(struct task_struc
        prev = &prev_p->thread;
        next = &next_p->thread;
  
 -      if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) ||
 -          test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR))
 -              ds_switch_to(prev_p, next_p);
 -      else if (next->debugctlmsr != prev->debugctlmsr)
 -              update_debugctlmsr(next->debugctlmsr);
 +      if (test_tsk_thread_flag(prev_p, TIF_BLOCKSTEP) ^
 +          test_tsk_thread_flag(next_p, TIF_BLOCKSTEP)) {
 +              unsigned long debugctl = get_debugctlmsr();
 +
 +              debugctl &= ~DEBUGCTLMSR_BTF;
 +              if (test_tsk_thread_flag(next_p, TIF_BLOCKSTEP))
 +                      debugctl |= DEBUGCTLMSR_BTF;
 +
 +              update_debugctlmsr(debugctl);
 +      }
  
        if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
            test_tsk_thread_flag(next_p, TIF_NOTSC)) {
@@@ -548,13 -543,11 +546,13 @@@ static int __cpuinit check_c1e_idle(con
                 * check OSVW bit for CPUs that are not affected
                 * by erratum #400
                 */
 -              rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, val);
 -              if (val >= 2) {
 -                      rdmsrl(MSR_AMD64_OSVW_STATUS, val);
 -                      if (!(val & BIT(1)))
 -                              goto no_c1e_idle;
 +              if (cpu_has(c, X86_FEATURE_OSVW)) {
 +                      rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, val);
 +                      if (val >= 2) {
 +                              rdmsrl(MSR_AMD64_OSVW_STATUS, val);
 +                              if (!(val & BIT(1)))
 +                                      goto no_c1e_idle;
 +                      }
                }
                return 1;
        }
index 75090c589b7a23f61dec3c70e801ffe2fdb248e9,0a7a4f5bbaa9d65a7f6e1929c7075af372af3b72..8d128783af47374e56412d01d0488aa12af1647b
@@@ -55,6 -55,7 +55,6 @@@
  #include <asm/cpu.h>
  #include <asm/idle.h>
  #include <asm/syscalls.h>
 -#include <asm/ds.h>
  #include <asm/debugreg.h>
  
  asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
@@@ -237,6 -238,13 +237,6 @@@ int copy_thread(unsigned long clone_fla
                kfree(p->thread.io_bitmap_ptr);
                p->thread.io_bitmap_max = 0;
        }
 -
 -      clear_tsk_thread_flag(p, TIF_DS_AREA_MSR);
 -      p->thread.ds_ctx = NULL;
 -
 -      clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
 -      p->thread.debugctlmsr = 0;
 -
        return err;
  }
  
@@@ -309,7 -317,7 +309,7 @@@ __switch_to(struct task_struct *prev_p
  
        /* we're going to use this soon, after a few expensive things */
        if (preload_fpu)
-               prefetch(next->xstate);
+               prefetch(next->fpu.state);
  
        /*
         * Reload esp0.
index 50cc84ac0a0df9e3cc02aa2a380f3d57c4ef48b3,979215f519852ffa49aba747b10b48bf6f528736..3c2422a99f1f8293480ad436551cfac8c600d326
@@@ -49,6 -49,7 +49,6 @@@
  #include <asm/ia32.h>
  #include <asm/idle.h>
  #include <asm/syscalls.h>
 -#include <asm/ds.h>
  #include <asm/debugreg.h>
  
  asmlinkage extern void ret_from_fork(void);
@@@ -312,6 -313,13 +312,6 @@@ int copy_thread(unsigned long clone_fla
                if (err)
                        goto out;
        }
 -
 -      clear_tsk_thread_flag(p, TIF_DS_AREA_MSR);
 -      p->thread.ds_ctx = NULL;
 -
 -      clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
 -      p->thread.debugctlmsr = 0;
 -
        err = 0;
  out:
        if (err && p->thread.io_bitmap_ptr) {
@@@ -388,7 -396,7 +388,7 @@@ __switch_to(struct task_struct *prev_p
  
        /* we're going to use this soon, after a few expensive things */
        if (preload_fpu)
-               prefetch(next->xstate);
+               prefetch(next->fpu.state);
  
        /*
         * Reload esp0, LDT and the page table pointer:
diff --combined arch/x86/kernel/traps.c
index 36f1bd9f8e76b04a927f3f74bd0e52ffc0990019,00516e1de55de3262c4a7aa204dffc06b9598f3c..02cfb9b8f5b10f8d282715cc7a79fd49e04b7468
@@@ -108,15 -108,6 +108,6 @@@ static inline void preempt_conditional_
        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)
@@@ -543,11 -534,11 +534,11 @@@ dotraplinkage void __kprobes do_debug(s
  
        /* DR6 may or may not be cleared by the CPU */
        set_debugreg(0, 6);
 +
        /*
         * The processor cleared BTF, so don't mark that we need it set.
         */
 -      clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
 -      tsk->thread.debugctlmsr = 0;
 +      clear_tsk_thread_flag(tsk, TIF_BLOCKSTEP);
  
        /* Store the virtualized DR6 value */
        tsk->thread.debugreg6 = dr6;
        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 */
                /*
  
  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
This page took 0.100164 seconds and 4 git commands to generate.