X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fasm-i386%2Fi387.h;h=bc1d6edae1edfe73b9d77c318fea69b9d0951328;hb=e0ff8aa1acd079b70e796571917ae0449b7c465b;hp=db663695d003e9b4140f6798717f3077a5dd81e7;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h index db663695d..bc1d6edae 100644 --- a/include/asm-i386/i387.h +++ b/include/asm-i386/i387.h @@ -13,46 +13,77 @@ #include #include +#include #include #include #include -extern unsigned long mxcsr_feature_mask; 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) { \ - asm volatile("fwait"); \ - (tsk)->thread_info->status &= ~TS_USEDFPU; \ + if (task_thread_info(tsk)->status & TS_USEDFPU) { \ + asm volatile("fnclex ; fwait"); \ + task_thread_info(tsk)->status &= ~TS_USEDFPU; \ stts(); \ } \ } while (0) @@ -86,13 +117,8 @@ static inline void save_init_fpu( struct task_struct *tsk ) */ extern unsigned short get_fpu_cwd( struct task_struct *tsk ); extern unsigned short get_fpu_swd( struct task_struct *tsk ); -extern unsigned short get_fpu_twd( struct task_struct *tsk ); extern unsigned short get_fpu_mxcsr( struct task_struct *tsk ); -extern void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd ); -extern void set_fpu_swd( struct task_struct *tsk, unsigned short swd ); -extern void set_fpu_twd( struct task_struct *tsk, unsigned short twd ); - /* * Signal frame handlers... */ @@ -117,7 +143,5 @@ extern int set_fpxregs( struct task_struct *tsk, */ extern int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu ); -extern int dump_extended_fpu( struct pt_regs *regs, - struct user_fxsr_struct *fpu ); #endif /* __ASM_I386_I387_H */