aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/i387.c
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-07-29 13:29:25 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-30 13:49:27 -0400
commitc37b5efea43f9e500363f9973dd00e3d2cdcc685 (patch)
tree9ce635f1672099dafcd78e535b4ea18d80235d8f /arch/x86/kernel/i387.c
parentbdd8caba5ed5bb7ee21c9f061597284ffeb280bf (diff)
x86, xsave: save/restore the extended state context in sigframe
On cpu's supporting xsave/xrstor, fpstate pointer in the sigcontext, will include the extended state information along with fpstate information. Presence of extended state information is indicated by the presence of FP_XSTATE_MAGIC1 at fpstate.sw_reserved.magic1 and FP_XSTATE_MAGIC2 at fpstate + (fpstate.sw_reserved.extended_size - FP_XSTATE_MAGIC2_SIZE). Extended feature bit mask that is saved in the memory layout is represented by the fpstate.sw_reserved.xstate_bv For RT signal frames, UC_FP_XSTATE in the uc_flags also indicate the presence of extended state information in the sigcontext's fpstate pointer. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r--arch/x86/kernel/i387.c82
1 files changed, 76 insertions, 6 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 7daf3a011dd9..cbb9dc474a21 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -26,6 +26,7 @@
26# define _fpstate_ia32 _fpstate 26# define _fpstate_ia32 _fpstate
27# define _xstate_ia32 _xstate 27# define _xstate_ia32 _xstate
28# define sig_xstate_ia32_size sig_xstate_size 28# define sig_xstate_ia32_size sig_xstate_size
29# define fx_sw_reserved_ia32 fx_sw_reserved
29# define user_i387_ia32_struct user_i387_struct 30# define user_i387_ia32_struct user_i387_struct
30# define user32_fxsr_struct user_fxsr_struct 31# define user32_fxsr_struct user_fxsr_struct
31#endif 32#endif
@@ -447,12 +448,30 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
447 if (err) 448 if (err)
448 return -1; 449 return -1;
449 450
450 if (__copy_to_user(&buf->_fxsr_env[0], fx, 451 if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
451 sizeof(struct i387_fxsave_struct)))
452 return -1; 452 return -1;
453 return 1; 453 return 1;
454} 454}
455 455
456static int save_i387_xsave(void __user *buf)
457{
458 struct _fpstate_ia32 __user *fx = buf;
459 int err = 0;
460
461 if (save_i387_fxsave(fx) < 0)
462 return -1;
463
464 err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
465 sizeof(struct _fpx_sw_bytes));
466 err |= __put_user(FP_XSTATE_MAGIC2,
467 (__u32 __user *) (buf + sig_xstate_ia32_size
468 - FP_XSTATE_MAGIC2_SIZE));
469 if (err)
470 return -1;
471
472 return 1;
473}
474
456int save_i387_xstate_ia32(void __user *buf) 475int save_i387_xstate_ia32(void __user *buf)
457{ 476{
458 struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; 477 struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
@@ -477,6 +496,8 @@ int save_i387_xstate_ia32(void __user *buf)
477 496
478 unlazy_fpu(tsk); 497 unlazy_fpu(tsk);
479 498
499 if (cpu_has_xsave)
500 return save_i387_xsave(fp);
480 if (cpu_has_fxsr) 501 if (cpu_has_fxsr)
481 return save_i387_fxsave(fp); 502 return save_i387_fxsave(fp);
482 else 503 else
@@ -491,14 +512,15 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
491 sizeof(struct i387_fsave_struct)); 512 sizeof(struct i387_fsave_struct));
492} 513}
493 514
494static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) 515static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
516 unsigned int size)
495{ 517{
496 struct task_struct *tsk = current; 518 struct task_struct *tsk = current;
497 struct user_i387_ia32_struct env; 519 struct user_i387_ia32_struct env;
498 int err; 520 int err;
499 521
500 err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], 522 err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
501 sizeof(struct i387_fxsave_struct)); 523 size);
502 /* mxcsr reserved bits must be masked to zero for security reasons */ 524 /* mxcsr reserved bits must be masked to zero for security reasons */
503 tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; 525 tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
504 if (err || __copy_from_user(&env, buf, sizeof(env))) 526 if (err || __copy_from_user(&env, buf, sizeof(env)))
@@ -508,6 +530,51 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
508 return 0; 530 return 0;
509} 531}
510 532
533static int restore_i387_xsave(void __user *buf)
534{
535 struct _fpx_sw_bytes fx_sw_user;
536 struct _fpstate_ia32 __user *fx_user =
537 ((struct _fpstate_ia32 __user *) buf);
538 struct i387_fxsave_struct __user *fx =
539 (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
540 struct xsave_hdr_struct *xsave_hdr =
541 &current->thread.xstate->xsave.xsave_hdr;
542 unsigned int lmask, hmask;
543 int err;
544
545 if (check_for_xstate(fx, buf, &fx_sw_user))
546 goto fx_only;
547
548 lmask = fx_sw_user.xstate_bv;
549 hmask = fx_sw_user.xstate_bv >> 32;
550
551 err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
552
553 xsave_hdr->xstate_bv &= (pcntxt_lmask | (((u64) pcntxt_hmask) << 32));
554 /*
555 * These bits must be zero.
556 */
557 xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
558
559 /*
560 * Init the state that is not present in the memory layout
561 * and enabled by the OS.
562 */
563 lmask = ~(pcntxt_lmask & ~lmask);
564 hmask = ~(pcntxt_hmask & ~hmask);
565 xsave_hdr->xstate_bv &= (lmask | (((u64) hmask) << 32));
566
567 return err;
568fx_only:
569 /*
570 * Couldn't find the extended state information in the memory
571 * layout. Restore the FP/SSE and init the other extended state
572 * enabled by the OS.
573 */
574 xsave_hdr->xstate_bv = XSTATE_FPSSE;
575 return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
576}
577
511int restore_i387_xstate_ia32(void __user *buf) 578int restore_i387_xstate_ia32(void __user *buf)
512{ 579{
513 int err; 580 int err;
@@ -535,8 +602,11 @@ int restore_i387_xstate_ia32(void __user *buf)
535 } 602 }
536 603
537 if (HAVE_HWFP) { 604 if (HAVE_HWFP) {
538 if (cpu_has_fxsr) 605 if (cpu_has_xsave)
539 err = restore_i387_fxsave(fp); 606 err = restore_i387_xsave(buf);
607 else if (cpu_has_fxsr)
608 err = restore_i387_fxsave(fp, sizeof(struct
609 i387_fxsave_struct));
540 else 610 else
541 err = restore_i387_fsave(fp); 611 err = restore_i387_fsave(fp);
542 } else { 612 } else {