aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/i387.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r--arch/x86/kernel/i387.c88
1 files changed, 46 insertions, 42 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index d2e39e69aaf8..8f8102d967b3 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -5,45 +5,41 @@
5 * General FPU state handling cleanups 5 * General FPU state handling cleanups
6 * Gareth Hughes <gareth@valinux.com>, May 2000 6 * Gareth Hughes <gareth@valinux.com>, May 2000
7 */ 7 */
8
9#include <linux/sched.h>
10#include <linux/module.h> 8#include <linux/module.h>
11#include <linux/regset.h> 9#include <linux/regset.h>
10#include <linux/sched.h>
11
12#include <asm/sigcontext.h>
12#include <asm/processor.h> 13#include <asm/processor.h>
13#include <asm/i387.h>
14#include <asm/math_emu.h> 14#include <asm/math_emu.h>
15#include <asm/sigcontext.h>
16#include <asm/user.h>
17#include <asm/ptrace.h>
18#include <asm/uaccess.h> 15#include <asm/uaccess.h>
16#include <asm/ptrace.h>
17#include <asm/i387.h>
18#include <asm/user.h>
19 19
20#ifdef CONFIG_X86_64 20#ifdef CONFIG_X86_64
21 21# include <asm/sigcontext32.h>
22#include <asm/sigcontext32.h> 22# include <asm/user32.h>
23#include <asm/user32.h>
24
25#else 23#else
26 24# define save_i387_ia32 save_i387
27#define save_i387_ia32 save_i387 25# define restore_i387_ia32 restore_i387
28#define restore_i387_ia32 restore_i387 26# define _fpstate_ia32 _fpstate
29 27# define user_i387_ia32_struct user_i387_struct
30#define _fpstate_ia32 _fpstate 28# define user32_fxsr_struct user_fxsr_struct
31#define user_i387_ia32_struct user_i387_struct
32#define user32_fxsr_struct user_fxsr_struct
33
34#endif 29#endif
35 30
36#ifdef CONFIG_MATH_EMULATION 31#ifdef CONFIG_MATH_EMULATION
37#define HAVE_HWFP (boot_cpu_data.hard_math) 32# define HAVE_HWFP (boot_cpu_data.hard_math)
38#else 33#else
39#define HAVE_HWFP 1 34# define HAVE_HWFP 1
40#endif 35#endif
41 36
42static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; 37static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
43 38
44void mxcsr_feature_mask_init(void) 39void mxcsr_feature_mask_init(void)
45{ 40{
46 unsigned long mask = 0; 41 unsigned long mask = 0;
42
47 clts(); 43 clts();
48 if (cpu_has_fxsr) { 44 if (cpu_has_fxsr) {
49 memset(&current->thread.i387.fxsave, 0, 45 memset(&current->thread.i387.fxsave, 0,
@@ -69,10 +65,11 @@ void __cpuinit fpu_init(void)
69 65
70 if (offsetof(struct task_struct, thread.i387.fxsave) & 15) 66 if (offsetof(struct task_struct, thread.i387.fxsave) & 15)
71 __bad_fxsave_alignment(); 67 __bad_fxsave_alignment();
68
72 set_in_cr4(X86_CR4_OSFXSR); 69 set_in_cr4(X86_CR4_OSFXSR);
73 set_in_cr4(X86_CR4_OSXMMEXCPT); 70 set_in_cr4(X86_CR4_OSXMMEXCPT);
74 71
75 write_cr0(oldcr0 & ~((1UL<<3)|(1UL<<2))); /* clear TS and EM */ 72 write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
76 73
77 mxcsr_feature_mask_init(); 74 mxcsr_feature_mask_init();
78 /* clean state in init */ 75 /* clean state in init */
@@ -178,6 +175,7 @@ static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
178 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ 175 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
179 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ 176 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
180 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ 177 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
178
181 return tmp; 179 return tmp;
182} 180}
183 181
@@ -232,8 +230,8 @@ static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
232 * FXSR floating point environment conversions. 230 * FXSR floating point environment conversions.
233 */ 231 */
234 232
235static void convert_from_fxsr(struct user_i387_ia32_struct *env, 233static void
236 struct task_struct *tsk) 234convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
237{ 235{
238 struct i387_fxsave_struct *fxsave = &tsk->thread.i387.fxsave; 236 struct i387_fxsave_struct *fxsave = &tsk->thread.i387.fxsave;
239 struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; 237 struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
@@ -252,10 +250,11 @@ static void convert_from_fxsr(struct user_i387_ia32_struct *env,
252 * should be actually ds/cs at fpu exception time, but 250 * should be actually ds/cs at fpu exception time, but
253 * that information is not available in 64bit mode. 251 * that information is not available in 64bit mode.
254 */ 252 */
255 asm("mov %%ds,%0" : "=r" (env->fos)); 253 asm("mov %%ds, %[fos]" : [fos] "=r" (env->fos));
256 asm("mov %%cs,%0" : "=r" (env->fcs)); 254 asm("mov %%cs, %[fcs]" : [fcs] "=r" (env->fcs));
257 } else { 255 } else {
258 struct pt_regs *regs = task_pt_regs(tsk); 256 struct pt_regs *regs = task_pt_regs(tsk);
257
259 env->fos = 0xffff0000 | tsk->thread.ds; 258 env->fos = 0xffff0000 | tsk->thread.ds;
260 env->fcs = regs->cs; 259 env->fcs = regs->cs;
261 } 260 }
@@ -309,9 +308,10 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
309 308
310 init_fpu(target); 309 init_fpu(target);
311 310
312 if (!cpu_has_fxsr) 311 if (!cpu_has_fxsr) {
313 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 312 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
314 &target->thread.i387.fsave, 0, -1); 313 &target->thread.i387.fsave, 0, -1);
314 }
315 315
316 if (kbuf && pos == 0 && count == sizeof(env)) { 316 if (kbuf && pos == 0 && count == sizeof(env)) {
317 convert_from_fxsr(kbuf, target); 317 convert_from_fxsr(kbuf, target);
@@ -319,6 +319,7 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
319 } 319 }
320 320
321 convert_from_fxsr(&env, target); 321 convert_from_fxsr(&env, target);
322
322 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1); 323 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
323} 324}
324 325
@@ -335,9 +336,10 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
335 init_fpu(target); 336 init_fpu(target);
336 set_stopped_child_used_math(target); 337 set_stopped_child_used_math(target);
337 338
338 if (!cpu_has_fxsr) 339 if (!cpu_has_fxsr) {
339 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 340 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
340 &target->thread.i387.fsave, 0, -1); 341 &target->thread.i387.fsave, 0, -1);
342 }
341 343
342 if (pos > 0 || count < sizeof(env)) 344 if (pos > 0 || count < sizeof(env))
343 convert_from_fxsr(&env, target); 345 convert_from_fxsr(&env, target);
@@ -392,28 +394,28 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf)
392{ 394{
393 if (!used_math()) 395 if (!used_math())
394 return 0; 396 return 0;
395 397 /*
396 /* This will cause a "finit" to be triggered by the next 398 * This will cause a "finit" to be triggered by the next
397 * attempted FPU operation by the 'current' process. 399 * attempted FPU operation by the 'current' process.
398 */ 400 */
399 clear_used_math(); 401 clear_used_math();
400 402
401 if (HAVE_HWFP) { 403 if (!HAVE_HWFP) {
402 if (cpu_has_fxsr) {
403 return save_i387_fxsave(buf);
404 } else {
405 return save_i387_fsave(buf);
406 }
407 } else {
408 return fpregs_soft_get(current, NULL, 404 return fpregs_soft_get(current, NULL,
409 0, sizeof(struct user_i387_ia32_struct), 405 0, sizeof(struct user_i387_ia32_struct),
410 NULL, buf) ? -1 : 1; 406 NULL, buf) ? -1 : 1;
411 } 407 }
408
409 if (cpu_has_fxsr)
410 return save_i387_fxsave(buf);
411 else
412 return save_i387_fsave(buf);
412} 413}
413 414
414static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) 415static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
415{ 416{
416 struct task_struct *tsk = current; 417 struct task_struct *tsk = current;
418
417 clear_fpu(tsk); 419 clear_fpu(tsk);
418 return __copy_from_user(&tsk->thread.i387.fsave, buf, 420 return __copy_from_user(&tsk->thread.i387.fsave, buf,
419 sizeof(struct i387_fsave_struct)); 421 sizeof(struct i387_fsave_struct));
@@ -421,9 +423,10 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
421 423
422static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) 424static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
423{ 425{
424 int err;
425 struct task_struct *tsk = current; 426 struct task_struct *tsk = current;
426 struct user_i387_ia32_struct env; 427 struct user_i387_ia32_struct env;
428 int err;
429
427 clear_fpu(tsk); 430 clear_fpu(tsk);
428 err = __copy_from_user(&tsk->thread.i387.fxsave, &buf->_fxsr_env[0], 431 err = __copy_from_user(&tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
429 sizeof(struct i387_fxsave_struct)); 432 sizeof(struct i387_fxsave_struct));
@@ -432,6 +435,7 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
432 if (err || __copy_from_user(&env, buf, sizeof(env))) 435 if (err || __copy_from_user(&env, buf, sizeof(env)))
433 return 1; 436 return 1;
434 convert_to_fxsr(tsk, &env); 437 convert_to_fxsr(tsk, &env);
438
435 return 0; 439 return 0;
436} 440}
437 441
@@ -440,17 +444,17 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
440 int err; 444 int err;
441 445
442 if (HAVE_HWFP) { 446 if (HAVE_HWFP) {
443 if (cpu_has_fxsr) { 447 if (cpu_has_fxsr)
444 err = restore_i387_fxsave(buf); 448 err = restore_i387_fxsave(buf);
445 } else { 449 else
446 err = restore_i387_fsave(buf); 450 err = restore_i387_fsave(buf);
447 }
448 } else { 451 } else {
449 err = fpregs_soft_set(current, NULL, 452 err = fpregs_soft_set(current, NULL,
450 0, sizeof(struct user_i387_ia32_struct), 453 0, sizeof(struct user_i387_ia32_struct),
451 NULL, buf) != 0; 454 NULL, buf) != 0;
452 } 455 }
453 set_used_math(); 456 set_used_math();
457
454 return err; 458 return err;
455} 459}
456 460
@@ -463,8 +467,8 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
463 */ 467 */
464int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu) 468int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu)
465{ 469{
466 int fpvalid;
467 struct task_struct *tsk = current; 470 struct task_struct *tsk = current;
471 int fpvalid;
468 472
469 fpvalid = !!used_math(); 473 fpvalid = !!used_math();
470 if (fpvalid) 474 if (fpvalid)