diff options
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/fpu-internal.h | 111 | ||||
-rw-r--r-- | arch/x86/include/asm/xsave.h | 6 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 246 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 10 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/signal.c | 15 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 432 |
8 files changed, 348 insertions, 484 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 452d4dd0a95a..8c77c64fbd27 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 016acb30fa4a..4fbb4195bc63 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 | ||
25 | extern unsigned int sig_xstate_size; | 25 | #ifdef CONFIG_X86_64 |
26 | # include <asm/sigcontext32.h> | ||
27 | # include <asm/user32.h> | ||
28 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
29 | compat_sigset_t *set, struct pt_regs *regs); | ||
30 | int 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 | |||
39 | extern unsigned int mxcsr_feature_mask; | ||
26 | extern void fpu_init(void); | 40 | extern void fpu_init(void); |
27 | 41 | ||
28 | DECLARE_PER_CPU(struct task_struct *, fpu_owner_task); | 42 | DECLARE_PER_CPU(struct task_struct *, fpu_owner_task); |
29 | 43 | ||
44 | extern void convert_from_fxsr(struct user_i387_ia32_struct *env, | ||
45 | struct task_struct *tsk); | ||
46 | extern void convert_to_fxsr(struct task_struct *tsk, | ||
47 | const struct user_i387_ia32_struct *env); | ||
48 | |||
30 | extern user_regset_active_fn fpregs_active, xfpregs_active; | 49 | extern user_regset_active_fn fpregs_active, xfpregs_active; |
31 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, | 50 | extern 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 | ||
42 | extern struct _fpx_sw_bytes fx_sw_reserved; | ||
43 | #ifdef CONFIG_IA32_EMULATION | ||
44 | extern unsigned int sig_xstate_ia32_size; | ||
45 | extern struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
46 | struct _fpstate_ia32; | ||
47 | struct _xstate_ia32; | ||
48 | extern int save_i387_xstate_ia32(void __user *buf); | ||
49 | extern 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) | ||
53 | extern void finit_soft_fpu(struct i387_soft_struct *soft); | 63 | extern void finit_soft_fpu(struct i387_soft_struct *soft); |
54 | #else | 64 | #else |
65 | # define HAVE_HWFP 1 | ||
55 | static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} | 66 | static 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 | ||
120 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | 131 | static 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 | |||
194 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
195 | compat_sigset_t *set, struct pt_regs *regs); | ||
196 | int 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 | */ |
395 | extern int save_i387_xstate(void __user *buf); | 382 | extern int save_xstate_sig(void __user *buf, void __user *fx, int size); |
396 | extern int restore_i387_xstate(void __user *buf); | 383 | extern int __restore_xstate_sig(void __user *buf, void __user *fx, int size); |
384 | |||
385 | static inline int xstate_sigframe_size(void) | ||
386 | { | ||
387 | return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size; | ||
388 | } | ||
389 | |||
390 | static 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 | ||
398 | static inline void __clear_fpu(struct task_struct *tsk) | 403 | static 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 | ||
446 | static inline void clear_fpu(struct task_struct *tsk) | 451 | static inline void stop_fpu_preload(struct task_struct *tsk) |
447 | { | 452 | { |
453 | tsk->fpu_counter = 0; | ||
454 | } | ||
455 | |||
456 | static 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 | ||
512 | extern void fpu_finit(struct fpu *fpu); | 527 | extern void fpu_finit(struct fpu *fpu); |
513 | 528 | ||
529 | static inline unsigned long | ||
530 | alloc_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 aaac810e8613..c1d989a15193 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]; | |||
38 | extern void xsave_init(void); | 38 | extern void xsave_init(void); |
39 | extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); | 39 | extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); |
40 | extern int init_fpu(struct task_struct *child); | 40 | extern int init_fpu(struct task_struct *child); |
41 | extern int check_for_xstate(struct i387_fxsave_struct __user *buf, | ||
42 | void __user *fpstate, | ||
43 | struct _fpx_sw_bytes *sw); | ||
44 | 41 | ||
45 | static inline int fpu_xrstor_checking(struct xsave_struct *fx) | 42 | static 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 f250431fb505..ab6a2e8028ae 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 | } |
114 | EXPORT_SYMBOL(unlazy_fpu); | 100 | EXPORT_SYMBOL(unlazy_fpu); |
115 | 101 | ||
116 | #ifdef CONFIG_MATH_EMULATION | 102 | unsigned 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 | |||
122 | static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; | ||
123 | unsigned int xstate_size; | 103 | unsigned int xstate_size; |
124 | EXPORT_SYMBOL_GPL(xstate_size); | 104 | EXPORT_SYMBOL_GPL(xstate_size); |
125 | unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); | ||
126 | static struct i387_fxsave_struct fx_scratch __cpuinitdata; | 105 | static struct i387_fxsave_struct fx_scratch __cpuinitdata; |
127 | 106 | ||
128 | static void __cpuinit mxcsr_feature_mask_init(void) | 107 | static 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 | ||
457 | static void | 436 | void |
458 | convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) | 437 | convert_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 | ||
494 | static void convert_to_fxsr(struct task_struct *tsk, | 473 | void 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 | |||
595 | static 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 | |||
606 | static 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 | |||
627 | static 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 | |||
663 | int 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 | |||
695 | static 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 | |||
703 | static 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 | |||
721 | static 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 | ¤t->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; | ||
754 | fx_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 | |||
764 | int 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 ef6a8456f719..30069d1a6a4d 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 | ||
100 | static 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 c4c6a5c2bf0f..861a9d1a463d 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 bed431a38162..e10f96a7e047 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 7a3d4df9eaf6..0923d27f23df 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 | */ |
26 | static struct xsave_struct *init_xstate_buf; | 24 | static struct xsave_struct *init_xstate_buf; |
27 | 25 | ||
28 | struct _fpx_sw_bytes fx_sw_reserved; | 26 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; |
29 | #ifdef CONFIG_IA32_EMULATION | ||
30 | struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
31 | #endif | ||
32 | |||
33 | static unsigned int *xstate_offsets, *xstate_sizes, xstate_features; | 27 | static 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 | */ |
45 | void __sanitize_i387_state(struct task_struct *tsk) | 39 | void __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 | */ |
107 | int check_for_xstate(struct i387_fxsave_struct __user *buf, | 101 | static 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 | */ |
135 | static 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 | ||
157 | int 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 | |||
158 | static 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 | |||
198 | static 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 | */ | ||
234 | int save_xstate_sig(void __user *buf, void __user *buf_fx, int size) | ||
235 | { | ||
236 | struct xsave_struct *xsave = ¤t->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, | 277 | static inline void |
199 | sizeof(struct _fpx_sw_bytes)); | 278 | sanitize_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 | */ |
238 | static int restore_user_xstate(void __user *buf) | 313 | static 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 | |||
266 | fx_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 | /* | 332 | int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size) |
277 | * This restores directly out of user space. Exceptions are handled. | ||
278 | */ | ||
279 | int 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 | */ |
309 | clear: | 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 | */ |
324 | static void prepare_fx_sw_frame(void) | 417 | static 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)) { |
349 | unsigned 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 |