* 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>
#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)
{
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);
}
/*
}
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.
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:
}
}
+#if 0
unsigned short get_fpu_twd( struct task_struct *tsk )
{
if ( cpu_has_fxsr ) {
return (unsigned short)tsk->thread.i387.fsave.twd;
}
}
+#endif /* 0 */
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 ) {
}
}
+#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);
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;
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 )
{
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];
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 ) {
} else {
err = restore_i387_soft( ¤t->thread.i387.soft, buf );
}
- current->used_math = 1;
+ set_used_math();
return err;
}
* 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;
}
/*
int fpvalid;
struct task_struct *tsk = current;
- fpvalid = tsk->used_math;
+ fpvalid = !!used_math();
if ( fpvalid ) {
unlazy_fpu( tsk );
if ( cpu_has_fxsr ) {
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)
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)