Merge to Fedora kernel-2.6.18-1.2255_FC5-vs2.0.2.2-rc9 patched with stable patch...
[linux-2.6.git] / arch / i386 / kernel / i387.c
index cc5628f..6658472 100644 (file)
@@ -8,8 +8,8 @@
  *     Gareth Hughes <gareth@valinux.com>, May 2000
  */
 
-#include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/module.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/math_emu.h>
@@ -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,6 +216,8 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd )
        }
 }
 
+#endif  /*  0  */
+
 /*
  * FXSR floating point environment conversions.
  */
@@ -227,7 +225,6 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd )
 static int convert_fxsr_to_user( struct _fpstate __user *buf,
                                        struct i387_fxsave_struct *fxsave )
 {
-       struct _fpreg tmp[8]; /* 80 bytes scratch area */
        unsigned long env[7];
        struct _fpreg __user *to;
        struct _fpxreg *from;
@@ -244,25 +241,23 @@ static int convert_fxsr_to_user( struct _fpstate __user *buf,
        if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
                return 1;
 
-       to = tmp;
+       to = &buf->_st[0];
        from = (struct _fpxreg *) &fxsave->st_space[0];
        for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
                unsigned long __user *t = (unsigned long __user *)to;
                unsigned long *f = (unsigned long *)from;
 
-               *t = *f;
-               *(t + 1) = *(f+1);
-               to->exponent = from->exponent;
+               if (__put_user(*f, t) ||
+                               __put_user(*(f + 1), t + 1) ||
+                               __put_user(from->exponent, &to->exponent))
+                       return 1;
        }
-       if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8])))
-               return 1;
        return 0;
 }
 
 static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
                                          struct _fpstate __user *buf )
 {
-       struct _fpreg tmp[8]; /* 80 bytes scratch area */
        unsigned long env[7];
        struct _fpxreg *to;
        struct _fpreg __user *from;
@@ -270,8 +265,6 @@ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
 
        if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
                return 1;
-       if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8])))
-               return 1;
 
        fxsave->cwd = (unsigned short)(env[0] & 0xffff);
        fxsave->swd = (unsigned short)(env[1] & 0xffff);
@@ -283,14 +276,15 @@ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
        fxsave->fos = env[6];
 
        to = (struct _fpxreg *) &fxsave->st_space[0];
-       from = tmp;
+       from = &buf->_st[0];
        for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
                unsigned long *t = (unsigned long *)to;
                unsigned long __user *f = (unsigned long __user *)from;
 
-               *t = *f;
-               *(t + 1) = *(f + 1);
-               to->exponent = from->exponent;
+               if (__get_user(*t, f) ||
+                               __get_user(*(t + 1), f + 1) ||
+                               __get_user(to->exponent, &from->exponent))
+                       return 1;
        }
        return 0;
 }
@@ -334,13 +328,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 ) {
@@ -386,7 +380,7 @@ int restore_i387( struct _fpstate __user *buf )
        } else {
                err = restore_i387_soft( &current->thread.i387.soft, buf );
        }
-       current->used_math = 1;
+       set_used_math();
        return err;
 }
 
@@ -510,7 +504,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 ) {
@@ -522,25 +516,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)
@@ -555,7 +535,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)