2005-04-16 15:20:36 -07:00
/*
* 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>
2006-04-20 02:36:45 +02:00
# include <linux/kernel_stat.h>
2005-04-16 15:20:36 -07:00
# 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 * ) ;
2005-07-22 16:06:16 -04:00
2005-04-16 15:20:36 -07:00
/*
* FPU lazy state save handling . . .
*/
2005-07-22 16:06:16 -04:00
/*
* 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 , \
2005-07-22 18:19:20 -04:00
" m " ( ( tsk ) - > thread . i387 . fxsave ) )
2005-04-16 15:20:36 -07:00
extern void kernel_fpu_begin ( void ) ;
# define kernel_fpu_end() do { stts(); preempt_enable(); } while(0)
2006-04-20 02:36:45 +02:00
/* 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
2005-04-16 15:20:36 -07:00
/*
* These must be called with preempt disabled
*/
static inline void __save_init_fpu ( struct task_struct * tsk )
{
2006-04-20 02:36:45 +02:00
/* Use more nops than strictly needed in case the compiler
varies code */
2005-07-22 18:19:20 -04:00
alternative_input (
2006-04-20 02:36:45 +02:00
" fnsave %[fx] ;fwait; " GENERIC_NOP8 GENERIC_NOP4 ,
" fxsave %[fx] \n "
2006-04-29 14:07:49 -04:00
" bt $7,%[fsw] ; jnc 1f ; fnclex \n 1: " ,
2005-07-22 18:19:20 -04:00
X86_FEATURE_FXSR ,
2006-04-20 02:36:45 +02:00
[ 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
2006-04-29 14:07:49 -04:00
values . safe_address is a random variable that should be in L1 */
2006-04-20 02:36:45 +02:00
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 ) ) ;
2006-01-12 01:05:40 -08:00
task_thread_info ( tsk ) - > status & = ~ TS_USEDFPU ;
2005-04-16 15:20:36 -07:00
}
2007-05-02 19:27:21 +02:00
# define __unlazy_fpu( tsk ) do { \
if ( task_thread_info ( tsk ) - > status & TS_USEDFPU ) { \
__save_init_fpu ( tsk ) ; \
stts ( ) ; \
} else \
tsk - > fpu_counter = 0 ; \
2005-04-16 15:20:36 -07:00
} while ( 0 )
# define __clear_fpu( tsk ) \
do { \
2007-05-02 19:27:21 +02:00
if ( task_thread_info ( tsk ) - > status & TS_USEDFPU ) { \
asm volatile ( " fnclex ; fwait " ) ; \
2006-01-12 01:05:40 -08:00
task_thread_info ( tsk ) - > status & = ~ TS_USEDFPU ; \
2005-04-16 15:20:36 -07:00
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 )
2007-05-02 19:27:21 +02:00
2005-04-16 15:20:36 -07:00
/*
* 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 ) ;
2006-12-07 02:14:01 +01:00
extern asmlinkage void math_state_restore ( void ) ;
2005-04-16 15:20:36 -07:00
/*
* 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 */