diff options
Diffstat (limited to 'include/asm-x86/i387_32.h')
-rw-r--r-- | include/asm-x86/i387_32.h | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/include/asm-x86/i387_32.h b/include/asm-x86/i387_32.h new file mode 100644 index 000000000000..cdd1e248e3b4 --- /dev/null +++ b/include/asm-x86/i387_32.h @@ -0,0 +1,151 @@ +/* + * include/asm-i386/i387.h + * + * Copyright (C) 1994 Linus Torvalds + * + * Pentium III FXSR, SSE support + * General FPU state handling cleanups + * Gareth Hughes <gareth@valinux.com>, May 2000 + */ + +#ifndef __ASM_I386_I387_H +#define __ASM_I386_I387_H + +#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... + */ + +/* + * 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 ) +{ + /* 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 (task_thread_info(tsk)->status & TS_USEDFPU) { \ + __save_init_fpu(tsk); \ + stts(); \ + } else \ + tsk->fpu_counter = 0; \ +} while (0) + +#define __clear_fpu( tsk ) \ +do { \ + if (task_thread_info(tsk)->status & TS_USEDFPU) { \ + asm volatile("fnclex ; fwait"); \ + task_thread_info(tsk)->status &= ~TS_USEDFPU; \ + stts(); \ + } \ +} while (0) + + +/* + * These disable preemption on their own and are safe + */ +static inline void save_init_fpu( struct task_struct *tsk ) +{ + preempt_disable(); + __save_init_fpu(tsk); + stts(); + preempt_enable(); +} + +#define unlazy_fpu( tsk ) do { \ + preempt_disable(); \ + __unlazy_fpu(tsk); \ + preempt_enable(); \ +} while (0) + +#define clear_fpu( tsk ) do { \ + preempt_disable(); \ + __clear_fpu( tsk ); \ + preempt_enable(); \ +} while (0) + +/* + * FPU state interaction... + */ +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_mxcsr( struct task_struct *tsk ); +extern asmlinkage void math_state_restore(void); + +/* + * Signal frame handlers... + */ +extern int save_i387( struct _fpstate __user *buf ); +extern int restore_i387( struct _fpstate __user *buf ); + +/* + * ptrace request handers... + */ +extern int get_fpregs( struct user_i387_struct __user *buf, + struct task_struct *tsk ); +extern int set_fpregs( struct task_struct *tsk, + struct user_i387_struct __user *buf ); + +extern int get_fpxregs( struct user_fxsr_struct __user *buf, + struct task_struct *tsk ); +extern int set_fpxregs( struct task_struct *tsk, + struct user_fxsr_struct __user *buf ); + +/* + * FPU state for core dumps... + */ +extern int dump_fpu( struct pt_regs *regs, + struct user_i387_struct *fpu ); + +#endif /* __ASM_I386_I387_H */ |