Commit 681b6bf7 authored by Nitin A. Kamble's avatar Nitin A. Kamble Committed by Linus Torvalds

[PATCH] mxcsr patch for i386 & x86-64

This enables proper mxcsr register masking: the magic mask "0xffbf"
is not necessarily correct for all CPU's, and there is an architected
way to discover the proper MXCSR feature bits by examining the fxsave
results.

Please refer to IA32 Software Developer's Manual, Volume 1, Section
11.6.6 for more details.
parent 91ddedbe
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/i387.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
...@@ -536,5 +537,5 @@ void __init cpu_init (void) ...@@ -536,5 +537,5 @@ void __init cpu_init (void)
*/ */
current_thread_info()->status = 0; current_thread_info()->status = 0;
current->used_math = 0; current->used_math = 0;
stts(); mxcsr_feature_mask_init();
} }
...@@ -24,6 +24,22 @@ ...@@ -24,6 +24,22 @@
#define HAVE_HWFP 1 #define HAVE_HWFP 1
#endif #endif
unsigned long mxcsr_feature_mask = 0xffffffff;
void mxcsr_feature_mask_init(void)
{
unsigned long mask = 0;
clts();
if (cpu_has_fxsr) {
memset(&current->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
asm volatile("fxsave %0" : : "m" (current->thread.i387.fxsave));
mask = current->thread.i387.fxsave.mxcsr_mask;
if (mask == 0) mask = 0x0000ffbf;
}
mxcsr_feature_mask &= mask;
stts();
}
/* /*
* The _current_ task is using the FPU for the first time * The _current_ task is using the FPU for the first time
* so initialize it and set the mxcsr to its default * so initialize it and set the mxcsr to its default
...@@ -204,13 +220,6 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd ) ...@@ -204,13 +220,6 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd )
} }
} }
void set_fpu_mxcsr( struct task_struct *tsk, unsigned short mxcsr )
{
if ( cpu_has_xmm ) {
tsk->thread.i387.fxsave.mxcsr = (mxcsr & 0xffbf);
}
}
/* /*
* FXSR floating point environment conversions. * FXSR floating point environment conversions.
*/ */
...@@ -355,8 +364,8 @@ static int restore_i387_fxsave( struct _fpstate __user *buf ) ...@@ -355,8 +364,8 @@ static int restore_i387_fxsave( struct _fpstate __user *buf )
clear_fpu( tsk ); clear_fpu( tsk );
err = __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0], err = __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
sizeof(struct i387_fxsave_struct) ); sizeof(struct i387_fxsave_struct) );
/* mxcsr bit 6 and 31-16 must be zero for security reasons */ /* mxcsr reserved bits must be masked to zero for security reasons */
tsk->thread.i387.fxsave.mxcsr &= 0xffbf; tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf ); return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
} }
...@@ -457,8 +466,8 @@ int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct __user *buf ) ...@@ -457,8 +466,8 @@ int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct __user *buf )
if (__copy_from_user( &tsk->thread.i387.fxsave, buf, if (__copy_from_user( &tsk->thread.i387.fxsave, buf,
sizeof(struct user_fxsr_struct) )) sizeof(struct user_fxsr_struct) ))
ret = -EFAULT; ret = -EFAULT;
/* mxcsr bit 6 and 31-16 must be zero for security reasons */ /* mxcsr reserved bits must be masked to zero for security reasons */
tsk->thread.i387.fxsave.mxcsr &= 0xffbf; tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
} else { } else {
ret = -EIO; ret = -EIO;
} }
......
...@@ -72,6 +72,7 @@ do_fpu_end(void) ...@@ -72,6 +72,7 @@ do_fpu_end(void)
/* restore FPU regs if necessary */ /* restore FPU regs if necessary */
/* Do it out of line so that gcc does not move cr0 load to some stupid place */ /* Do it out of line so that gcc does not move cr0 load to some stupid place */
kernel_fpu_end(); kernel_fpu_end();
mxcsr_feature_mask_init();
} }
void restore_processor_state(void) void restore_processor_state(void)
......
...@@ -155,7 +155,7 @@ int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fs ...@@ -155,7 +155,7 @@ int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fs
&buf->_fxsr_env[0], &buf->_fxsr_env[0],
sizeof(struct i387_fxsave_struct))) sizeof(struct i387_fxsave_struct)))
return -1; return -1;
tsk->thread.i387.fxsave.mxcsr &= 0xffbf; tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
tsk->used_math = 1; tsk->used_math = 1;
} }
return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf); return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
......
...@@ -357,10 +357,10 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) ...@@ -357,10 +357,10 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
/* no checking to be bug-to-bug compatible with i386 */ /* no checking to be bug-to-bug compatible with i386 */
__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)); __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
child->used_math = 1; child->used_math = 1;
child->thread.i387.fxsave.mxcsr &= 0xffbf; child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
ret = 0; ret = 0;
break; break;
} }
default: default:
ret = -EINVAL; ret = -EINVAL;
......
...@@ -24,6 +24,20 @@ ...@@ -24,6 +24,20 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
unsigned int mxcsr_feature_mask = 0xffffffff;
void mxcsr_feature_mask_init(void)
{
unsigned int mask;
clts();
memset(&current->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
asm volatile("fxsave %0" : : "m" (current->thread.i387.fxsave));
mask = current->thread.i387.fxsave.mxcsr_mask;
if (mask == 0) mask = 0x0000ffbf;
mxcsr_feature_mask &= mask;
stts();
}
/* /*
* Called at bootup to set up the initial FPU state that is later cloned * Called at bootup to set up the initial FPU state that is later cloned
* into all processes. * into all processes.
...@@ -40,8 +54,8 @@ void __init fpu_init(void) ...@@ -40,8 +54,8 @@ void __init fpu_init(void)
write_cr0(oldcr0 & ~((1UL<<3)|(1UL<<2))); /* clear TS and EM */ write_cr0(oldcr0 & ~((1UL<<3)|(1UL<<2))); /* clear TS and EM */
mxcsr_feature_mask_init();
/* clean state in init */ /* clean state in init */
stts();
current_thread_info()->status = 0; current_thread_info()->status = 0;
current->used_math = 0; current->used_math = 0;
} }
......
...@@ -77,6 +77,7 @@ do_fpu_end(void) ...@@ -77,6 +77,7 @@ do_fpu_end(void)
/* restore FPU regs if necessary */ /* restore FPU regs if necessary */
/* Do it out of line so that gcc does not move cr0 load to some stupid place */ /* Do it out of line so that gcc does not move cr0 load to some stupid place */
kernel_fpu_end(); kernel_fpu_end();
mxcsr_feature_mask_init();
} }
void restore_processor_state(void) void restore_processor_state(void)
......
...@@ -12,10 +12,13 @@ ...@@ -12,10 +12,13 @@
#define __ASM_I386_I387_H #define __ASM_I386_I387_H
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/sigcontext.h> #include <asm/sigcontext.h>
#include <asm/user.h> #include <asm/user.h>
extern unsigned long mxcsr_feature_mask;
extern void mxcsr_feature_mask_init(void);
extern void init_fpu(struct task_struct *); extern void init_fpu(struct task_struct *);
/* /*
* FPU lazy state save handling... * FPU lazy state save handling...
...@@ -89,12 +92,6 @@ extern unsigned short get_fpu_mxcsr( struct task_struct *tsk ); ...@@ -89,12 +92,6 @@ extern unsigned short get_fpu_mxcsr( struct task_struct *tsk );
extern void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd ); extern void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd );
extern void set_fpu_swd( struct task_struct *tsk, unsigned short swd ); extern void set_fpu_swd( struct task_struct *tsk, unsigned short swd );
extern void set_fpu_twd( struct task_struct *tsk, unsigned short twd ); extern void set_fpu_twd( struct task_struct *tsk, unsigned short twd );
extern void set_fpu_mxcsr( struct task_struct *tsk, unsigned short mxcsr );
#define load_mxcsr( val ) do { \
unsigned long __mxcsr = ((unsigned long)(val) & 0xffbf); \
asm volatile( "ldmxcsr %0" : : "m" (__mxcsr) ); \
} while (0)
/* /*
* Signal frame handlers... * Signal frame handlers...
......
...@@ -332,7 +332,7 @@ struct i387_fxsave_struct { ...@@ -332,7 +332,7 @@ struct i387_fxsave_struct {
long foo; long foo;
long fos; long fos;
long mxcsr; long mxcsr;
long reserved; long mxcsr_mask;
long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
long padding[56]; long padding[56];
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
extern void fpu_init(void); extern void fpu_init(void);
extern unsigned int mxcsr_feature_mask;
extern void mxcsr_feature_mask_init(void);
extern void init_fpu(struct task_struct *child); extern void init_fpu(struct task_struct *child);
extern int save_i387(struct _fpstate *buf); extern int save_i387(struct _fpstate *buf);
...@@ -52,11 +54,6 @@ static inline int need_signal_i387(struct task_struct *me) ...@@ -52,11 +54,6 @@ static inline int need_signal_i387(struct task_struct *me)
} \ } \
} while (0) } while (0)
#define load_mxcsr(val) do { \
unsigned long __mxcsr = ((unsigned long)(val) & 0xffbf); \
asm volatile("ldmxcsr %0" : : "m" (__mxcsr)); \
} while (0)
/* /*
* ptrace request handers... * ptrace request handers...
*/ */
...@@ -75,7 +72,6 @@ extern int set_fpregs(struct task_struct *tsk, ...@@ -75,7 +72,6 @@ extern int set_fpregs(struct task_struct *tsk,
#define set_fpu_cwd(t,val) ((t)->thread.i387.fxsave.cwd = (val)) #define set_fpu_cwd(t,val) ((t)->thread.i387.fxsave.cwd = (val))
#define set_fpu_swd(t,val) ((t)->thread.i387.fxsave.swd = (val)) #define set_fpu_swd(t,val) ((t)->thread.i387.fxsave.swd = (val))
#define set_fpu_fxsr_twd(t,val) ((t)->thread.i387.fxsave.twd = (val)) #define set_fpu_fxsr_twd(t,val) ((t)->thread.i387.fxsave.twd = (val))
#define set_fpu_mxcsr(t,val) ((t)->thread.i387.fxsave.mxcsr = (val)&0xffbf)
static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment