aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2012-07-24 19:05:29 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2012-09-18 18:51:48 -0400
commit72a671ced66db6d1c2bfff1c930a101ac8d08204 (patch)
treefb3f58fa735d2d3cffc636e3e0f8114a04b04623
parent0ca5bd0d886578ad0afeceaa83458c0f35cb3c6b (diff)
x86, fpu: Unify signal handling code paths for x86 and x86_64 kernels
Currently for x86 and x86_32 binaries, fpstate in the user sigframe is copied to/from the fpstate in the task struct. And in the case of signal delivery for x86_64 binaries, if the fpstate is live in the CPU registers, then the live state is copied directly to the user sigframe. Otherwise fpstate in the task struct is copied to the user sigframe. During restore, fpstate in the user sigframe is restored directly to the live CPU registers. Historically, different code paths led to different bugs. For example, x86_64 code path was not preemption safe till recently. Also there is lot of code duplication for support of new features like xsave etc. Unify signal handling code paths for x86 and x86_64 kernels. New strategy is as follows: Signal delivery: Both for 32/64-bit frames, align the core math frame area to 64bytes as needed by xsave (this where the main fpu/extended state gets copied to and excludes the legacy compatibility fsave header for the 32-bit [f]xsave frames). If the state is live, copy the register state directly to the user frame. If not live, copy the state in the thread struct to the user frame. And for 32-bit [f]xsave frames, construct the fsave header separately before the actual [f]xsave area. Signal return: As the 32-bit frames with [f]xstate has an additional 'fsave' header, copy everything back from the user sigframe to the fpstate in the task structure and reconstruct the fxstate from the 'fsave' header (Also user passed pointers may not be correctly aligned for any attempt to directly restore any partial state). At the next fpstate usage, everything will be restored to the live CPU registers. For all the 64-bit frames and the 32-bit fsave frame, restore the state from the user sigframe directly to the live CPU registers. 64-bit signals always restored the math frame directly, so we can expect the math frame pointer to be correctly aligned. For 32-bit fsave frames, there are no alignment requirements, so we can restore the state directly. "lat_sig catch" microbenchmark numbers (for x86, x86_64, x86_32 binaries) are with in the noise range with this change. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Link: http://lkml.kernel.org/r/1343171129-2747-4-git-send-email-suresh.b.siddha@intel.com [ Merged in compilation fix ] Link: http://lkml.kernel.org/r/1344544736.8326.17.camel@sbsiddha-desk.sc.intel.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/x86/ia32/ia32_signal.c9
-rw-r--r--arch/x86/include/asm/fpu-internal.h111
-rw-r--r--arch/x86/include/asm/xsave.h6
-rw-r--r--arch/x86/kernel/i387.c246
-rw-r--r--arch/x86/kernel/process.c10
-rw-r--r--arch/x86/kernel/ptrace.c3
-rw-r--r--arch/x86/kernel/signal.c15
-rw-r--r--arch/x86/kernel/xsave.c432
8 files changed, 348 insertions, 484 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 452d4dd0a95..8c77c64fbd2 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -251,7 +251,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
251 251
252 get_user_ex(tmp, &sc->fpstate); 252 get_user_ex(tmp, &sc->fpstate);
253 buf = compat_ptr(tmp); 253 buf = compat_ptr(tmp);
254 err |= restore_i387_xstate_ia32(buf); 254 err |= restore_xstate_sig(buf, 1);
255 255
256 get_user_ex(*pax, &sc->ax); 256 get_user_ex(*pax, &sc->ax);
257 } get_user_catch(err); 257 } get_user_catch(err);
@@ -382,9 +382,12 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
382 sp = (unsigned long) ka->sa.sa_restorer; 382 sp = (unsigned long) ka->sa.sa_restorer;
383 383
384 if (used_math()) { 384 if (used_math()) {
385 sp = sp - sig_xstate_ia32_size; 385 unsigned long fx_aligned, math_size;
386
387 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
386 *fpstate = (struct _fpstate_ia32 __user *) sp; 388 *fpstate = (struct _fpstate_ia32 __user *) sp;
387 if (save_i387_xstate_ia32(*fpstate) < 0) 389 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
390 math_size) < 0)
388 return (void __user *) -1L; 391 return (void __user *) -1L;
389 } 392 }
390 393
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 016acb30fa4..4fbb4195bc6 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -22,11 +22,30 @@
22#include <asm/uaccess.h> 22#include <asm/uaccess.h>
23#include <asm/xsave.h> 23#include <asm/xsave.h>
24 24
25extern unsigned int sig_xstate_size; 25#ifdef CONFIG_X86_64
26# include <asm/sigcontext32.h>
27# include <asm/user32.h>
28int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
29 compat_sigset_t *set, struct pt_regs *regs);
30int ia32_setup_frame(int sig, struct k_sigaction *ka,
31 compat_sigset_t *set, struct pt_regs *regs);
32#else
33# define user_i387_ia32_struct user_i387_struct
34# define user32_fxsr_struct user_fxsr_struct
35# define ia32_setup_frame __setup_frame
36# define ia32_setup_rt_frame __setup_rt_frame
37#endif
38
39extern unsigned int mxcsr_feature_mask;
26extern void fpu_init(void); 40extern void fpu_init(void);
27 41
28DECLARE_PER_CPU(struct task_struct *, fpu_owner_task); 42DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
29 43
44extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
45 struct task_struct *tsk);
46extern void convert_to_fxsr(struct task_struct *tsk,
47 const struct user_i387_ia32_struct *env);
48
30extern user_regset_active_fn fpregs_active, xfpregs_active; 49extern user_regset_active_fn fpregs_active, xfpregs_active;
31extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, 50extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
32 xstateregs_get; 51 xstateregs_get;
@@ -39,19 +58,11 @@ extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
39 */ 58 */
40#define xstateregs_active fpregs_active 59#define xstateregs_active fpregs_active
41 60
42extern struct _fpx_sw_bytes fx_sw_reserved;
43#ifdef CONFIG_IA32_EMULATION
44extern unsigned int sig_xstate_ia32_size;
45extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
46struct _fpstate_ia32;
47struct _xstate_ia32;
48extern int save_i387_xstate_ia32(void __user *buf);
49extern int restore_i387_xstate_ia32(void __user *buf);
50#endif
51
52#ifdef CONFIG_MATH_EMULATION 61#ifdef CONFIG_MATH_EMULATION
62# define HAVE_HWFP (boot_cpu_data.hard_math)
53extern void finit_soft_fpu(struct i387_soft_struct *soft); 63extern void finit_soft_fpu(struct i387_soft_struct *soft);
54#else 64#else
65# define HAVE_HWFP 1
55static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} 66static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
56#endif 67#endif
57 68
@@ -119,17 +130,6 @@ static inline int fsave_user(struct i387_fsave_struct __user *fx)
119 130
120static inline int fxsave_user(struct i387_fxsave_struct __user *fx) 131static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
121{ 132{
122 int err;
123
124 /*
125 * Clear the bytes not touched by the fxsave and reserved
126 * for the SW usage.
127 */
128 err = __clear_user(&fx->sw_reserved,
129 sizeof(struct _fpx_sw_bytes));
130 if (unlikely(err))
131 return -EFAULT;
132
133 if (config_enabled(CONFIG_X86_32)) 133 if (config_enabled(CONFIG_X86_32))
134 return check_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx)); 134 return check_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
135 else if (config_enabled(CONFIG_AS_FXSAVEQ)) 135 else if (config_enabled(CONFIG_AS_FXSAVEQ))
@@ -189,19 +189,6 @@ static inline void fpu_fxsave(struct fpu *fpu)
189 : [fx] "R" (&fpu->state->fxsave)); 189 : [fx] "R" (&fpu->state->fxsave));
190 } 190 }
191} 191}
192#ifdef CONFIG_X86_64
193
194int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
195 compat_sigset_t *set, struct pt_regs *regs);
196int ia32_setup_frame(int sig, struct k_sigaction *ka,
197 compat_sigset_t *set, struct pt_regs *regs);
198
199#else /* CONFIG_X86_32 */
200
201#define ia32_setup_frame __setup_frame
202#define ia32_setup_rt_frame __setup_rt_frame
203
204#endif /* CONFIG_X86_64 */
205 192
206/* 193/*
207 * These must be called with preempt disabled. Returns 194 * These must be called with preempt disabled. Returns
@@ -392,10 +379,28 @@ static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
392/* 379/*
393 * Signal frame handlers... 380 * Signal frame handlers...
394 */ 381 */
395extern int save_i387_xstate(void __user *buf); 382extern int save_xstate_sig(void __user *buf, void __user *fx, int size);
396extern int restore_i387_xstate(void __user *buf); 383extern int __restore_xstate_sig(void __user *buf, void __user *fx, int size);
384
385static inline int xstate_sigframe_size(void)
386{
387 return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size;
388}
389
390static inline int restore_xstate_sig(void __user *buf, int ia32_frame)
391{
392 void __user *buf_fx = buf;
393 int size = xstate_sigframe_size();
394
395 if (ia32_frame && use_fxsr()) {
396 buf_fx = buf + sizeof(struct i387_fsave_struct);
397 size += sizeof(struct i387_fsave_struct);
398 }
399
400 return __restore_xstate_sig(buf, buf_fx, size);
401}
397 402
398static inline void __clear_fpu(struct task_struct *tsk) 403static inline void __drop_fpu(struct task_struct *tsk)
399{ 404{
400 if (__thread_has_fpu(tsk)) { 405 if (__thread_has_fpu(tsk)) {
401 /* Ignore delayed exceptions from user space */ 406 /* Ignore delayed exceptions from user space */
@@ -443,11 +448,21 @@ static inline void save_init_fpu(struct task_struct *tsk)
443 preempt_enable(); 448 preempt_enable();
444} 449}
445 450
446static inline void clear_fpu(struct task_struct *tsk) 451static inline void stop_fpu_preload(struct task_struct *tsk)
447{ 452{
453 tsk->fpu_counter = 0;
454}
455
456static inline void drop_fpu(struct task_struct *tsk)
457{
458 /*
459 * Forget coprocessor state..
460 */
461 stop_fpu_preload(tsk);
448 preempt_disable(); 462 preempt_disable();
449 __clear_fpu(tsk); 463 __drop_fpu(tsk);
450 preempt_enable(); 464 preempt_enable();
465 clear_used_math();
451} 466}
452 467
453/* 468/*
@@ -511,4 +526,20 @@ static inline void fpu_copy(struct fpu *dst, struct fpu *src)
511 526
512extern void fpu_finit(struct fpu *fpu); 527extern void fpu_finit(struct fpu *fpu);
513 528
529static inline unsigned long
530alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx,
531 unsigned long *size)
532{
533 unsigned long frame_size = xstate_sigframe_size();
534
535 *buf_fx = sp = round_down(sp - frame_size, 64);
536 if (ia32_frame && use_fxsr()) {
537 frame_size += sizeof(struct i387_fsave_struct);
538 sp -= sizeof(struct i387_fsave_struct);
539 }
540
541 *size = frame_size;
542 return sp;
543}
544
514#endif 545#endif
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index aaac810e861..c1d989a1519 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -38,9 +38,6 @@ extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
38extern void xsave_init(void); 38extern void xsave_init(void);
39extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); 39extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
40extern int init_fpu(struct task_struct *child); 40extern int init_fpu(struct task_struct *child);
41extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
42 void __user *fpstate,
43 struct _fpx_sw_bytes *sw);
44 41
45static inline int fpu_xrstor_checking(struct xsave_struct *fx) 42static inline int fpu_xrstor_checking(struct xsave_struct *fx)
46{ 43{
@@ -68,8 +65,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)
68 * Clear the xsave header first, so that reserved fields are 65 * Clear the xsave header first, so that reserved fields are
69 * initialized to zero. 66 * initialized to zero.
70 */ 67 */
71 err = __clear_user(&buf->xsave_hdr, 68 err = __clear_user(&buf->xsave_hdr, sizeof(buf->xsave_hdr));
72 sizeof(struct xsave_hdr_struct));
73 if (unlikely(err)) 69 if (unlikely(err))
74 return -EFAULT; 70 return -EFAULT;
75 71
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index f250431fb50..ab6a2e8028a 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -19,20 +19,6 @@
19#include <asm/fpu-internal.h> 19#include <asm/fpu-internal.h>
20#include <asm/user.h> 20#include <asm/user.h>
21 21
22#ifdef CONFIG_X86_64
23# include <asm/sigcontext32.h>
24# include <asm/user32.h>
25#else
26# define save_i387_xstate_ia32 save_i387_xstate
27# define restore_i387_xstate_ia32 restore_i387_xstate
28# define _fpstate_ia32 _fpstate
29# define _xstate_ia32 _xstate
30# define sig_xstate_ia32_size sig_xstate_size
31# define fx_sw_reserved_ia32 fx_sw_reserved
32# define user_i387_ia32_struct user_i387_struct
33# define user32_fxsr_struct user_fxsr_struct
34#endif
35
36/* 22/*
37 * Were we in an interrupt that interrupted kernel mode? 23 * Were we in an interrupt that interrupted kernel mode?
38 * 24 *
@@ -113,16 +99,9 @@ void unlazy_fpu(struct task_struct *tsk)
113} 99}
114EXPORT_SYMBOL(unlazy_fpu); 100EXPORT_SYMBOL(unlazy_fpu);
115 101
116#ifdef CONFIG_MATH_EMULATION 102unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
117# define HAVE_HWFP (boot_cpu_data.hard_math)
118#else
119# define HAVE_HWFP 1
120#endif
121
122static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
123unsigned int xstate_size; 103unsigned int xstate_size;
124EXPORT_SYMBOL_GPL(xstate_size); 104EXPORT_SYMBOL_GPL(xstate_size);
125unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
126static struct i387_fxsave_struct fx_scratch __cpuinitdata; 105static struct i387_fxsave_struct fx_scratch __cpuinitdata;
127 106
128static void __cpuinit mxcsr_feature_mask_init(void) 107static void __cpuinit mxcsr_feature_mask_init(void)
@@ -454,7 +433,7 @@ static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
454 * FXSR floating point environment conversions. 433 * FXSR floating point environment conversions.
455 */ 434 */
456 435
457static void 436void
458convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) 437convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
459{ 438{
460 struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave; 439 struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
@@ -491,8 +470,8 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
491 memcpy(&to[i], &from[i], sizeof(to[0])); 470 memcpy(&to[i], &from[i], sizeof(to[0]));
492} 471}
493 472
494static void convert_to_fxsr(struct task_struct *tsk, 473void convert_to_fxsr(struct task_struct *tsk,
495 const struct user_i387_ia32_struct *env) 474 const struct user_i387_ia32_struct *env)
496 475
497{ 476{
498 struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave; 477 struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
@@ -589,223 +568,6 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
589} 568}
590 569
591/* 570/*
592 * Signal frame handlers.
593 */
594
595static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
596{
597 struct task_struct *tsk = current;
598 struct i387_fsave_struct *fp = &tsk->thread.fpu.state->fsave;
599
600 fp->status = fp->swd;
601 if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
602 return -1;
603 return 1;
604}
605
606static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
607{
608 struct task_struct *tsk = current;
609 struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
610 struct user_i387_ia32_struct env;
611 int err = 0;
612
613 convert_from_fxsr(&env, tsk);
614 if (__copy_to_user(buf, &env, sizeof(env)))
615 return -1;
616
617 err |= __put_user(fx->swd, &buf->status);
618 err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
619 if (err)
620 return -1;
621
622 if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
623 return -1;
624 return 1;
625}
626
627static int save_i387_xsave(void __user *buf)
628{
629 struct task_struct *tsk = current;
630 struct _fpstate_ia32 __user *fx = buf;
631 int err = 0;
632
633
634 sanitize_i387_state(tsk);
635
636 /*
637 * For legacy compatible, we always set FP/SSE bits in the bit
638 * vector while saving the state to the user context.
639 * This will enable us capturing any changes(during sigreturn) to
640 * the FP/SSE bits by the legacy applications which don't touch
641 * xstate_bv in the xsave header.
642 *
643 * xsave aware applications can change the xstate_bv in the xsave
644 * header as well as change any contents in the memory layout.
645 * xrestore as part of sigreturn will capture all the changes.
646 */
647 tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
648
649 if (save_i387_fxsave(fx) < 0)
650 return -1;
651
652 err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
653 sizeof(struct _fpx_sw_bytes));
654 err |= __put_user(FP_XSTATE_MAGIC2,
655 (__u32 __user *) (buf + sig_xstate_ia32_size
656 - FP_XSTATE_MAGIC2_SIZE));
657 if (err)
658 return -1;
659
660 return 1;
661}
662
663int save_i387_xstate_ia32(void __user *buf)
664{
665 struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
666 struct task_struct *tsk = current;
667
668 if (!used_math())
669 return 0;
670
671 if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
672 return -EACCES;
673 /*
674 * This will cause a "finit" to be triggered by the next
675 * attempted FPU operation by the 'current' process.
676 */
677 clear_used_math();
678
679 if (!HAVE_HWFP) {
680 return fpregs_soft_get(current, NULL,
681 0, sizeof(struct user_i387_ia32_struct),
682 NULL, fp) ? -1 : 1;
683 }
684
685 unlazy_fpu(tsk);
686
687 if (cpu_has_xsave)
688 return save_i387_xsave(fp);
689 if (cpu_has_fxsr)
690 return save_i387_fxsave(fp);
691 else
692 return save_i387_fsave(fp);
693}
694
695static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
696{
697 struct task_struct *tsk = current;
698
699 return __copy_from_user(&tsk->thread.fpu.state->fsave, buf,
700 sizeof(struct i387_fsave_struct));
701}
702
703static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
704 unsigned int size)
705{
706 struct task_struct *tsk = current;
707 struct user_i387_ia32_struct env;
708 int err;
709
710 err = __copy_from_user(&tsk->thread.fpu.state->fxsave, &buf->_fxsr_env[0],
711 size);
712 /* mxcsr reserved bits must be masked to zero for security reasons */
713 tsk->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
714 if (err || __copy_from_user(&env, buf, sizeof(env)))
715 return 1;
716 convert_to_fxsr(tsk, &env);
717
718 return 0;
719}
720
721static int restore_i387_xsave(void __user *buf)
722{
723 struct _fpx_sw_bytes fx_sw_user;
724 struct _fpstate_ia32 __user *fx_user =
725 ((struct _fpstate_ia32 __user *) buf);
726 struct i387_fxsave_struct __user *fx =
727 (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
728 struct xsave_hdr_struct *xsave_hdr =
729 &current->thread.fpu.state->xsave.xsave_hdr;
730 u64 mask;
731 int err;
732
733 if (check_for_xstate(fx, buf, &fx_sw_user))
734 goto fx_only;
735
736 mask = fx_sw_user.xstate_bv;
737
738 err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
739
740 xsave_hdr->xstate_bv &= pcntxt_mask;
741 /*
742 * These bits must be zero.
743 */
744 xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
745
746 /*
747 * Init the state that is not present in the memory layout
748 * and enabled by the OS.
749 */
750 mask = ~(pcntxt_mask & ~mask);
751 xsave_hdr->xstate_bv &= mask;
752
753 return err;
754fx_only:
755 /*
756 * Couldn't find the extended state information in the memory
757 * layout. Restore the FP/SSE and init the other extended state
758 * enabled by the OS.
759 */
760 xsave_hdr->xstate_bv = XSTATE_FPSSE;
761 return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
762}
763
764int restore_i387_xstate_ia32(void __user *buf)
765{
766 int err;
767 struct task_struct *tsk = current;
768 struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
769
770 if (HAVE_HWFP)
771 clear_fpu(tsk);
772
773 if (!buf) {
774 if (used_math()) {
775 clear_fpu(tsk);
776 clear_used_math();
777 }
778
779 return 0;
780 } else
781 if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
782 return -EACCES;
783
784 if (!used_math()) {
785 err = init_fpu(tsk);
786 if (err)
787 return err;
788 }
789
790 if (HAVE_HWFP) {
791 if (cpu_has_xsave)
792 err = restore_i387_xsave(buf);
793 else if (cpu_has_fxsr)
794 err = restore_i387_fxsave(fp, sizeof(struct
795 i387_fxsave_struct));
796 else
797 err = restore_i387_fsave(fp);
798 } else {
799 err = fpregs_soft_set(current, NULL,
800 0, sizeof(struct user_i387_ia32_struct),
801 NULL, fp) != 0;
802 }
803 set_used_math();
804
805 return err;
806}
807
808/*
809 * FPU state for core dumps. 571 * FPU state for core dumps.
810 * This is only used for a.out dumps now. 572 * This is only used for a.out dumps now.
811 * It is declared generically using elf_fpregset_t (which is 573 * It is declared generically using elf_fpregset_t (which is
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index ef6a8456f71..30069d1a6a4 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -97,16 +97,6 @@ void arch_task_cache_init(void)
97 SLAB_PANIC | SLAB_NOTRACK, NULL); 97 SLAB_PANIC | SLAB_NOTRACK, NULL);
98} 98}
99 99
100static inline void drop_fpu(struct task_struct *tsk)
101{
102 /*
103 * Forget coprocessor state..
104 */
105 tsk->fpu_counter = 0;
106 clear_fpu(tsk);
107 clear_used_math();
108}
109
110/* 100/*
111 * Free current thread data structures etc.. 101 * Free current thread data structures etc..
112 */ 102 */
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index c4c6a5c2bf0..861a9d1a463 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1332,9 +1332,6 @@ static const struct user_regset_view user_x86_64_view = {
1332#define genregs32_get genregs_get 1332#define genregs32_get genregs_get
1333#define genregs32_set genregs_set 1333#define genregs32_set genregs_set
1334 1334
1335#define user_i387_ia32_struct user_i387_struct
1336#define user32_fxsr_struct user_fxsr_struct
1337
1338#endif /* CONFIG_X86_64 */ 1335#endif /* CONFIG_X86_64 */
1339 1336
1340#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 1337#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index bed431a3816..e10f96a7e04 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -114,7 +114,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
114 regs->orig_ax = -1; /* disable syscall checks */ 114 regs->orig_ax = -1; /* disable syscall checks */
115 115
116 get_user_ex(buf, &sc->fpstate); 116 get_user_ex(buf, &sc->fpstate);
117 err |= restore_i387_xstate(buf); 117 err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
118 118
119 get_user_ex(*pax, &sc->ax); 119 get_user_ex(*pax, &sc->ax);
120 } get_user_catch(err); 120 } get_user_catch(err);
@@ -206,7 +206,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
206 void __user **fpstate) 206 void __user **fpstate)
207{ 207{
208 /* Default to using normal stack */ 208 /* Default to using normal stack */
209 unsigned long math_size = 0;
209 unsigned long sp = regs->sp; 210 unsigned long sp = regs->sp;
211 unsigned long buf_fx = 0;
210 int onsigstack = on_sig_stack(sp); 212 int onsigstack = on_sig_stack(sp);
211 213
212 /* redzone */ 214 /* redzone */
@@ -228,10 +230,8 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
228 } 230 }
229 231
230 if (used_math()) { 232 if (used_math()) {
231 sp -= sig_xstate_size; 233 sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
232#ifdef CONFIG_X86_64 234 &buf_fx, &math_size);
233 sp = round_down(sp, 64);
234#endif /* CONFIG_X86_64 */
235 *fpstate = (void __user *)sp; 235 *fpstate = (void __user *)sp;
236 } 236 }
237 237
@@ -244,8 +244,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
244 if (onsigstack && !likely(on_sig_stack(sp))) 244 if (onsigstack && !likely(on_sig_stack(sp)))
245 return (void __user *)-1L; 245 return (void __user *)-1L;
246 246
247 /* save i387 state */ 247 /* save i387 and extended state */
248 if (used_math() && save_i387_xstate(*fpstate) < 0) 248 if (used_math() &&
249 save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0)
249 return (void __user *)-1L; 250 return (void __user *)-1L;
250 251
251 return (void __user *)sp; 252 return (void __user *)sp;
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 7a3d4df9eaf..0923d27f23d 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -10,9 +10,7 @@
10#include <linux/compat.h> 10#include <linux/compat.h>
11#include <asm/i387.h> 11#include <asm/i387.h>
12#include <asm/fpu-internal.h> 12#include <asm/fpu-internal.h>
13#ifdef CONFIG_IA32_EMULATION 13#include <asm/sigframe.h>
14#include <asm/sigcontext32.h>
15#endif
16#include <asm/xcr.h> 14#include <asm/xcr.h>
17 15
18/* 16/*
@@ -25,11 +23,7 @@ u64 pcntxt_mask;
25 */ 23 */
26static struct xsave_struct *init_xstate_buf; 24static struct xsave_struct *init_xstate_buf;
27 25
28struct _fpx_sw_bytes fx_sw_reserved; 26static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
29#ifdef CONFIG_IA32_EMULATION
30struct _fpx_sw_bytes fx_sw_reserved_ia32;
31#endif
32
33static unsigned int *xstate_offsets, *xstate_sizes, xstate_features; 27static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
34 28
35/* 29/*
@@ -44,9 +38,9 @@ static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
44 */ 38 */
45void __sanitize_i387_state(struct task_struct *tsk) 39void __sanitize_i387_state(struct task_struct *tsk)
46{ 40{
47 u64 xstate_bv;
48 int feature_bit = 0x2;
49 struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave; 41 struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
42 int feature_bit = 0x2;
43 u64 xstate_bv;
50 44
51 if (!fx) 45 if (!fx)
52 return; 46 return;
@@ -104,215 +98,314 @@ void __sanitize_i387_state(struct task_struct *tsk)
104 * Check for the presence of extended state information in the 98 * Check for the presence of extended state information in the
105 * user fpstate pointer in the sigcontext. 99 * user fpstate pointer in the sigcontext.
106 */ 100 */
107int check_for_xstate(struct i387_fxsave_struct __user *buf, 101static inline int check_for_xstate(struct i387_fxsave_struct __user *buf,
108 void __user *fpstate, 102 void __user *fpstate,
109 struct _fpx_sw_bytes *fx_sw_user) 103 struct _fpx_sw_bytes *fx_sw)
110{ 104{
111 int min_xstate_size = sizeof(struct i387_fxsave_struct) + 105 int min_xstate_size = sizeof(struct i387_fxsave_struct) +
112 sizeof(struct xsave_hdr_struct); 106 sizeof(struct xsave_hdr_struct);
113 unsigned int magic2; 107 unsigned int magic2;
114 int err;
115 108
116 err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0], 109 if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw)))
117 sizeof(struct _fpx_sw_bytes)); 110 return -1;
118 if (err)
119 return -EFAULT;
120 111
121 /* 112 /* Check for the first magic field and other error scenarios. */
122 * First Magic check failed. 113 if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
123 */ 114 fx_sw->xstate_size < min_xstate_size ||
124 if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1) 115 fx_sw->xstate_size > xstate_size ||
125 return -EINVAL; 116 fx_sw->xstate_size > fx_sw->extended_size)
117 return -1;
126 118
127 /* 119 /*
128 * Check for error scenarios.
129 */
130 if (fx_sw_user->xstate_size < min_xstate_size ||
131 fx_sw_user->xstate_size > xstate_size ||
132 fx_sw_user->xstate_size > fx_sw_user->extended_size)
133 return -EINVAL;
134
135 err = __get_user(magic2, (__u32 __user *) (fpstate +
136 fx_sw_user->extended_size -
137 FP_XSTATE_MAGIC2_SIZE));
138 if (err)
139 return err;
140 /*
141 * Check for the presence of second magic word at the end of memory 120 * Check for the presence of second magic word at the end of memory
142 * layout. This detects the case where the user just copied the legacy 121 * layout. This detects the case where the user just copied the legacy
143 * fpstate layout with out copying the extended state information 122 * fpstate layout with out copying the extended state information
144 * in the memory layout. 123 * in the memory layout.
145 */ 124 */
146 if (magic2 != FP_XSTATE_MAGIC2) 125 if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))
147 return -EFAULT; 126 || magic2 != FP_XSTATE_MAGIC2)
127 return -1;
148 128
149 return 0; 129 return 0;
150} 130}
151 131
152#ifdef CONFIG_X86_64
153/* 132/*
154 * Signal frame handlers. 133 * Signal frame handlers.
155 */ 134 */
135static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
136{
137 if (use_fxsr()) {
138 struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
139 struct user_i387_ia32_struct env;
140 struct _fpstate_ia32 __user *fp = buf;
156 141
157int save_i387_xstate(void __user *buf) 142 convert_from_fxsr(&env, tsk);
143
144 if (__copy_to_user(buf, &env, sizeof(env)) ||
145 __put_user(xsave->i387.swd, &fp->status) ||
146 __put_user(X86_FXSR_MAGIC, &fp->magic))
147 return -1;
148 } else {
149 struct i387_fsave_struct __user *fp = buf;
150 u32 swd;
151 if (__get_user(swd, &fp->swd) || __put_user(swd, &fp->status))
152 return -1;
153 }
154
155 return 0;
156}
157
158static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
158{ 159{
159 struct task_struct *tsk = current; 160 struct xsave_struct __user *x = buf;
160 int err = 0; 161 struct _fpx_sw_bytes *sw_bytes;
162 u32 xstate_bv;
163 int err;
161 164
162 if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size)) 165 /* Setup the bytes not touched by the [f]xsave and reserved for SW. */
163 return -EACCES; 166 sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved;
167 err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes));
164 168
165 BUG_ON(sig_xstate_size < xstate_size); 169 if (!use_xsave())
170 return err;
166 171
167 if ((unsigned long)buf % 64) 172 err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size));
168 pr_err("%s: bad fpstate %p\n", __func__, buf);
169 173
170 if (!used_math()) 174 /*
171 return 0; 175 * Read the xstate_bv which we copied (directly from the cpu or
176 * from the state in task struct) to the user buffers.
177 */
178 err |= __get_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
172 179
173 if (user_has_fpu()) { 180 /*
174 if (use_xsave()) 181 * For legacy compatible, we always set FP/SSE bits in the bit
175 err = xsave_user(buf); 182 * vector while saving the state to the user context. This will
176 else 183 * enable us capturing any changes(during sigreturn) to
177 err = fxsave_user(buf); 184 * the FP/SSE bits by the legacy applications which don't touch
185 * xstate_bv in the xsave header.
186 *
187 * xsave aware apps can change the xstate_bv in the xsave
188 * header as well as change any contents in the memory layout.
189 * xrestore as part of sigreturn will capture all the changes.
190 */
191 xstate_bv |= XSTATE_FPSSE;
178 192
179 if (unlikely(err)) { 193 err |= __put_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
180 __clear_user(buf, xstate_size); 194
181 return err; 195 return err;
182 } 196}
197
198static inline int save_user_xstate(struct xsave_struct __user *buf)
199{
200 int err;
201
202 if (use_xsave())
203 err = xsave_user(buf);
204 else if (use_fxsr())
205 err = fxsave_user((struct i387_fxsave_struct __user *) buf);
206 else
207 err = fsave_user((struct i387_fsave_struct __user *) buf);
208
209 if (unlikely(err) && __clear_user(buf, xstate_size))
210 err = -EFAULT;
211 return err;
212}
213
214/*
215 * Save the fpu, extended register state to the user signal frame.
216 *
217 * 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save
218 * state is copied.
219 * 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'.
220 *
221 * buf == buf_fx for 64-bit frames and 32-bit fsave frame.
222 * buf != buf_fx for 32-bit frames with fxstate.
223 *
224 * If the fpu, extended register state is live, save the state directly
225 * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise,
226 * copy the thread's fpu state to the user frame starting at 'buf_fx'.
227 *
228 * If this is a 32-bit frame with fxstate, put a fsave header before
229 * the aligned state at 'buf_fx'.
230 *
231 * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
232 * indicating the absence/presence of the extended state to the user.
233 */
234int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
235{
236 struct xsave_struct *xsave = &current->thread.fpu.state->xsave;
237 struct task_struct *tsk = current;
238 int ia32_fxstate = (buf != buf_fx);
239
240 ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
241 config_enabled(CONFIG_IA32_EMULATION));
242
243 if (!access_ok(VERIFY_WRITE, buf, size))
244 return -EACCES;
245
246 if (!HAVE_HWFP)
247 return fpregs_soft_get(current, NULL, 0,
248 sizeof(struct user_i387_ia32_struct), NULL,
249 (struct _fpstate_ia32 __user *) buf) ? -1 : 1;
250
251 if (user_has_fpu()) {
252 /* Save the live register state to the user directly. */
253 if (save_user_xstate(buf_fx))
254 return -1;
255 /* Update the thread's fxstate to save the fsave header. */
256 if (ia32_fxstate)
257 fpu_fxsave(&tsk->thread.fpu);
183 user_fpu_end(); 258 user_fpu_end();
184 } else { 259 } else {
185 sanitize_i387_state(tsk); 260 sanitize_i387_state(tsk);
186 if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave, 261 if (__copy_to_user(buf_fx, xsave, xstate_size))
187 xstate_size))
188 return -1; 262 return -1;
189 } 263 }
190 264
191 clear_used_math(); /* trigger finit */ 265 /* Save the fsave header for the 32-bit frames. */
266 if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf))
267 return -1;
192 268
193 if (use_xsave()) { 269 if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
194 struct _fpstate __user *fx = buf; 270 return -1;
195 struct _xstate __user *x = buf; 271
196 u64 xstate_bv; 272 drop_fpu(tsk); /* trigger finit */
273
274 return 0;
275}
197 276
198 err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved, 277static inline void
199 sizeof(struct _fpx_sw_bytes)); 278sanitize_restored_xstate(struct task_struct *tsk,
279 struct user_i387_ia32_struct *ia32_env,
280 u64 xstate_bv, int fx_only)
281{
282 struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
283 struct xsave_hdr_struct *xsave_hdr = &xsave->xsave_hdr;
200 284
201 err |= __put_user(FP_XSTATE_MAGIC2, 285 if (use_xsave()) {
202 (__u32 __user *) (buf + sig_xstate_size 286 /* These bits must be zero. */
203 - FP_XSTATE_MAGIC2_SIZE)); 287 xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
204 288
205 /* 289 /*
206 * Read the xstate_bv which we copied (directly from the cpu or 290 * Init the state that is not present in the memory
207 * from the state in task struct) to the user buffers and 291 * layout and not enabled by the OS.
208 * set the FP/SSE bits.
209 */ 292 */
210 err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv); 293 if (fx_only)
294 xsave_hdr->xstate_bv = XSTATE_FPSSE;
295 else
296 xsave_hdr->xstate_bv &= (pcntxt_mask & xstate_bv);
297 }
211 298
299 if (use_fxsr()) {
212 /* 300 /*
213 * For legacy compatible, we always set FP/SSE bits in the bit 301 * mscsr reserved bits must be masked to zero for security
214 * vector while saving the state to the user context. This will 302 * reasons.
215 * enable us capturing any changes(during sigreturn) to
216 * the FP/SSE bits by the legacy applications which don't touch
217 * xstate_bv in the xsave header.
218 *
219 * xsave aware apps can change the xstate_bv in the xsave
220 * header as well as change any contents in the memory layout.
221 * xrestore as part of sigreturn will capture all the changes.
222 */ 303 */
223 xstate_bv |= XSTATE_FPSSE; 304 xsave->i387.mxcsr &= mxcsr_feature_mask;
224
225 err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
226 305
227 if (err) 306 convert_to_fxsr(tsk, ia32_env);
228 return err;
229 } 307 }
230
231 return 1;
232} 308}
233 309
234/* 310/*
235 * Restore the extended state if present. Otherwise, restore the FP/SSE 311 * Restore the extended state if present. Otherwise, restore the FP/SSE state.
236 * state.
237 */ 312 */
238static int restore_user_xstate(void __user *buf) 313static inline int restore_user_xstate(void __user *buf, u64 xbv, int fx_only)
239{ 314{
240 struct _fpx_sw_bytes fx_sw_user; 315 if (use_xsave()) {
241 u64 mask; 316 if ((unsigned long)buf % 64 || fx_only) {
242 int err; 317 u64 init_bv = pcntxt_mask & ~XSTATE_FPSSE;
243 318 xrstor_state(init_xstate_buf, init_bv);
244 if (((unsigned long)buf % 64) || 319 return fxrstor_checking((__force void *) buf);
245 check_for_xstate(buf, buf, &fx_sw_user)) 320 } else {
246 goto fx_only; 321 u64 init_bv = pcntxt_mask & ~xbv;
247 322 if (unlikely(init_bv))
248 mask = fx_sw_user.xstate_bv; 323 xrstor_state(init_xstate_buf, init_bv);
249 324 return xrestore_user(buf, xbv);
250 /* 325 }
251 * restore the state passed by the user. 326 } else if (use_fxsr()) {
252 */ 327 return fxrstor_checking((__force void *) buf);
253 err = xrestore_user(buf, mask); 328 } else
254 if (err) 329 return frstor_checking((__force void *) buf);
255 return err;
256
257 /*
258 * init the state skipped by the user.
259 */
260 mask = pcntxt_mask & ~mask;
261 if (unlikely(mask))
262 xrstor_state(init_xstate_buf, mask);
263
264 return 0;
265
266fx_only:
267 /*
268 * couldn't find the extended state information in the
269 * memory layout. Restore just the FP/SSE and init all
270 * the other extended state.
271 */
272 xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
273 return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
274} 330}
275 331
276/* 332int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
277 * This restores directly out of user space. Exceptions are handled.
278 */
279int restore_i387_xstate(void __user *buf)
280{ 333{
334 int ia32_fxstate = (buf != buf_fx);
281 struct task_struct *tsk = current; 335 struct task_struct *tsk = current;
282 int err = 0; 336 int state_size = xstate_size;
337 u64 xstate_bv = 0;
338 int fx_only = 0;
339
340 ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
341 config_enabled(CONFIG_IA32_EMULATION));
283 342
284 if (!buf) { 343 if (!buf) {
285 if (used_math()) 344 drop_fpu(tsk);
286 goto clear;
287 return 0; 345 return 0;
288 } else 346 }
289 if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) 347
290 return -EACCES; 348 if (!access_ok(VERIFY_READ, buf, size))
349 return -EACCES;
350
351 if (!used_math() && init_fpu(tsk))
352 return -1;
291 353
292 if (!used_math()) { 354 if (!HAVE_HWFP) {
293 err = init_fpu(tsk); 355 return fpregs_soft_set(current, NULL,
294 if (err) 356 0, sizeof(struct user_i387_ia32_struct),
295 return err; 357 NULL, buf) != 0;
296 } 358 }
297 359
298 user_fpu_begin(); 360 if (use_xsave()) {
299 if (use_xsave()) 361 struct _fpx_sw_bytes fx_sw_user;
300 err = restore_user_xstate(buf); 362 if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) {
301 else 363 /*
302 err = fxrstor_checking((__force struct i387_fxsave_struct *) 364 * Couldn't find the extended state information in the
303 buf); 365 * memory layout. Restore just the FP/SSE and init all
304 if (unlikely(err)) { 366 * the other extended state.
367 */
368 state_size = sizeof(struct i387_fxsave_struct);
369 fx_only = 1;
370 } else {
371 state_size = fx_sw_user.xstate_size;
372 xstate_bv = fx_sw_user.xstate_bv;
373 }
374 }
375
376 if (ia32_fxstate) {
377 /*
378 * For 32-bit frames with fxstate, copy the user state to the
379 * thread's fpu state, reconstruct fxstate from the fsave
380 * header. Sanitize the copied state etc.
381 */
382 struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
383 struct user_i387_ia32_struct env;
384
385 stop_fpu_preload(tsk);
386 unlazy_fpu(tsk);
387
388 if (__copy_from_user(xsave, buf_fx, state_size) ||
389 __copy_from_user(&env, buf, sizeof(env))) {
390 drop_fpu(tsk);
391 return -1;
392 }
393
394 sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
395 } else {
305 /* 396 /*
306 * Encountered an error while doing the restore from the 397 * For 64-bit frames and 32-bit fsave frames, restore the user
307 * user buffer, clear the fpu state. 398 * state to the registers directly (with exceptions handled).
308 */ 399 */
309clear: 400 user_fpu_begin();
310 clear_fpu(tsk); 401 if (restore_user_xstate(buf_fx, xstate_bv, fx_only)) {
311 clear_used_math(); 402 drop_fpu(tsk);
403 return -1;
404 }
312 } 405 }
313 return err; 406
407 return 0;
314} 408}
315#endif
316 409
317/* 410/*
318 * Prepare the SW reserved portion of the fxsave memory layout, indicating 411 * Prepare the SW reserved portion of the fxsave memory layout, indicating
@@ -323,31 +416,22 @@ clear:
323 */ 416 */
324static void prepare_fx_sw_frame(void) 417static void prepare_fx_sw_frame(void)
325{ 418{
326 int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) + 419 int fsave_header_size = sizeof(struct i387_fsave_struct);
327 FP_XSTATE_MAGIC2_SIZE; 420 int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
328
329 sig_xstate_size = sizeof(struct _fpstate) + size_extended;
330
331#ifdef CONFIG_IA32_EMULATION
332 sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
333#endif
334 421
335 memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved)); 422 if (config_enabled(CONFIG_X86_32))
423 size += fsave_header_size;
336 424
337 fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; 425 fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
338 fx_sw_reserved.extended_size = sig_xstate_size; 426 fx_sw_reserved.extended_size = size;
339 fx_sw_reserved.xstate_bv = pcntxt_mask; 427 fx_sw_reserved.xstate_bv = pcntxt_mask;
340 fx_sw_reserved.xstate_size = xstate_size; 428 fx_sw_reserved.xstate_size = xstate_size;
341#ifdef CONFIG_IA32_EMULATION
342 memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
343 sizeof(struct _fpx_sw_bytes));
344 fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
345#endif
346}
347 429
348#ifdef CONFIG_X86_64 430 if (config_enabled(CONFIG_IA32_EMULATION)) {
349unsigned int sig_xstate_size = sizeof(struct _fpstate); 431 fx_sw_reserved_ia32 = fx_sw_reserved;
350#endif 432 fx_sw_reserved_ia32.extended_size += fsave_header_size;
433 }
434}
351 435
352/* 436/*
353 * Enable the extended processor state save/restore feature 437 * Enable the extended processor state save/restore feature