X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fi387.c;h=8503c464f8be0e87bc5e6cd0975000e796974b50;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=0d35516ca293596bf199a79ecb75577d7417ce5c;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c index 0d35516ca..8503c464f 100644 --- a/arch/i386/kernel/i387.c +++ b/arch/i386/kernel/i387.c @@ -8,8 +8,8 @@ * Gareth Hughes , May 2000 */ -#include #include +#include #include #include #include @@ -24,7 +24,7 @@ #define HAVE_HWFP 1 #endif -unsigned long mxcsr_feature_mask = 0xffffffff; +static unsigned long mxcsr_feature_mask __read_mostly = 0xffffffff; void mxcsr_feature_mask_init(void) { @@ -60,7 +60,8 @@ void init_fpu(struct task_struct *tsk) tsk->thread.i387.fsave.twd = 0xffffffffu; tsk->thread.i387.fsave.fos = 0xffff0000u; } - tsk->used_math = 1; + /* only the device not available exception or ptrace can call init_fpu */ + set_stopped_child_used_math(tsk); } /* @@ -78,17 +79,7 @@ void kernel_fpu_begin(void) } clts(); } - -void restore_fpu( struct task_struct *tsk ) -{ - if ( cpu_has_fxsr ) { - asm volatile( "fxrstor %0" - : : "m" (tsk->thread.i387.fxsave) ); - } else { - asm volatile( "frstor %0" - : : "m" (tsk->thread.i387.fsave) ); - } -} +EXPORT_SYMBOL_GPL(kernel_fpu_begin); /* * FPU tag word conversions. @@ -111,16 +102,17 @@ static inline unsigned short twd_i387_to_fxsr( unsigned short twd ) static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave ) { struct _fpxreg *st = NULL; + unsigned long tos = (fxsave->swd >> 11) & 7; unsigned long twd = (unsigned long) fxsave->twd; unsigned long tag; unsigned long ret = 0xffff0000u; int i; -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); +#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16); for ( i = 0 ; i < 8 ; i++ ) { if ( twd & 0x1 ) { - st = (struct _fpxreg *) FPREG_ADDR( fxsave, i ); + st = FPREG_ADDR( fxsave, (i - tos) & 7 ); switch ( st->exponent & 0x7fff ) { case 0x7fff: @@ -175,6 +167,7 @@ unsigned short get_fpu_swd( struct task_struct *tsk ) } } +#if 0 unsigned short get_fpu_twd( struct task_struct *tsk ) { if ( cpu_has_fxsr ) { @@ -183,6 +176,7 @@ unsigned short get_fpu_twd( struct task_struct *tsk ) return (unsigned short)tsk->thread.i387.fsave.twd; } } +#endif /* 0 */ unsigned short get_fpu_mxcsr( struct task_struct *tsk ) { @@ -193,6 +187,8 @@ unsigned short get_fpu_mxcsr( struct task_struct *tsk ) } } +#if 0 + void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd ) { if ( cpu_has_fxsr ) { @@ -220,18 +216,16 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd ) } } +#endif /* 0 */ + /* * FXSR floating point environment conversions. */ -static int convert_fxsr_to_user( struct _fpstate __user *buf, - struct i387_fxsave_struct *fxsave ) +static inline void +convert_fxsr_env_to_i387(unsigned long env[7], + struct i387_fxsave_struct *fxsave) { - unsigned long env[7]; - struct _fpreg __user *to; - struct _fpxreg *from; - int i; - env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; env[2] = twd_fxsr_to_i387(fxsave); @@ -239,14 +233,24 @@ static int convert_fxsr_to_user( struct _fpstate __user *buf, env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); env[5] = fxsave->foo; env[6] = fxsave->fos; +} +static int convert_fxsr_to_user(struct _fpstate __user *buf, + struct i387_fxsave_struct *fxsave) +{ + unsigned long env[7]; + struct _fpreg __user *to; + struct _fpxreg *from; + int i; + + convert_fxsr_env_to_i387(env, fxsave); if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; to = &buf->_st[0]; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { - unsigned long *t = (unsigned long *)to; + unsigned long __user *t = (unsigned long __user *)to; unsigned long *f = (unsigned long *)from; if (__put_user(*f, t) || @@ -257,6 +261,20 @@ static int convert_fxsr_to_user( struct _fpstate __user *buf, return 0; } +static inline void +convert_fxsr_env_from_i387(struct i387_fxsave_struct *fxsave, + const unsigned long env[7]) +{ + fxsave->cwd = (unsigned short)(env[0] & 0xffff); + fxsave->swd = (unsigned short)(env[1] & 0xffff); + fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); + fxsave->fip = env[3]; + fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); + fxsave->fcs = (env[4] & 0xffff); + fxsave->foo = env[5]; + fxsave->fos = env[6]; +} + static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { @@ -268,20 +286,13 @@ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; - fxsave->cwd = (unsigned short)(env[0] & 0xffff); - fxsave->swd = (unsigned short)(env[1] & 0xffff); - fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); - fxsave->fip = env[3]; - fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); - fxsave->fcs = (env[4] & 0xffff); - fxsave->foo = env[5]; - fxsave->fos = env[6]; + convert_fxsr_env_from_i387(fxsave, env); to = (struct _fpxreg *) &fxsave->st_space[0]; from = &buf->_st[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; - unsigned long *f = (unsigned long *)from; + unsigned long __user *f = (unsigned long __user *)from; if (__get_user(*t, f) || __get_user(*(t + 1), f + 1) || @@ -330,13 +341,13 @@ static int save_i387_fxsave( struct _fpstate __user *buf ) int save_i387( struct _fpstate __user *buf ) { - if ( !current->used_math ) + if ( !used_math() ) return 0; /* This will cause a "finit" to be triggered by the next * attempted FPU operation by the 'current' process. */ - current->used_math = 0; + clear_used_math(); if ( HAVE_HWFP ) { if ( cpu_has_fxsr ) { @@ -382,7 +393,7 @@ int restore_i387( struct _fpstate __user *buf ) } else { err = restore_i387_soft( ¤t->thread.i387.soft, buf ); } - current->used_math = 1; + set_used_math(); return err; } @@ -390,88 +401,82 @@ int restore_i387( struct _fpstate __user *buf ) * ptrace request handlers. */ -static inline int get_fpregs_fsave( struct user_i387_struct __user *buf, - struct task_struct *tsk ) +static inline void get_fpregs_fsave(struct user_i387_struct *buf, + struct task_struct *tsk) { - return __copy_to_user( buf, &tsk->thread.i387.fsave, - sizeof(struct user_i387_struct) ); + memcpy(buf, &tsk->thread.i387.fsave, sizeof(struct user_i387_struct)); } -static inline int get_fpregs_fxsave( struct user_i387_struct __user *buf, - struct task_struct *tsk ) +static inline void get_fpregs_fxsave(struct user_i387_struct *buf, + struct task_struct *tsk) { - return convert_fxsr_to_user( (struct _fpstate __user *)buf, - &tsk->thread.i387.fxsave ); + struct _fpreg *to; + const struct _fpxreg *from; + unsigned int i; + + convert_fxsr_env_to_i387((unsigned long *) buf, + &tsk->thread.i387.fxsave); + + to = (struct _fpreg *) buf->st_space; + from = (const struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0]; + for (i = 0; i < 8; i++, to++, from++) + *to = *(const struct _fpreg *) from; } -int get_fpregs( struct user_i387_struct __user *buf, struct task_struct *tsk ) +int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk) { if ( HAVE_HWFP ) { - if ( cpu_has_fxsr ) { - return get_fpregs_fxsave( buf, tsk ); - } else { - return get_fpregs_fsave( buf, tsk ); - } + if (cpu_has_fxsr) + get_fpregs_fxsave(buf, tsk); + else + get_fpregs_fsave(buf, tsk); + return 0; } else { return save_i387_soft( &tsk->thread.i387.soft, (struct _fpstate __user *)buf ); } } -static inline int set_fpregs_fsave( struct task_struct *tsk, - struct user_i387_struct __user *buf ) +static inline void set_fpregs_fsave(struct task_struct *tsk, + const struct user_i387_struct *buf) { - return __copy_from_user( &tsk->thread.i387.fsave, buf, - sizeof(struct user_i387_struct) ); + memcpy(&tsk->thread.i387.fsave, buf, sizeof(struct user_i387_struct)); } -static inline int set_fpregs_fxsave( struct task_struct *tsk, - struct user_i387_struct __user *buf ) +static inline void set_fpregs_fxsave(struct task_struct *tsk, + const struct user_i387_struct *buf) { - return convert_fxsr_from_user( &tsk->thread.i387.fxsave, - (struct _fpstate __user *)buf ); + struct _fpxreg *to; + const struct _fpreg *from; + unsigned int i; + + convert_fxsr_env_from_i387(&tsk->thread.i387.fxsave, + (unsigned long *) buf); + + to = (struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0]; + from = (const struct _fpreg *) buf->st_space; + for (i = 0; i < 8; i++, to++, from++) + *(struct _fpreg *) to = *from; } -int set_fpregs( struct task_struct *tsk, struct user_i387_struct __user *buf ) +int set_fpregs(struct task_struct *tsk, const struct user_i387_struct *buf) { if ( HAVE_HWFP ) { - if ( cpu_has_fxsr ) { - return set_fpregs_fxsave( tsk, buf ); - } else { - return set_fpregs_fsave( tsk, buf ); - } + if (cpu_has_fxsr) + set_fpregs_fxsave(tsk, buf); + else + set_fpregs_fsave(tsk, buf); + return 0; } else { return restore_i387_soft( &tsk->thread.i387.soft, (struct _fpstate __user *)buf ); } } -int get_fpxregs( struct user_fxsr_struct __user *buf, struct task_struct *tsk ) -{ - if ( cpu_has_fxsr ) { - if (__copy_to_user( buf, &tsk->thread.i387.fxsave, - sizeof(struct user_fxsr_struct) )) - return -EFAULT; - return 0; - } else { - return -EIO; - } -} - -int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct __user *buf ) +void updated_fpxregs(struct task_struct *tsk) { - int ret = 0; - - if ( cpu_has_fxsr ) { - if (__copy_from_user( &tsk->thread.i387.fxsave, buf, - sizeof(struct user_fxsr_struct) )) - ret = -EFAULT; - /* mxcsr reserved bits must be masked to zero for security reasons */ - tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; - } else { - ret = -EIO; - } - return ret; + /* mxcsr reserved bits must be masked to zero for security reasons */ + tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; } /* @@ -506,7 +511,7 @@ int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu ) int fpvalid; struct task_struct *tsk = current; - fpvalid = tsk->used_math; + fpvalid = !!used_math(); if ( fpvalid ) { unlazy_fpu( tsk ); if ( cpu_has_fxsr ) { @@ -518,25 +523,11 @@ int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu ) return fpvalid; } - -int dump_extended_fpu( struct pt_regs *regs, struct user_fxsr_struct *fpu ) -{ - int fpvalid; - struct task_struct *tsk = current; - - fpvalid = tsk->used_math && cpu_has_fxsr; - if ( fpvalid ) { - unlazy_fpu( tsk ); - memcpy( fpu, &tsk->thread.i387.fxsave, - sizeof(struct user_fxsr_struct) ); - } - - return fpvalid; -} +EXPORT_SYMBOL(dump_fpu); int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu) { - int fpvalid = tsk->used_math; + int fpvalid = !!tsk_used_math(tsk); if (fpvalid) { if (tsk == current) @@ -551,7 +542,7 @@ int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu) int dump_task_extended_fpu(struct task_struct *tsk, struct user_fxsr_struct *fpu) { - int fpvalid = tsk->used_math && cpu_has_fxsr; + int fpvalid = tsk_used_math(tsk) && cpu_has_fxsr; if (fpvalid) { if (tsk == current)