Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Oct 2010 20:34:32 +0000 (13:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Oct 2010 20:34:32 +0000 (13:34 -0700)
* 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, fpu: Merge fpu_save_init()
  x86-32, fpu: Rewrite fpu_save_init()
  x86, fpu: Remove PSHUFB_XMM5_* macros
  x86, fpu: Remove unnecessary ifdefs from i387 code.
  x86-32, fpu: Remove math_emulate stub
  x86-64, fpu: Simplify constraints for fxsave/fxtstor
  x86-64, fpu: Fix %cs value in convert_from_fxsr()
  x86-64, fpu: Disable preemption when using TS_USEDFPU
  x86, fpu: Merge __save_init_fpu()
  x86, fpu: Merge tolerant_fwait()
  x86, fpu: Merge fpu_init()
  x86: Use correct type for %cr4
  x86, xsave: Disable xsave in i387 emulation mode

Fixed up fxsaveq-induced conflict in arch/x86/include/asm/i387.h

1  2 
arch/x86/include/asm/i387.h
arch/x86/include/asm/processor.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/i387.c

@@@ -55,6 -55,12 +55,12 @@@ extern int save_i387_xstate_ia32(void _
  extern int restore_i387_xstate_ia32(void __user *buf);
  #endif
  
+ #ifdef CONFIG_MATH_EMULATION
+ extern void finit_soft_fpu(struct i387_soft_struct *soft);
+ #else
+ static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
+ #endif
  #define X87_FSW_ES (1 << 7)   /* Exception Summary */
  
  static __always_inline __pure bool use_xsaveopt(void)
@@@ -67,6 -73,11 +73,11 @@@ static __always_inline __pure bool use_
        return static_cpu_has(X86_FEATURE_XSAVE);
  }
  
+ static __always_inline __pure bool use_fxsr(void)
+ {
+         return static_cpu_has(X86_FEATURE_FXSR);
+ }
  extern void __sanitize_i387_state(struct task_struct *);
  
  static inline void sanitize_i387_state(struct task_struct *tsk)
  }
  
  #ifdef CONFIG_X86_64
- /* Ignore delayed exceptions from user space */
- static inline void tolerant_fwait(void)
- {
-       asm volatile("1: fwait\n"
-                    "2:\n"
-                    _ASM_EXTABLE(1b, 2b));
- }
  static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
  {
        int err;
  
+       /* See comment in fxsave() below. */
        asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
                     "2:\n"
                     ".section .fixup,\"ax\"\n"
                     ".previous\n"
                     _ASM_EXTABLE(1b, 3b)
                     : [err] "=r" (err)
- #if 0 /* See comment in fxsave() below. */
-                    : [fx] "r" (fx), "m" (*fx), "0" (0));
- #else
-                    : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
- #endif
+                    : [fx] "R" (fx), "m" (*fx), "0" (0));
        return err;
  }
  
- /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
-    is pending. Clear the x87 state here by setting it to fixed
-    values. The kernel data segment can be sometimes 0 and sometimes
-    new user value. Both should be ok.
-    Use the PDA as safe address because it should be already in L1. */
- static inline void fpu_clear(struct fpu *fpu)
- {
-       struct xsave_struct *xstate = &fpu->state->xsave;
-       struct i387_fxsave_struct *fx = &fpu->state->fxsave;
-       /*
-        * xsave header may indicate the init state of the FP.
-        */
-       if (use_xsave() &&
-           !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
-               return;
-       if (unlikely(fx->swd & X87_FSW_ES))
-               asm volatile("fnclex");
-       alternative_input(ASM_NOP8 ASM_NOP2,
-                         "    emms\n"          /* clear stack tags */
-                         "    fildl %%gs:0",   /* load to clear state */
-                         X86_FEATURE_FXSAVE_LEAK);
- }
- static inline void clear_fpu_state(struct task_struct *tsk)
- {
-       fpu_clear(&tsk->thread.fpu);
- }
  static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
  {
        int err;
        if (unlikely(err))
                return -EFAULT;
  
+       /* See comment in fxsave() below. */
        asm volatile("1:  rex64/fxsave (%[fx])\n\t"
                     "2:\n"
                     ".section .fixup,\"ax\"\n"
                     ".previous\n"
                     _ASM_EXTABLE(1b, 3b)
                     : [err] "=r" (err), "=m" (*fx)
- #if 0 /* See comment in fxsave() below. */
-                    : [fx] "r" (fx), "0" (0));
- #else
-                    : [fx] "cdaSDb" (fx), "0" (0));
- #endif
+                    : [fx] "R" (fx), "0" (0));
        if (unlikely(err) &&
            __clear_user(fx, sizeof(struct i387_fxsave_struct)))
                err = -EFAULT;
@@@ -174,57 -140,26 +140,30 @@@ static inline void fpu_fxsave(struct fp
        /* Using "rex64; fxsave %0" is broken because, if the memory operand
           uses any extended registers for addressing, a second REX prefix
           will be generated (to the assembler, rex64 followed by semicolon
 -         is a separate instruction), and hence the 64-bitness is lost.
 -         Using "fxsaveq %0" would be the ideal choice, but is only supported
 -         starting with gas 2.16.
 -      asm volatile("fxsaveq %0"
 -                   : "=m" (fpu->state->fxsave));
 -         Using, as a workaround, the properly prefixed form below isn't
 +         is a separate instruction), and hence the 64-bitness is lost. */
++
 +#ifdef CONFIG_AS_FXSAVEQ
 +      /* Using "fxsaveq %0" would be the ideal choice, but is only supported
 +         starting with gas 2.16. */
 +      __asm__ __volatile__("fxsaveq %0"
 +                           : "=m" (fpu->state->fxsave));
- #elif 0
++#else
 +      /* Using, as a workaround, the properly prefixed form below isn't
           accepted by any binutils version so far released, complaining that
           the same type of prefix is used twice if an extended register is
-          needed for addressing (fix submitted to mainline 2005-11-21). */
-       __asm__ __volatile__("rex64/fxsave %0"
-                            : "=m" (fpu->state->fxsave));
- #else
-       /* This, however, we can work around by forcing the compiler to select
+          needed for addressing (fix submitted to mainline 2005-11-21).
+       asm volatile("rex64/fxsave %0"
+                    : "=m" (fpu->state->fxsave));
+          This, however, we can work around by forcing the compiler to select
           an addressing mode that doesn't require extended registers. */
-       __asm__ __volatile__("rex64/fxsave (%1)"
-                            : "=m" (fpu->state->fxsave)
-                            : "cdaSDb" (&fpu->state->fxsave));
+       asm volatile("rex64/fxsave (%[fx])"
+                    : "=m" (fpu->state->fxsave)
+                    : [fx] "R" (&fpu->state->fxsave));
 +#endif
  }
  
- static inline void fpu_save_init(struct fpu *fpu)
- {
-       if (use_xsave())
-               fpu_xsave(fpu);
-       else
-               fpu_fxsave(fpu);
-       fpu_clear(fpu);
- }
- static inline void __save_init_fpu(struct task_struct *tsk)
- {
-       fpu_save_init(&tsk->thread.fpu);
-       task_thread_info(tsk)->status &= ~TS_USEDFPU;
- }
  #else  /* CONFIG_X86_32 */
  
- #ifdef CONFIG_MATH_EMULATION
- extern void finit_soft_fpu(struct i387_soft_struct *soft);
- #else
- static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
- #endif
- static inline void tolerant_fwait(void)
- {
-       asm volatile("fnclex ; fwait");
- }
  /* perform fxrstor iff the processor has extended states, otherwise frstor */
  static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
  {
        return 0;
  }
  
+ static inline void fpu_fxsave(struct fpu *fpu)
+ {
+       asm volatile("fxsave %[fx]"
+                    : [fx] "=m" (fpu->state->fxsave));
+ }
+ #endif        /* CONFIG_X86_64 */
  /* We need a safe address that is cheap to find and that is already
     in L1 during context switch. The best choices are unfortunately
     different for UP and SMP */
  static inline void fpu_save_init(struct fpu *fpu)
  {
        if (use_xsave()) {
-               struct xsave_struct *xstate = &fpu->state->xsave;
-               struct i387_fxsave_struct *fx = &fpu->state->fxsave;
                fpu_xsave(fpu);
  
                /*
                 * xsave header may indicate the init state of the FP.
                 */
-               if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
-                       goto end;
-               if (unlikely(fx->swd & X87_FSW_ES))
-                       asm volatile("fnclex");
-               /*
-                * we can do a simple return here or be paranoid :)
-                */
-               goto clear_state;
+               if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
+                       return;
+       } else if (use_fxsr()) {
+               fpu_fxsave(fpu);
+       } else {
+               asm volatile("fsave %[fx]; fwait"
+                            : [fx] "=m" (fpu->state->fsave));
+               return;
        }
  
-       /* Use more nops than strictly needed in case the compiler
-          varies code */
-       alternative_input(
-               "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
-               "fxsave %[fx]\n"
-               "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
-               X86_FEATURE_FXSR,
-               [fx] "m" (fpu->state->fxsave),
-               [fsw] "m" (fpu->state->fxsave.swd) : "memory");
- clear_state:
+       if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES))
+               asm volatile("fnclex");
        /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
           is pending.  Clear the x87 state here by setting it to fixed
           values. safe_address is a random variable that should be in L1 */
        alternative_input(
-               GENERIC_NOP8 GENERIC_NOP2,
+               ASM_NOP8 ASM_NOP2,
                "emms\n\t"              /* clear stack tags */
-               "fildl %[addr]",        /* set F?P to defined value */
+               "fildl %P[addr]",       /* set F?P to defined value */
                X86_FEATURE_FXSAVE_LEAK,
                [addr] "m" (safe_address));
- end:
-       ;
  }
  
  static inline void __save_init_fpu(struct task_struct *tsk)
        task_thread_info(tsk)->status &= ~TS_USEDFPU;
  }
  
- #endif        /* CONFIG_X86_64 */
  static inline int fpu_fxrstor_checking(struct fpu *fpu)
  {
        return fxrstor_checking(&fpu->state->fxsave);
@@@ -344,7 -270,10 +274,10 @@@ static inline void __unlazy_fpu(struct 
  static inline void __clear_fpu(struct task_struct *tsk)
  {
        if (task_thread_info(tsk)->status & TS_USEDFPU) {
-               tolerant_fwait();
+               /* Ignore delayed exceptions from user space */
+               asm volatile("1: fwait\n"
+                            "2:\n"
+                            _ASM_EXTABLE(1b, 2b));
                task_thread_info(tsk)->status &= ~TS_USEDFPU;
                stts();
        }
@@@ -405,19 -334,6 +338,6 @@@ static inline void irq_ts_restore(int T
                stts();
  }
  
- #ifdef CONFIG_X86_64
- static inline void save_init_fpu(struct task_struct *tsk)
- {
-       __save_init_fpu(tsk);
-       stts();
- }
- #define unlazy_fpu    __unlazy_fpu
- #define clear_fpu     __clear_fpu
- #else  /* CONFIG_X86_32 */
  /*
   * These disable preemption on their own and are safe
   */
@@@ -443,8 -359,6 +363,6 @@@ static inline void clear_fpu(struct tas
        preempt_enable();
  }
  
- #endif        /* CONFIG_X86_64 */
  /*
   * i387 state interaction
   */
@@@ -508,7 -422,4 +426,4 @@@ extern void fpu_finit(struct fpu *fpu)
  
  #endif /* __ASSEMBLY__ */
  
- #define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
- #define PSHUFB_XMM5_XMM6 .byte 0x66, 0x0f, 0x38, 0x00, 0xf5
  #endif /* _ASM_X86_I387_H */
@@@ -110,8 -110,6 +110,8 @@@ struct cpuinfo_x86 
        u16                     phys_proc_id;
        /* Core id: */
        u16                     cpu_core_id;
 +      /* Compute unit id */
 +      u8                      compute_unit_id;
        /* Index into per_cpu list: */
        u16                     cpu_index;
  #endif
@@@ -604,7 -602,7 +604,7 @@@ extern unsigned long               mmu_cr4_features
  
  static inline void set_in_cr4(unsigned long mask)
  {
-       unsigned cr4;
+       unsigned long cr4;
  
        mmu_cr4_features |= mask;
        cr4 = read_cr4();
  
  static inline void clear_in_cr4(unsigned long mask)
  {
-       unsigned cr4;
+       unsigned long cr4;
  
        mmu_cr4_features &= ~mask;
        cr4 = read_cr4();
@@@ -545,7 -545,7 +545,7 @@@ void __cpuinit cpu_detect(struct cpuinf
        }
  }
  
 -static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
 +void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
  {
        u32 tfms, xlvl;
        u32 ebx;
@@@ -665,7 -665,7 +665,7 @@@ static void __init early_identify_cpu(s
                this_cpu->c_early_init(c);
  
  #ifdef CONFIG_SMP
 -      c->cpu_index = boot_cpu_id;
 +      c->cpu_index = 0;
  #endif
        filter_cpuid_features(c, false);
  }
@@@ -704,21 -704,16 +704,21 @@@ void __init early_cpu_init(void
  }
  
  /*
 - * The NOPL instruction is supposed to exist on all CPUs with
 - * family >= 6; unfortunately, that's not true in practice because
 - * of early VIA chips and (more importantly) broken virtualizers that
 - * are not easy to detect.  In the latter case it doesn't even *fail*
 - * reliably, so probing for it doesn't even work.  Disable it completely
 + * The NOPL instruction is supposed to exist on all CPUs of family >= 6;
 + * unfortunately, that's not true in practice because of early VIA
 + * chips and (more importantly) broken virtualizers that are not easy
 + * to detect. In the latter case it doesn't even *fail* reliably, so
 + * probing for it doesn't even work. Disable it completely on 32-bit
   * unless we can find a reliable way to detect all the broken cases.
 + * Enable it explicitly on 64-bit for non-constant inputs of cpu_has().
   */
  static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
  {
 +#ifdef CONFIG_X86_32
        clear_cpu_cap(c, X86_FEATURE_NOPL);
 +#else
 +      set_cpu_cap(c, X86_FEATURE_NOPL);
 +#endif
  }
  
  static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
@@@ -1269,13 -1264,6 +1269,6 @@@ void __cpuinit cpu_init(void
        clear_all_debug_regs();
        dbg_restore_debug_regs();
  
-       /*
-        * Force FPU initialization:
-        */
-       current_thread_info()->status = 0;
-       clear_used_math();
-       mxcsr_feature_mask_init();
        fpu_init();
        xsave_init();
  }
diff --combined arch/x86/kernel/i387.c
@@@ -40,7 -40,6 +40,7 @@@
  
  static unsigned int           mxcsr_feature_mask __read_mostly = 0xffffffffu;
  unsigned int xstate_size;
 +EXPORT_SYMBOL_GPL(xstate_size);
  unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
  static struct i387_fxsave_struct fx_scratch __cpuinitdata;
  
@@@ -68,19 -67,22 +68,22 @@@ static void __cpuinit init_thread_xstat
         */
  
        if (!HAVE_HWFP) {
+               /*
+                * Disable xsave as we do not support it if i387
+                * emulation is enabled.
+                */
+               setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+               setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
                xstate_size = sizeof(struct i387_soft_struct);
                return;
        }
  
        if (cpu_has_fxsr)
                xstate_size = sizeof(struct i387_fxsave_struct);
- #ifdef CONFIG_X86_32
        else
                xstate_size = sizeof(struct i387_fsave_struct);
- #endif
  }
  
- #ifdef CONFIG_X86_64
  /*
   * Called at bootup to set up the initial FPU state that is later cloned
   * into all processes.
  
  void __cpuinit fpu_init(void)
  {
-       unsigned long oldcr0 = read_cr0();
-       set_in_cr4(X86_CR4_OSFXSR);
-       set_in_cr4(X86_CR4_OSXMMEXCPT);
+       unsigned long cr0;
+       unsigned long cr4_mask = 0;
  
-       write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
+       if (cpu_has_fxsr)
+               cr4_mask |= X86_CR4_OSFXSR;
+       if (cpu_has_xmm)
+               cr4_mask |= X86_CR4_OSXMMEXCPT;
+       if (cr4_mask)
+               set_in_cr4(cr4_mask);
+       cr0 = read_cr0();
+       cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
+       if (!HAVE_HWFP)
+               cr0 |= X86_CR0_EM;
+       write_cr0(cr0);
  
        if (!smp_processor_id())
                init_thread_xstate();
        clear_used_math();
  }
  
- #else /* CONFIG_X86_64 */
- void __cpuinit fpu_init(void)
- {
-       if (!smp_processor_id())
-               init_thread_xstate();
- }
- #endif        /* CONFIG_X86_32 */
  void fpu_finit(struct fpu *fpu)
  {
- #ifdef CONFIG_X86_32
        if (!HAVE_HWFP) {
                finit_soft_fpu(&fpu->state->soft);
                return;
        }
- #endif
  
        if (cpu_has_fxsr) {
                struct i387_fxsave_struct *fx = &fpu->state->fxsave;
@@@ -386,19 -385,17 +386,17 @@@ convert_from_fxsr(struct user_i387_ia32
  #ifdef CONFIG_X86_64
        env->fip = fxsave->rip;
        env->foo = fxsave->rdp;
+       /*
+        * should be actually ds/cs at fpu exception time, but
+        * that information is not available in 64bit mode.
+        */
+       env->fcs = task_pt_regs(tsk)->cs;
        if (tsk == current) {
-               /*
-                * should be actually ds/cs at fpu exception time, but
-                * that information is not available in 64bit mode.
-                */
-               asm("mov %%ds, %[fos]" : [fos] "=r" (env->fos));
-               asm("mov %%cs, %[fcs]" : [fcs] "=r" (env->fcs));
+               savesegment(ds, env->fos);
        } else {
-               struct pt_regs *regs = task_pt_regs(tsk);
-               env->fos = 0xffff0000 | tsk->thread.ds;
-               env->fcs = regs->cs;
+               env->fos = tsk->thread.ds;
        }
+       env->fos |= 0xffff0000;
  #else
        env->fip = fxsave->fip;
        env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);