Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / include / asm-i386 / i387.h
index f6feb98..bc1d6ed 100644 (file)
 
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/kernel_stat.h>
 #include <asm/processor.h>
 #include <asm/sigcontext.h>
 #include <asm/user.h>
 
 extern void mxcsr_feature_mask_init(void);
 extern void init_fpu(struct task_struct *);
+
 /*
  * FPU lazy state save handling...
  */
-extern void restore_fpu( struct task_struct *tsk );
+
+/*
+ * The "nop" is needed to make the instructions the same
+ * length.
+ */
+#define restore_fpu(tsk)                       \
+       alternative_input(                      \
+               "nop ; frstor %1",              \
+               "fxrstor %1",                   \
+               X86_FEATURE_FXSR,               \
+               "m" ((tsk)->thread.i387.fxsave))
 
 extern void kernel_fpu_begin(void);
 #define kernel_fpu_end() do { stts(); preempt_enable(); } while(0)
 
+/* 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 */
+#ifdef CONFIG_SMP
+#define safe_address (__per_cpu_offset[0])
+#else
+#define safe_address (kstat_cpu(0).cpustat.user)
+#endif
+
 /*
  * These must be called with preempt disabled
  */
 static inline void __save_init_fpu( struct task_struct *tsk )
 {
-       if ( cpu_has_fxsr ) {
-               asm volatile( "fxsave %0 ; fnclex"
-                             : "=m" (tsk->thread.i387.fxsave) );
-       } else {
-               asm volatile( "fnsave %0 ; fwait"
-                             : "=m" (tsk->thread.i387.fsave) );
-       }
-       tsk->thread_info->status &= ~TS_USEDFPU;
+       /* 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" (tsk->thread.i387.fxsave),
+               [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory");
+       /* 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,
+               "emms\n\t"              /* clear stack tags */
+               "fildl %[addr]",        /* set F?P to defined value */
+               X86_FEATURE_FXSAVE_LEAK,
+               [addr] "m" (safe_address));
+       task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
 #define __unlazy_fpu( tsk ) do { \
-       if ((tsk)->thread_info->status & TS_USEDFPU) \
+       if (task_thread_info(tsk)->status & TS_USEDFPU) \
                save_init_fpu( tsk ); \
 } while (0)
 
 #define __clear_fpu( tsk )                                     \
 do {                                                           \
-       if ((tsk)->thread_info->status & TS_USEDFPU) {          \
+       if (task_thread_info(tsk)->status & TS_USEDFPU) {               \
                asm volatile("fnclex ; fwait");                         \
-               (tsk)->thread_info->status &= ~TS_USEDFPU;      \
+               task_thread_info(tsk)->status &= ~TS_USEDFPU;   \
                stts();                                         \
        }                                                       \
 } while (0)