diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2008-07-29 13:29:25 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-30 13:49:27 -0400 |
commit | c37b5efea43f9e500363f9973dd00e3d2cdcc685 (patch) | |
tree | 9ce635f1672099dafcd78e535b4ea18d80235d8f /arch/x86/kernel/i387.c | |
parent | bdd8caba5ed5bb7ee21c9f061597284ffeb280bf (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.c | 82 |
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 | ||
456 | static 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 | |||
456 | int save_i387_xstate_ia32(void __user *buf) | 475 | int 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 | ||
494 | static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) | 515 | static 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 | ||
533 | static 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 | ¤t->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; | ||
568 | fx_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 | |||
511 | int restore_i387_xstate_ia32(void __user *buf) | 578 | int 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 { |