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 | |
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>
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 82 | ||||
-rw-r--r-- | arch/x86/kernel/signal_32.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/signal_64.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 172 | ||||
-rw-r--r-- | include/asm-x86/i387.h | 4 | ||||
-rw-r--r-- | include/asm-x86/ucontext.h | 6 | ||||
-rw-r--r-- | include/asm-x86/xsave.h | 5 |
8 files changed, 264 insertions, 22 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index c596eabbe98b..f25a10124005 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -544,7 +544,10 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
544 | goto give_sigsegv; | 544 | goto give_sigsegv; |
545 | 545 | ||
546 | /* Create the ucontext. */ | 546 | /* Create the ucontext. */ |
547 | err |= __put_user(0, &frame->uc.uc_flags); | 547 | if (cpu_has_xsave) |
548 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
549 | else | ||
550 | err |= __put_user(0, &frame->uc.uc_flags); | ||
548 | err |= __put_user(0, &frame->uc.uc_link); | 551 | err |= __put_user(0, &frame->uc.uc_link); |
549 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 552 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
550 | err |= __put_user(sas_ss_flags(regs->sp), | 553 | err |= __put_user(sas_ss_flags(regs->sp), |
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 { |
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 690cc616ac07..0f98d69fbdb0 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -441,7 +441,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
441 | goto give_sigsegv; | 441 | goto give_sigsegv; |
442 | 442 | ||
443 | /* Create the ucontext. */ | 443 | /* Create the ucontext. */ |
444 | err |= __put_user(0, &frame->uc.uc_flags); | 444 | if (cpu_has_xsave) |
445 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
446 | else | ||
447 | err |= __put_user(0, &frame->uc.uc_flags); | ||
445 | err |= __put_user(0, &frame->uc.uc_link); | 448 | err |= __put_user(0, &frame->uc.uc_link); |
446 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 449 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
447 | err |= __put_user(sas_ss_flags(regs->sp), | 450 | err |= __put_user(sas_ss_flags(regs->sp), |
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index ddf6123a55c8..2621b98f5bf6 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -192,7 +192,7 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) | |||
192 | sp = current->sas_ss_sp + current->sas_ss_size; | 192 | sp = current->sas_ss_sp + current->sas_ss_size; |
193 | } | 193 | } |
194 | 194 | ||
195 | return (void __user *)round_down(sp - size, 16); | 195 | return (void __user *)round_down(sp - size, 64); |
196 | } | 196 | } |
197 | 197 | ||
198 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 198 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
@@ -226,7 +226,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
226 | } | 226 | } |
227 | 227 | ||
228 | /* Create the ucontext. */ | 228 | /* Create the ucontext. */ |
229 | err |= __put_user(0, &frame->uc.uc_flags); | 229 | if (cpu_has_xsave) |
230 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
231 | else | ||
232 | err |= __put_user(0, &frame->uc.uc_flags); | ||
230 | err |= __put_user(0, &frame->uc.uc_link); | 233 | err |= __put_user(0, &frame->uc.uc_link); |
231 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 234 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
232 | err |= __put_user(sas_ss_flags(regs->sp), | 235 | err |= __put_user(sas_ss_flags(regs->sp), |
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index 608e72d7ca64..dd66d0714c18 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c | |||
@@ -6,12 +6,68 @@ | |||
6 | #include <linux/bootmem.h> | 6 | #include <linux/bootmem.h> |
7 | #include <linux/compat.h> | 7 | #include <linux/compat.h> |
8 | #include <asm/i387.h> | 8 | #include <asm/i387.h> |
9 | #ifdef CONFIG_IA32_EMULATION | ||
10 | #include <asm/sigcontext32.h> | ||
11 | #endif | ||
9 | 12 | ||
10 | /* | 13 | /* |
11 | * Supported feature mask by the CPU and the kernel. | 14 | * Supported feature mask by the CPU and the kernel. |
12 | */ | 15 | */ |
13 | unsigned int pcntxt_hmask, pcntxt_lmask; | 16 | unsigned int pcntxt_hmask, pcntxt_lmask; |
14 | 17 | ||
18 | struct _fpx_sw_bytes fx_sw_reserved; | ||
19 | #ifdef CONFIG_IA32_EMULATION | ||
20 | struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
21 | #endif | ||
22 | |||
23 | /* | ||
24 | * Check for the presence of extended state information in the | ||
25 | * user fpstate pointer in the sigcontext. | ||
26 | */ | ||
27 | int check_for_xstate(struct i387_fxsave_struct __user *buf, | ||
28 | void __user *fpstate, | ||
29 | struct _fpx_sw_bytes *fx_sw_user) | ||
30 | { | ||
31 | int min_xstate_size = sizeof(struct i387_fxsave_struct) + | ||
32 | sizeof(struct xsave_hdr_struct); | ||
33 | unsigned int magic2; | ||
34 | int err; | ||
35 | |||
36 | err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0], | ||
37 | sizeof(struct _fpx_sw_bytes)); | ||
38 | |||
39 | if (err) | ||
40 | return err; | ||
41 | |||
42 | /* | ||
43 | * First Magic check failed. | ||
44 | */ | ||
45 | if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1) | ||
46 | return -1; | ||
47 | |||
48 | /* | ||
49 | * Check for error scenarios. | ||
50 | */ | ||
51 | if (fx_sw_user->xstate_size < min_xstate_size || | ||
52 | fx_sw_user->xstate_size > xstate_size || | ||
53 | fx_sw_user->xstate_size > fx_sw_user->extended_size) | ||
54 | return -1; | ||
55 | |||
56 | err = __get_user(magic2, (__u32 *) (((void *)fpstate) + | ||
57 | fx_sw_user->extended_size - | ||
58 | FP_XSTATE_MAGIC2_SIZE)); | ||
59 | /* | ||
60 | * Check for the presence of second magic word at the end of memory | ||
61 | * layout. This detects the case where the user just copied the legacy | ||
62 | * fpstate layout with out copying the extended state information | ||
63 | * in the memory layout. | ||
64 | */ | ||
65 | if (err || magic2 != FP_XSTATE_MAGIC2) | ||
66 | return -1; | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
15 | #ifdef CONFIG_X86_64 | 71 | #ifdef CONFIG_X86_64 |
16 | /* | 72 | /* |
17 | * Signal frame handlers. | 73 | * Signal frame handlers. |
@@ -28,15 +84,18 @@ int save_i387_xstate(void __user *buf) | |||
28 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != | 84 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != |
29 | sizeof(tsk->thread.xstate->fxsave)); | 85 | sizeof(tsk->thread.xstate->fxsave)); |
30 | 86 | ||
31 | if ((unsigned long)buf % 16) | 87 | if ((unsigned long)buf % 64) |
32 | printk("save_i387_xstate: bad fpstate %p\n", buf); | 88 | printk("save_i387_xstate: bad fpstate %p\n", buf); |
33 | 89 | ||
34 | if (!used_math()) | 90 | if (!used_math()) |
35 | return 0; | 91 | return 0; |
36 | clear_used_math(); /* trigger finit */ | 92 | clear_used_math(); /* trigger finit */ |
37 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | 93 | if (task_thread_info(tsk)->status & TS_USEDFPU) { |
38 | err = save_i387_checking((struct i387_fxsave_struct __user *) | 94 | if (task_thread_info(tsk)->status & TS_XSAVE) |
39 | buf); | 95 | err = xsave_user(buf); |
96 | else | ||
97 | err = fxsave_user(buf); | ||
98 | |||
40 | if (err) | 99 | if (err) |
41 | return err; | 100 | return err; |
42 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 101 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
@@ -46,23 +105,77 @@ int save_i387_xstate(void __user *buf) | |||
46 | xstate_size)) | 105 | xstate_size)) |
47 | return -1; | 106 | return -1; |
48 | } | 107 | } |
108 | |||
109 | if (task_thread_info(tsk)->status & TS_XSAVE) { | ||
110 | struct _fpstate __user *fx = buf; | ||
111 | |||
112 | err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved, | ||
113 | sizeof(struct _fpx_sw_bytes)); | ||
114 | |||
115 | err |= __put_user(FP_XSTATE_MAGIC2, | ||
116 | (__u32 __user *) (buf + sig_xstate_size | ||
117 | - FP_XSTATE_MAGIC2_SIZE)); | ||
118 | } | ||
119 | |||
49 | return 1; | 120 | return 1; |
50 | } | 121 | } |
51 | 122 | ||
52 | /* | 123 | /* |
124 | * Restore the extended state if present. Otherwise, restore the FP/SSE | ||
125 | * state. | ||
126 | */ | ||
127 | int restore_user_xstate(void __user *buf) | ||
128 | { | ||
129 | struct _fpx_sw_bytes fx_sw_user; | ||
130 | unsigned int lmask, hmask; | ||
131 | int err; | ||
132 | |||
133 | if (((unsigned long)buf % 64) || | ||
134 | check_for_xstate(buf, buf, &fx_sw_user)) | ||
135 | goto fx_only; | ||
136 | |||
137 | lmask = fx_sw_user.xstate_bv; | ||
138 | hmask = fx_sw_user.xstate_bv >> 32; | ||
139 | |||
140 | /* | ||
141 | * restore the state passed by the user. | ||
142 | */ | ||
143 | err = xrestore_user(buf, lmask, hmask); | ||
144 | if (err) | ||
145 | return err; | ||
146 | |||
147 | /* | ||
148 | * init the state skipped by the user. | ||
149 | */ | ||
150 | lmask = pcntxt_lmask & ~lmask; | ||
151 | hmask = pcntxt_hmask & ~hmask; | ||
152 | |||
153 | xrstor_state(init_xstate_buf, lmask, hmask); | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | fx_only: | ||
158 | /* | ||
159 | * couldn't find the extended state information in the | ||
160 | * memory layout. Restore just the FP/SSE and init all | ||
161 | * the other extended state. | ||
162 | */ | ||
163 | xrstor_state(init_xstate_buf, pcntxt_lmask & ~XSTATE_FPSSE, | ||
164 | pcntxt_hmask); | ||
165 | return fxrstor_checking((__force struct i387_fxsave_struct *)buf); | ||
166 | } | ||
167 | |||
168 | /* | ||
53 | * This restores directly out of user space. Exceptions are handled. | 169 | * This restores directly out of user space. Exceptions are handled. |
54 | */ | 170 | */ |
55 | int restore_i387_xstate(void __user *buf) | 171 | int restore_i387_xstate(void __user *buf) |
56 | { | 172 | { |
57 | struct task_struct *tsk = current; | 173 | struct task_struct *tsk = current; |
58 | int err; | 174 | int err = 0; |
59 | 175 | ||
60 | if (!buf) { | 176 | if (!buf) { |
61 | if (used_math()) { | 177 | if (used_math()) |
62 | clear_fpu(tsk); | 178 | goto clear; |
63 | clear_used_math(); | ||
64 | } | ||
65 | |||
66 | return 0; | 179 | return 0; |
67 | } else | 180 | } else |
68 | if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) | 181 | if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) |
@@ -78,12 +191,17 @@ int restore_i387_xstate(void __user *buf) | |||
78 | clts(); | 191 | clts(); |
79 | task_thread_info(current)->status |= TS_USEDFPU; | 192 | task_thread_info(current)->status |= TS_USEDFPU; |
80 | } | 193 | } |
81 | err = fxrstor_checking((__force struct i387_fxsave_struct *)buf); | 194 | if (task_thread_info(tsk)->status & TS_XSAVE) |
195 | err = restore_user_xstate(buf); | ||
196 | else | ||
197 | err = fxrstor_checking((__force struct i387_fxsave_struct *) | ||
198 | buf); | ||
82 | if (unlikely(err)) { | 199 | if (unlikely(err)) { |
83 | /* | 200 | /* |
84 | * Encountered an error while doing the restore from the | 201 | * Encountered an error while doing the restore from the |
85 | * user buffer, clear the fpu state. | 202 | * user buffer, clear the fpu state. |
86 | */ | 203 | */ |
204 | clear: | ||
87 | clear_fpu(tsk); | 205 | clear_fpu(tsk); |
88 | clear_used_math(); | 206 | clear_used_math(); |
89 | } | 207 | } |
@@ -92,6 +210,38 @@ int restore_i387_xstate(void __user *buf) | |||
92 | #endif | 210 | #endif |
93 | 211 | ||
94 | /* | 212 | /* |
213 | * Prepare the SW reserved portion of the fxsave memory layout, indicating | ||
214 | * the presence of the extended state information in the memory layout | ||
215 | * pointed by the fpstate pointer in the sigcontext. | ||
216 | * This will be saved when ever the FP and extended state context is | ||
217 | * saved on the user stack during the signal handler delivery to the user. | ||
218 | */ | ||
219 | void prepare_fx_sw_frame(void) | ||
220 | { | ||
221 | int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) + | ||
222 | FP_XSTATE_MAGIC2_SIZE; | ||
223 | |||
224 | sig_xstate_size = sizeof(struct _fpstate) + size_extended; | ||
225 | |||
226 | #ifdef CONFIG_IA32_EMULATION | ||
227 | sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended; | ||
228 | #endif | ||
229 | |||
230 | memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved)); | ||
231 | |||
232 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; | ||
233 | fx_sw_reserved.extended_size = sig_xstate_size; | ||
234 | fx_sw_reserved.xstate_bv = pcntxt_lmask | | ||
235 | (((u64) (pcntxt_hmask)) << 32); | ||
236 | fx_sw_reserved.xstate_size = xstate_size; | ||
237 | #ifdef CONFIG_IA32_EMULATION | ||
238 | memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved, | ||
239 | sizeof(struct _fpx_sw_bytes)); | ||
240 | fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size; | ||
241 | #endif | ||
242 | } | ||
243 | |||
244 | /* | ||
95 | * Represents init state for the supported extended state. | 245 | * Represents init state for the supported extended state. |
96 | */ | 246 | */ |
97 | struct xsave_struct *init_xstate_buf; | 247 | struct xsave_struct *init_xstate_buf; |
@@ -162,6 +312,8 @@ void __init xsave_cntxt_init(void) | |||
162 | 312 | ||
163 | xstate_size = ebx; | 313 | xstate_size = ebx; |
164 | 314 | ||
315 | prepare_fx_sw_frame(); | ||
316 | |||
165 | setup_xstate_init(); | 317 | setup_xstate_init(); |
166 | 318 | ||
167 | printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, " | 319 | printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, " |
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h index dc3745e8040a..d3dda7161954 100644 --- a/include/asm-x86/i387.h +++ b/include/asm-x86/i387.h | |||
@@ -31,8 +31,10 @@ extern user_regset_active_fn fpregs_active, xfpregs_active; | |||
31 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; | 31 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; |
32 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; | 32 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; |
33 | 33 | ||
34 | extern struct _fpx_sw_bytes fx_sw_reserved; | ||
34 | #ifdef CONFIG_IA32_EMULATION | 35 | #ifdef CONFIG_IA32_EMULATION |
35 | extern unsigned int sig_xstate_ia32_size; | 36 | extern unsigned int sig_xstate_ia32_size; |
37 | extern struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
36 | struct _fpstate_ia32; | 38 | struct _fpstate_ia32; |
37 | struct _xstate_ia32; | 39 | struct _xstate_ia32; |
38 | extern int save_i387_xstate_ia32(void __user *buf); | 40 | extern int save_i387_xstate_ia32(void __user *buf); |
@@ -104,7 +106,7 @@ static inline void clear_fpu_state(struct task_struct *tsk) | |||
104 | X86_FEATURE_FXSAVE_LEAK); | 106 | X86_FEATURE_FXSAVE_LEAK); |
105 | } | 107 | } |
106 | 108 | ||
107 | static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | 109 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) |
108 | { | 110 | { |
109 | int err; | 111 | int err; |
110 | 112 | ||
diff --git a/include/asm-x86/ucontext.h b/include/asm-x86/ucontext.h index 9948dd328084..89eaa5456a7e 100644 --- a/include/asm-x86/ucontext.h +++ b/include/asm-x86/ucontext.h | |||
@@ -1,6 +1,12 @@ | |||
1 | #ifndef ASM_X86__UCONTEXT_H | 1 | #ifndef ASM_X86__UCONTEXT_H |
2 | #define ASM_X86__UCONTEXT_H | 2 | #define ASM_X86__UCONTEXT_H |
3 | 3 | ||
4 | #define UC_FP_XSTATE 0x1 /* indicates the presence of extended state | ||
5 | * information in the memory layout pointed | ||
6 | * by the fpstate pointer in the ucontext's | ||
7 | * sigcontext struct (uc_mcontext). | ||
8 | */ | ||
9 | |||
4 | struct ucontext { | 10 | struct ucontext { |
5 | unsigned long uc_flags; | 11 | unsigned long uc_flags; |
6 | struct ucontext *uc_link; | 12 | struct ucontext *uc_link; |
diff --git a/include/asm-x86/xsave.h b/include/asm-x86/xsave.h index b716511aede2..b7f64b9fcd94 100644 --- a/include/asm-x86/xsave.h +++ b/include/asm-x86/xsave.h | |||
@@ -29,6 +29,9 @@ extern struct xsave_struct *init_xstate_buf; | |||
29 | extern void xsave_cntxt_init(void); | 29 | extern void xsave_cntxt_init(void); |
30 | extern void xsave_init(void); | 30 | extern void xsave_init(void); |
31 | extern int init_fpu(struct task_struct *child); | 31 | extern int init_fpu(struct task_struct *child); |
32 | extern int check_for_xstate(struct i387_fxsave_struct __user *buf, | ||
33 | void __user *fpstate, | ||
34 | struct _fpx_sw_bytes *sw); | ||
32 | 35 | ||
33 | static inline int xrstor_checking(struct xsave_struct *fx) | 36 | static inline int xrstor_checking(struct xsave_struct *fx) |
34 | { | 37 | { |
@@ -48,7 +51,7 @@ static inline int xrstor_checking(struct xsave_struct *fx) | |||
48 | return err; | 51 | return err; |
49 | } | 52 | } |
50 | 53 | ||
51 | static inline int xsave_check(struct xsave_struct __user *buf) | 54 | static inline int xsave_user(struct xsave_struct __user *buf) |
52 | { | 55 | { |
53 | int err; | 56 | int err; |
54 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" | 57 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" |