diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-09-05 03:18:39 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-05 03:18:39 -0400 |
commit | accf0fa697eeb5ff4c2360edc4da5b10abac0b7b (patch) | |
tree | a57dc9aa4a6b83be8ac8b4528cf06db5621e62aa | |
parent | ebd60cd64f8ab1170102c3ab072eb73042b7a33d (diff) | |
parent | fe47784ba5cbb6b713c013e046859946789b45e4 (diff) |
Merge branch 'x86/xsave' into x86/core
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 51 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 13 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 154 | ||||
-rw-r--r-- | arch/x86/kernel/sigframe.h | 14 | ||||
-rw-r--r-- | arch/x86/kernel/signal_32.c | 45 | ||||
-rw-r--r-- | arch/x86/kernel/signal_64.c | 95 | ||||
-rw-r--r-- | arch/x86/kernel/traps_32.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 316 | ||||
-rw-r--r-- | arch/x86/power/cpu_32.c | 7 | ||||
-rw-r--r-- | arch/x86/power/cpu_64.c | 7 | ||||
-rw-r--r-- | include/asm-x86/i387.h | 84 | ||||
-rw-r--r-- | include/asm-x86/processor-flags.h | 1 | ||||
-rw-r--r-- | include/asm-x86/processor.h | 20 | ||||
-rw-r--r-- | include/asm-x86/sigcontext.h | 87 | ||||
-rw-r--r-- | include/asm-x86/sigcontext32.h | 6 | ||||
-rw-r--r-- | include/asm-x86/thread_info.h | 1 | ||||
-rw-r--r-- | include/asm-x86/ucontext.h | 6 | ||||
-rw-r--r-- | include/asm-x86/xcr.h | 49 | ||||
-rw-r--r-- | include/asm-x86/xsave.h | 118 |
21 files changed, 899 insertions, 184 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 20af4c79579a..f25a10124005 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -179,9 +179,10 @@ struct sigframe | |||
179 | u32 pretcode; | 179 | u32 pretcode; |
180 | int sig; | 180 | int sig; |
181 | struct sigcontext_ia32 sc; | 181 | struct sigcontext_ia32 sc; |
182 | struct _fpstate_ia32 fpstate; | 182 | struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ |
183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; | 183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; |
184 | char retcode[8]; | 184 | char retcode[8]; |
185 | /* fp state follows here */ | ||
185 | }; | 186 | }; |
186 | 187 | ||
187 | struct rt_sigframe | 188 | struct rt_sigframe |
@@ -192,8 +193,8 @@ struct rt_sigframe | |||
192 | u32 puc; | 193 | u32 puc; |
193 | compat_siginfo_t info; | 194 | compat_siginfo_t info; |
194 | struct ucontext_ia32 uc; | 195 | struct ucontext_ia32 uc; |
195 | struct _fpstate_ia32 fpstate; | ||
196 | char retcode[8]; | 196 | char retcode[8]; |
197 | /* fp state follows here */ | ||
197 | }; | 198 | }; |
198 | 199 | ||
199 | #define COPY(x) { \ | 200 | #define COPY(x) { \ |
@@ -215,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
215 | unsigned int *peax) | 216 | unsigned int *peax) |
216 | { | 217 | { |
217 | unsigned int tmpflags, gs, oldgs, err = 0; | 218 | unsigned int tmpflags, gs, oldgs, err = 0; |
218 | struct _fpstate_ia32 __user *buf; | 219 | void __user *buf; |
219 | u32 tmp; | 220 | u32 tmp; |
220 | 221 | ||
221 | /* Always make any pending restarted system calls return -EINTR */ | 222 | /* Always make any pending restarted system calls return -EINTR */ |
@@ -259,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
259 | 260 | ||
260 | err |= __get_user(tmp, &sc->fpstate); | 261 | err |= __get_user(tmp, &sc->fpstate); |
261 | buf = compat_ptr(tmp); | 262 | buf = compat_ptr(tmp); |
262 | if (buf) { | 263 | err |= restore_i387_xstate_ia32(buf); |
263 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
264 | goto badframe; | ||
265 | err |= restore_i387_ia32(buf); | ||
266 | } else { | ||
267 | struct task_struct *me = current; | ||
268 | |||
269 | if (used_math()) { | ||
270 | clear_fpu(me); | ||
271 | clear_used_math(); | ||
272 | } | ||
273 | } | ||
274 | 264 | ||
275 | err |= __get_user(tmp, &sc->ax); | 265 | err |= __get_user(tmp, &sc->ax); |
276 | *peax = tmp; | 266 | *peax = tmp; |
277 | 267 | ||
278 | return err; | 268 | return err; |
279 | |||
280 | badframe: | ||
281 | return 1; | ||
282 | } | 269 | } |
283 | 270 | ||
284 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) | 271 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) |
@@ -350,7 +337,7 @@ badframe: | |||
350 | */ | 337 | */ |
351 | 338 | ||
352 | static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | 339 | static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, |
353 | struct _fpstate_ia32 __user *fpstate, | 340 | void __user *fpstate, |
354 | struct pt_regs *regs, unsigned int mask) | 341 | struct pt_regs *regs, unsigned int mask) |
355 | { | 342 | { |
356 | int tmp, err = 0; | 343 | int tmp, err = 0; |
@@ -381,7 +368,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
381 | err |= __put_user((u32)regs->flags, &sc->flags); | 368 | err |= __put_user((u32)regs->flags, &sc->flags); |
382 | err |= __put_user((u32)regs->sp, &sc->sp_at_signal); | 369 | err |= __put_user((u32)regs->sp, &sc->sp_at_signal); |
383 | 370 | ||
384 | tmp = save_i387_ia32(fpstate); | 371 | tmp = save_i387_xstate_ia32(fpstate); |
385 | if (tmp < 0) | 372 | if (tmp < 0) |
386 | err = -EFAULT; | 373 | err = -EFAULT; |
387 | else { | 374 | else { |
@@ -402,7 +389,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
402 | * Determine which stack to use.. | 389 | * Determine which stack to use.. |
403 | */ | 390 | */ |
404 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 391 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
405 | size_t frame_size) | 392 | size_t frame_size, |
393 | void **fpstate) | ||
406 | { | 394 | { |
407 | unsigned long sp; | 395 | unsigned long sp; |
408 | 396 | ||
@@ -421,6 +409,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
421 | ka->sa.sa_restorer) | 409 | ka->sa.sa_restorer) |
422 | sp = (unsigned long) ka->sa.sa_restorer; | 410 | sp = (unsigned long) ka->sa.sa_restorer; |
423 | 411 | ||
412 | if (used_math()) { | ||
413 | sp = sp - sig_xstate_ia32_size; | ||
414 | *fpstate = (struct _fpstate_ia32 *) sp; | ||
415 | } | ||
416 | |||
424 | sp -= frame_size; | 417 | sp -= frame_size; |
425 | /* Align the stack pointer according to the i386 ABI, | 418 | /* Align the stack pointer according to the i386 ABI, |
426 | * i.e. so that on function entry ((sp + 4) & 15) == 0. */ | 419 | * i.e. so that on function entry ((sp + 4) & 15) == 0. */ |
@@ -434,6 +427,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
434 | struct sigframe __user *frame; | 427 | struct sigframe __user *frame; |
435 | void __user *restorer; | 428 | void __user *restorer; |
436 | int err = 0; | 429 | int err = 0; |
430 | void __user *fpstate = NULL; | ||
437 | 431 | ||
438 | /* copy_to_user optimizes that into a single 8 byte store */ | 432 | /* copy_to_user optimizes that into a single 8 byte store */ |
439 | static const struct { | 433 | static const struct { |
@@ -448,7 +442,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
448 | 0, | 442 | 0, |
449 | }; | 443 | }; |
450 | 444 | ||
451 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 445 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
452 | 446 | ||
453 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 447 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
454 | goto give_sigsegv; | 448 | goto give_sigsegv; |
@@ -457,8 +451,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
457 | if (err) | 451 | if (err) |
458 | goto give_sigsegv; | 452 | goto give_sigsegv; |
459 | 453 | ||
460 | err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, | 454 | err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); |
461 | set->sig[0]); | ||
462 | if (err) | 455 | if (err) |
463 | goto give_sigsegv; | 456 | goto give_sigsegv; |
464 | 457 | ||
@@ -522,6 +515,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
522 | struct rt_sigframe __user *frame; | 515 | struct rt_sigframe __user *frame; |
523 | void __user *restorer; | 516 | void __user *restorer; |
524 | int err = 0; | 517 | int err = 0; |
518 | void __user *fpstate = NULL; | ||
525 | 519 | ||
526 | /* __copy_to_user optimizes that into a single 8 byte store */ | 520 | /* __copy_to_user optimizes that into a single 8 byte store */ |
527 | static const struct { | 521 | static const struct { |
@@ -537,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
537 | 0, | 531 | 0, |
538 | }; | 532 | }; |
539 | 533 | ||
540 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 534 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
541 | 535 | ||
542 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 536 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
543 | goto give_sigsegv; | 537 | goto give_sigsegv; |
@@ -550,13 +544,16 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
550 | goto give_sigsegv; | 544 | goto give_sigsegv; |
551 | 545 | ||
552 | /* Create the ucontext. */ | 546 | /* Create the ucontext. */ |
553 | 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); | ||
554 | err |= __put_user(0, &frame->uc.uc_link); | 551 | err |= __put_user(0, &frame->uc.uc_link); |
555 | 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); |
556 | err |= __put_user(sas_ss_flags(regs->sp), | 553 | err |= __put_user(sas_ss_flags(regs->sp), |
557 | &frame->uc.uc_stack.ss_flags); | 554 | &frame->uc.uc_stack.ss_flags); |
558 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 555 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
559 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 556 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
560 | regs, set->sig[0]); | 557 | regs, set->sig[0]); |
561 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 558 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
562 | if (err) | 559 | if (err) |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index dac24c4390dd..c9be69fedb70 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -38,7 +38,7 @@ obj-y += tsc.o io_delay.o rtc.o | |||
38 | 38 | ||
39 | obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o | 39 | obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o |
40 | obj-y += process.o | 40 | obj-y += process.o |
41 | obj-y += i387.o | 41 | obj-y += i387.o xsave.o |
42 | obj-y += ptrace.o | 42 | obj-y += ptrace.o |
43 | obj-y += ds.o | 43 | obj-y += ds.o |
44 | obj-$(CONFIG_X86_32) += tls.o | 44 | obj-$(CONFIG_X86_32) += tls.o |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 0785b3c8d043..c63ec65f484c 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -739,9 +739,20 @@ void __cpuinit cpu_init(void) | |||
739 | /* | 739 | /* |
740 | * Force FPU initialization: | 740 | * Force FPU initialization: |
741 | */ | 741 | */ |
742 | current_thread_info()->status = 0; | 742 | if (cpu_has_xsave) |
743 | current_thread_info()->status = TS_XSAVE; | ||
744 | else | ||
745 | current_thread_info()->status = 0; | ||
743 | clear_used_math(); | 746 | clear_used_math(); |
744 | mxcsr_feature_mask_init(); | 747 | mxcsr_feature_mask_init(); |
748 | |||
749 | /* | ||
750 | * Boot processor to setup the FP and extended state context info. | ||
751 | */ | ||
752 | if (!smp_processor_id()) | ||
753 | init_thread_xstate(); | ||
754 | |||
755 | xsave_init(); | ||
745 | } | 756 | } |
746 | 757 | ||
747 | #ifdef CONFIG_HOTPLUG_CPU | 758 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index eb9ddd8efb82..45723f1fe198 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -21,9 +21,12 @@ | |||
21 | # include <asm/sigcontext32.h> | 21 | # include <asm/sigcontext32.h> |
22 | # include <asm/user32.h> | 22 | # include <asm/user32.h> |
23 | #else | 23 | #else |
24 | # define save_i387_ia32 save_i387 | 24 | # define save_i387_xstate_ia32 save_i387_xstate |
25 | # define restore_i387_ia32 restore_i387 | 25 | # define restore_i387_xstate_ia32 restore_i387_xstate |
26 | # define _fpstate_ia32 _fpstate | 26 | # define _fpstate_ia32 _fpstate |
27 | # define _xstate_ia32 _xstate | ||
28 | # define sig_xstate_ia32_size sig_xstate_size | ||
29 | # define fx_sw_reserved_ia32 fx_sw_reserved | ||
27 | # define user_i387_ia32_struct user_i387_struct | 30 | # define user_i387_ia32_struct user_i387_struct |
28 | # define user32_fxsr_struct user_fxsr_struct | 31 | # define user32_fxsr_struct user_fxsr_struct |
29 | #endif | 32 | #endif |
@@ -36,6 +39,7 @@ | |||
36 | 39 | ||
37 | static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; | 40 | static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; |
38 | unsigned int xstate_size; | 41 | unsigned int xstate_size; |
42 | unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); | ||
39 | static struct i387_fxsave_struct fx_scratch __cpuinitdata; | 43 | static struct i387_fxsave_struct fx_scratch __cpuinitdata; |
40 | 44 | ||
41 | void __cpuinit mxcsr_feature_mask_init(void) | 45 | void __cpuinit mxcsr_feature_mask_init(void) |
@@ -61,6 +65,11 @@ void __init init_thread_xstate(void) | |||
61 | return; | 65 | return; |
62 | } | 66 | } |
63 | 67 | ||
68 | if (cpu_has_xsave) { | ||
69 | xsave_cntxt_init(); | ||
70 | return; | ||
71 | } | ||
72 | |||
64 | if (cpu_has_fxsr) | 73 | if (cpu_has_fxsr) |
65 | xstate_size = sizeof(struct i387_fxsave_struct); | 74 | xstate_size = sizeof(struct i387_fxsave_struct); |
66 | #ifdef CONFIG_X86_32 | 75 | #ifdef CONFIG_X86_32 |
@@ -83,9 +92,19 @@ void __cpuinit fpu_init(void) | |||
83 | 92 | ||
84 | write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */ | 93 | write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */ |
85 | 94 | ||
95 | /* | ||
96 | * Boot processor to setup the FP and extended state context info. | ||
97 | */ | ||
98 | if (!smp_processor_id()) | ||
99 | init_thread_xstate(); | ||
100 | xsave_init(); | ||
101 | |||
86 | mxcsr_feature_mask_init(); | 102 | mxcsr_feature_mask_init(); |
87 | /* clean state in init */ | 103 | /* clean state in init */ |
88 | current_thread_info()->status = 0; | 104 | if (cpu_has_xsave) |
105 | current_thread_info()->status = TS_XSAVE; | ||
106 | else | ||
107 | current_thread_info()->status = 0; | ||
89 | clear_used_math(); | 108 | clear_used_math(); |
90 | } | 109 | } |
91 | #endif /* CONFIG_X86_64 */ | 110 | #endif /* CONFIG_X86_64 */ |
@@ -195,6 +214,13 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
195 | */ | 214 | */ |
196 | target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; | 215 | target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; |
197 | 216 | ||
217 | /* | ||
218 | * update the header bits in the xsave header, indicating the | ||
219 | * presence of FP and SSE state. | ||
220 | */ | ||
221 | if (cpu_has_xsave) | ||
222 | target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; | ||
223 | |||
198 | return ret; | 224 | return ret; |
199 | } | 225 | } |
200 | 226 | ||
@@ -395,6 +421,12 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
395 | if (!ret) | 421 | if (!ret) |
396 | convert_to_fxsr(target, &env); | 422 | convert_to_fxsr(target, &env); |
397 | 423 | ||
424 | /* | ||
425 | * update the header bit in the xsave header, indicating the | ||
426 | * presence of FP. | ||
427 | */ | ||
428 | if (cpu_has_xsave) | ||
429 | target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP; | ||
398 | return ret; | 430 | return ret; |
399 | } | 431 | } |
400 | 432 | ||
@@ -407,7 +439,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) | |||
407 | struct task_struct *tsk = current; | 439 | struct task_struct *tsk = current; |
408 | struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; | 440 | struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; |
409 | 441 | ||
410 | unlazy_fpu(tsk); | ||
411 | fp->status = fp->swd; | 442 | fp->status = fp->swd; |
412 | if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) | 443 | if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) |
413 | return -1; | 444 | return -1; |
@@ -421,8 +452,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) | |||
421 | struct user_i387_ia32_struct env; | 452 | struct user_i387_ia32_struct env; |
422 | int err = 0; | 453 | int err = 0; |
423 | 454 | ||
424 | unlazy_fpu(tsk); | ||
425 | |||
426 | convert_from_fxsr(&env, tsk); | 455 | convert_from_fxsr(&env, tsk); |
427 | if (__copy_to_user(buf, &env, sizeof(env))) | 456 | if (__copy_to_user(buf, &env, sizeof(env))) |
428 | return -1; | 457 | return -1; |
@@ -432,16 +461,40 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) | |||
432 | if (err) | 461 | if (err) |
433 | return -1; | 462 | return -1; |
434 | 463 | ||
435 | if (__copy_to_user(&buf->_fxsr_env[0], fx, | 464 | if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size)) |
436 | sizeof(struct i387_fxsave_struct))) | ||
437 | return -1; | 465 | return -1; |
438 | return 1; | 466 | return 1; |
439 | } | 467 | } |
440 | 468 | ||
441 | int save_i387_ia32(struct _fpstate_ia32 __user *buf) | 469 | static int save_i387_xsave(void __user *buf) |
470 | { | ||
471 | struct _fpstate_ia32 __user *fx = buf; | ||
472 | int err = 0; | ||
473 | |||
474 | if (save_i387_fxsave(fx) < 0) | ||
475 | return -1; | ||
476 | |||
477 | err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32, | ||
478 | sizeof(struct _fpx_sw_bytes)); | ||
479 | err |= __put_user(FP_XSTATE_MAGIC2, | ||
480 | (__u32 __user *) (buf + sig_xstate_ia32_size | ||
481 | - FP_XSTATE_MAGIC2_SIZE)); | ||
482 | if (err) | ||
483 | return -1; | ||
484 | |||
485 | return 1; | ||
486 | } | ||
487 | |||
488 | int save_i387_xstate_ia32(void __user *buf) | ||
442 | { | 489 | { |
490 | struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; | ||
491 | struct task_struct *tsk = current; | ||
492 | |||
443 | if (!used_math()) | 493 | if (!used_math()) |
444 | return 0; | 494 | return 0; |
495 | |||
496 | if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size)) | ||
497 | return -EACCES; | ||
445 | /* | 498 | /* |
446 | * This will cause a "finit" to be triggered by the next | 499 | * This will cause a "finit" to be triggered by the next |
447 | * attempted FPU operation by the 'current' process. | 500 | * attempted FPU operation by the 'current' process. |
@@ -451,13 +504,17 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf) | |||
451 | if (!HAVE_HWFP) { | 504 | if (!HAVE_HWFP) { |
452 | return fpregs_soft_get(current, NULL, | 505 | return fpregs_soft_get(current, NULL, |
453 | 0, sizeof(struct user_i387_ia32_struct), | 506 | 0, sizeof(struct user_i387_ia32_struct), |
454 | NULL, buf) ? -1 : 1; | 507 | NULL, fp) ? -1 : 1; |
455 | } | 508 | } |
456 | 509 | ||
510 | unlazy_fpu(tsk); | ||
511 | |||
512 | if (cpu_has_xsave) | ||
513 | return save_i387_xsave(fp); | ||
457 | if (cpu_has_fxsr) | 514 | if (cpu_has_fxsr) |
458 | return save_i387_fxsave(buf); | 515 | return save_i387_fxsave(fp); |
459 | else | 516 | else |
460 | return save_i387_fsave(buf); | 517 | return save_i387_fsave(fp); |
461 | } | 518 | } |
462 | 519 | ||
463 | static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) | 520 | static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) |
@@ -468,14 +525,15 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) | |||
468 | sizeof(struct i387_fsave_struct)); | 525 | sizeof(struct i387_fsave_struct)); |
469 | } | 526 | } |
470 | 527 | ||
471 | static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) | 528 | static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf, |
529 | unsigned int size) | ||
472 | { | 530 | { |
473 | struct task_struct *tsk = current; | 531 | struct task_struct *tsk = current; |
474 | struct user_i387_ia32_struct env; | 532 | struct user_i387_ia32_struct env; |
475 | int err; | 533 | int err; |
476 | 534 | ||
477 | err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], | 535 | err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], |
478 | sizeof(struct i387_fxsave_struct)); | 536 | size); |
479 | /* mxcsr reserved bits must be masked to zero for security reasons */ | 537 | /* mxcsr reserved bits must be masked to zero for security reasons */ |
480 | tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; | 538 | tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; |
481 | if (err || __copy_from_user(&env, buf, sizeof(env))) | 539 | if (err || __copy_from_user(&env, buf, sizeof(env))) |
@@ -485,14 +543,69 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) | |||
485 | return 0; | 543 | return 0; |
486 | } | 544 | } |
487 | 545 | ||
488 | int restore_i387_ia32(struct _fpstate_ia32 __user *buf) | 546 | static int restore_i387_xsave(void __user *buf) |
547 | { | ||
548 | struct _fpx_sw_bytes fx_sw_user; | ||
549 | struct _fpstate_ia32 __user *fx_user = | ||
550 | ((struct _fpstate_ia32 __user *) buf); | ||
551 | struct i387_fxsave_struct __user *fx = | ||
552 | (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0]; | ||
553 | struct xsave_hdr_struct *xsave_hdr = | ||
554 | ¤t->thread.xstate->xsave.xsave_hdr; | ||
555 | u64 mask; | ||
556 | int err; | ||
557 | |||
558 | if (check_for_xstate(fx, buf, &fx_sw_user)) | ||
559 | goto fx_only; | ||
560 | |||
561 | mask = fx_sw_user.xstate_bv; | ||
562 | |||
563 | err = restore_i387_fxsave(buf, fx_sw_user.xstate_size); | ||
564 | |||
565 | xsave_hdr->xstate_bv &= pcntxt_mask; | ||
566 | /* | ||
567 | * These bits must be zero. | ||
568 | */ | ||
569 | xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; | ||
570 | |||
571 | /* | ||
572 | * Init the state that is not present in the memory layout | ||
573 | * and enabled by the OS. | ||
574 | */ | ||
575 | mask = ~(pcntxt_mask & ~mask); | ||
576 | xsave_hdr->xstate_bv &= mask; | ||
577 | |||
578 | return err; | ||
579 | fx_only: | ||
580 | /* | ||
581 | * Couldn't find the extended state information in the memory | ||
582 | * layout. Restore the FP/SSE and init the other extended state | ||
583 | * enabled by the OS. | ||
584 | */ | ||
585 | xsave_hdr->xstate_bv = XSTATE_FPSSE; | ||
586 | return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct)); | ||
587 | } | ||
588 | |||
589 | int restore_i387_xstate_ia32(void __user *buf) | ||
489 | { | 590 | { |
490 | int err; | 591 | int err; |
491 | struct task_struct *tsk = current; | 592 | struct task_struct *tsk = current; |
593 | struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; | ||
492 | 594 | ||
493 | if (HAVE_HWFP) | 595 | if (HAVE_HWFP) |
494 | clear_fpu(tsk); | 596 | clear_fpu(tsk); |
495 | 597 | ||
598 | if (!buf) { | ||
599 | if (used_math()) { | ||
600 | clear_fpu(tsk); | ||
601 | clear_used_math(); | ||
602 | } | ||
603 | |||
604 | return 0; | ||
605 | } else | ||
606 | if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size)) | ||
607 | return -EACCES; | ||
608 | |||
496 | if (!used_math()) { | 609 | if (!used_math()) { |
497 | err = init_fpu(tsk); | 610 | err = init_fpu(tsk); |
498 | if (err) | 611 | if (err) |
@@ -500,14 +613,17 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf) | |||
500 | } | 613 | } |
501 | 614 | ||
502 | if (HAVE_HWFP) { | 615 | if (HAVE_HWFP) { |
503 | if (cpu_has_fxsr) | 616 | if (cpu_has_xsave) |
504 | err = restore_i387_fxsave(buf); | 617 | err = restore_i387_xsave(buf); |
618 | else if (cpu_has_fxsr) | ||
619 | err = restore_i387_fxsave(fp, sizeof(struct | ||
620 | i387_fxsave_struct)); | ||
505 | else | 621 | else |
506 | err = restore_i387_fsave(buf); | 622 | err = restore_i387_fsave(fp); |
507 | } else { | 623 | } else { |
508 | err = fpregs_soft_set(current, NULL, | 624 | err = fpregs_soft_set(current, NULL, |
509 | 0, sizeof(struct user_i387_ia32_struct), | 625 | 0, sizeof(struct user_i387_ia32_struct), |
510 | NULL, buf) != 0; | 626 | NULL, fp) != 0; |
511 | } | 627 | } |
512 | set_used_math(); | 628 | set_used_math(); |
513 | 629 | ||
diff --git a/arch/x86/kernel/sigframe.h b/arch/x86/kernel/sigframe.h index 72bbb519d2dc..6dd7e2b70a4b 100644 --- a/arch/x86/kernel/sigframe.h +++ b/arch/x86/kernel/sigframe.h | |||
@@ -3,9 +3,18 @@ struct sigframe { | |||
3 | char __user *pretcode; | 3 | char __user *pretcode; |
4 | int sig; | 4 | int sig; |
5 | struct sigcontext sc; | 5 | struct sigcontext sc; |
6 | struct _fpstate fpstate; | 6 | /* |
7 | * fpstate is unused. fpstate is moved/allocated after | ||
8 | * retcode[] below. This movement allows to have the FP state and the | ||
9 | * future state extensions (xsave) stay together. | ||
10 | * And at the same time retaining the unused fpstate, prevents changing | ||
11 | * the offset of extramask[] in the sigframe and thus prevent any | ||
12 | * legacy application accessing/modifying it. | ||
13 | */ | ||
14 | struct _fpstate fpstate_unused; | ||
7 | unsigned long extramask[_NSIG_WORDS-1]; | 15 | unsigned long extramask[_NSIG_WORDS-1]; |
8 | char retcode[8]; | 16 | char retcode[8]; |
17 | /* fp state follows here */ | ||
9 | }; | 18 | }; |
10 | 19 | ||
11 | struct rt_sigframe { | 20 | struct rt_sigframe { |
@@ -15,13 +24,14 @@ struct rt_sigframe { | |||
15 | void __user *puc; | 24 | void __user *puc; |
16 | struct siginfo info; | 25 | struct siginfo info; |
17 | struct ucontext uc; | 26 | struct ucontext uc; |
18 | struct _fpstate fpstate; | ||
19 | char retcode[8]; | 27 | char retcode[8]; |
28 | /* fp state follows here */ | ||
20 | }; | 29 | }; |
21 | #else | 30 | #else |
22 | struct rt_sigframe { | 31 | struct rt_sigframe { |
23 | char __user *pretcode; | 32 | char __user *pretcode; |
24 | struct ucontext uc; | 33 | struct ucontext uc; |
25 | struct siginfo info; | 34 | struct siginfo info; |
35 | /* fp state follows here */ | ||
26 | }; | 36 | }; |
27 | #endif | 37 | #endif |
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 0c727f64e79b..8d380b699c0c 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -160,28 +160,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
160 | } | 160 | } |
161 | 161 | ||
162 | { | 162 | { |
163 | struct _fpstate __user *buf; | 163 | void __user *buf; |
164 | 164 | ||
165 | err |= __get_user(buf, &sc->fpstate); | 165 | err |= __get_user(buf, &sc->fpstate); |
166 | if (buf) { | 166 | err |= restore_i387_xstate(buf); |
167 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
168 | goto badframe; | ||
169 | err |= restore_i387(buf); | ||
170 | } else { | ||
171 | struct task_struct *me = current; | ||
172 | |||
173 | if (used_math()) { | ||
174 | clear_fpu(me); | ||
175 | clear_used_math(); | ||
176 | } | ||
177 | } | ||
178 | } | 167 | } |
179 | 168 | ||
180 | err |= __get_user(*pax, &sc->ax); | 169 | err |= __get_user(*pax, &sc->ax); |
181 | return err; | 170 | return err; |
182 | |||
183 | badframe: | ||
184 | return 1; | ||
185 | } | 171 | } |
186 | 172 | ||
187 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 173 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) |
@@ -263,7 +249,7 @@ badframe: | |||
263 | * Set up a signal frame. | 249 | * Set up a signal frame. |
264 | */ | 250 | */ |
265 | static int | 251 | static int |
266 | setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | 252 | setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, |
267 | struct pt_regs *regs, unsigned long mask) | 253 | struct pt_regs *regs, unsigned long mask) |
268 | { | 254 | { |
269 | int tmp, err = 0; | 255 | int tmp, err = 0; |
@@ -290,7 +276,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
290 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 276 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
291 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 277 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); |
292 | 278 | ||
293 | tmp = save_i387(fpstate); | 279 | tmp = save_i387_xstate(fpstate); |
294 | if (tmp < 0) | 280 | if (tmp < 0) |
295 | err = 1; | 281 | err = 1; |
296 | else | 282 | else |
@@ -307,7 +293,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
307 | * Determine which stack to use.. | 293 | * Determine which stack to use.. |
308 | */ | 294 | */ |
309 | static inline void __user * | 295 | static inline void __user * |
310 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 296 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
297 | void **fpstate) | ||
311 | { | 298 | { |
312 | unsigned long sp; | 299 | unsigned long sp; |
313 | 300 | ||
@@ -333,6 +320,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
333 | sp = (unsigned long) ka->sa.sa_restorer; | 320 | sp = (unsigned long) ka->sa.sa_restorer; |
334 | } | 321 | } |
335 | 322 | ||
323 | if (used_math()) { | ||
324 | sp = sp - sig_xstate_size; | ||
325 | *fpstate = (struct _fpstate *) sp; | ||
326 | } | ||
327 | |||
336 | sp -= frame_size; | 328 | sp -= frame_size; |
337 | /* | 329 | /* |
338 | * Align the stack pointer according to the i386 ABI, | 330 | * Align the stack pointer according to the i386 ABI, |
@@ -351,8 +343,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
351 | void __user *restorer; | 343 | void __user *restorer; |
352 | int err = 0; | 344 | int err = 0; |
353 | int usig; | 345 | int usig; |
346 | void __user *fpstate = NULL; | ||
354 | 347 | ||
355 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 348 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
356 | 349 | ||
357 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 350 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
358 | goto give_sigsegv; | 351 | goto give_sigsegv; |
@@ -367,7 +360,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
367 | if (err) | 360 | if (err) |
368 | goto give_sigsegv; | 361 | goto give_sigsegv; |
369 | 362 | ||
370 | err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); | 363 | err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); |
371 | if (err) | 364 | if (err) |
372 | goto give_sigsegv; | 365 | goto give_sigsegv; |
373 | 366 | ||
@@ -428,8 +421,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
428 | void __user *restorer; | 421 | void __user *restorer; |
429 | int err = 0; | 422 | int err = 0; |
430 | int usig; | 423 | int usig; |
424 | void __user *fpstate = NULL; | ||
431 | 425 | ||
432 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 426 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
433 | 427 | ||
434 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 428 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
435 | goto give_sigsegv; | 429 | goto give_sigsegv; |
@@ -448,13 +442,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
448 | goto give_sigsegv; | 442 | goto give_sigsegv; |
449 | 443 | ||
450 | /* Create the ucontext. */ | 444 | /* Create the ucontext. */ |
451 | err |= __put_user(0, &frame->uc.uc_flags); | 445 | if (cpu_has_xsave) |
446 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
447 | else | ||
448 | err |= __put_user(0, &frame->uc.uc_flags); | ||
452 | err |= __put_user(0, &frame->uc.uc_link); | 449 | err |= __put_user(0, &frame->uc.uc_link); |
453 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 450 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
454 | err |= __put_user(sas_ss_flags(regs->sp), | 451 | err |= __put_user(sas_ss_flags(regs->sp), |
455 | &frame->uc.uc_stack.ss_flags); | 452 | &frame->uc.uc_stack.ss_flags); |
456 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 453 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
457 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 454 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
458 | regs, set->sig[0]); | 455 | regs, set->sig[0]); |
459 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 456 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
460 | if (err) | 457 | if (err) |
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 2f1464050059..4665b598a376 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -55,69 +55,6 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
55 | } | 55 | } |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * Signal frame handlers. | ||
59 | */ | ||
60 | |||
61 | static inline int save_i387(struct _fpstate __user *buf) | ||
62 | { | ||
63 | struct task_struct *tsk = current; | ||
64 | int err = 0; | ||
65 | |||
66 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != | ||
67 | sizeof(tsk->thread.xstate->fxsave)); | ||
68 | |||
69 | if ((unsigned long)buf % 16) | ||
70 | printk("save_i387: bad fpstate %p\n", buf); | ||
71 | |||
72 | if (!used_math()) | ||
73 | return 0; | ||
74 | clear_used_math(); /* trigger finit */ | ||
75 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | ||
76 | err = save_i387_checking((struct i387_fxsave_struct __user *) | ||
77 | buf); | ||
78 | if (err) | ||
79 | return err; | ||
80 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | ||
81 | stts(); | ||
82 | } else { | ||
83 | if (__copy_to_user(buf, &tsk->thread.xstate->fxsave, | ||
84 | sizeof(struct i387_fxsave_struct))) | ||
85 | return -1; | ||
86 | } | ||
87 | return 1; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * This restores directly out of user space. Exceptions are handled. | ||
92 | */ | ||
93 | static inline int restore_i387(struct _fpstate __user *buf) | ||
94 | { | ||
95 | struct task_struct *tsk = current; | ||
96 | int err; | ||
97 | |||
98 | if (!used_math()) { | ||
99 | err = init_fpu(tsk); | ||
100 | if (err) | ||
101 | return err; | ||
102 | } | ||
103 | |||
104 | if (!(task_thread_info(current)->status & TS_USEDFPU)) { | ||
105 | clts(); | ||
106 | task_thread_info(current)->status |= TS_USEDFPU; | ||
107 | } | ||
108 | err = restore_fpu_checking((__force struct i387_fxsave_struct *)buf); | ||
109 | if (unlikely(err)) { | ||
110 | /* | ||
111 | * Encountered an error while doing the restore from the | ||
112 | * user buffer, clear the fpu state. | ||
113 | */ | ||
114 | clear_fpu(tsk); | ||
115 | clear_used_math(); | ||
116 | } | ||
117 | return err; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Do a signal return; undo the signal stack. | 58 | * Do a signal return; undo the signal stack. |
122 | */ | 59 | */ |
123 | static int | 60 | static int |
@@ -161,25 +98,11 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
161 | { | 98 | { |
162 | struct _fpstate __user * buf; | 99 | struct _fpstate __user * buf; |
163 | err |= __get_user(buf, &sc->fpstate); | 100 | err |= __get_user(buf, &sc->fpstate); |
164 | 101 | err |= restore_i387_xstate(buf); | |
165 | if (buf) { | ||
166 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
167 | goto badframe; | ||
168 | err |= restore_i387(buf); | ||
169 | } else { | ||
170 | struct task_struct *me = current; | ||
171 | if (used_math()) { | ||
172 | clear_fpu(me); | ||
173 | clear_used_math(); | ||
174 | } | ||
175 | } | ||
176 | } | 102 | } |
177 | 103 | ||
178 | err |= __get_user(*pax, &sc->ax); | 104 | err |= __get_user(*pax, &sc->ax); |
179 | return err; | 105 | return err; |
180 | |||
181 | badframe: | ||
182 | return 1; | ||
183 | } | 106 | } |
184 | 107 | ||
185 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | 108 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) |
@@ -270,26 +193,23 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) | |||
270 | sp = current->sas_ss_sp + current->sas_ss_size; | 193 | sp = current->sas_ss_sp + current->sas_ss_size; |
271 | } | 194 | } |
272 | 195 | ||
273 | return (void __user *)round_down(sp - size, 16); | 196 | return (void __user *)round_down(sp - size, 64); |
274 | } | 197 | } |
275 | 198 | ||
276 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 199 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
277 | sigset_t *set, struct pt_regs * regs) | 200 | sigset_t *set, struct pt_regs * regs) |
278 | { | 201 | { |
279 | struct rt_sigframe __user *frame; | 202 | struct rt_sigframe __user *frame; |
280 | struct _fpstate __user *fp = NULL; | 203 | void __user *fp = NULL; |
281 | int err = 0; | 204 | int err = 0; |
282 | struct task_struct *me = current; | 205 | struct task_struct *me = current; |
283 | 206 | ||
284 | if (used_math()) { | 207 | if (used_math()) { |
285 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); | 208 | fp = get_stack(ka, regs, sig_xstate_size); |
286 | frame = (void __user *)round_down( | 209 | frame = (void __user *)round_down( |
287 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | 210 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
288 | 211 | ||
289 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) | 212 | if (save_i387_xstate(fp) < 0) |
290 | goto give_sigsegv; | ||
291 | |||
292 | if (save_i387(fp) < 0) | ||
293 | err |= -1; | 213 | err |= -1; |
294 | } else | 214 | } else |
295 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; | 215 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
@@ -304,7 +224,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
304 | } | 224 | } |
305 | 225 | ||
306 | /* Create the ucontext. */ | 226 | /* Create the ucontext. */ |
307 | err |= __put_user(0, &frame->uc.uc_flags); | 227 | if (cpu_has_xsave) |
228 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
229 | else | ||
230 | err |= __put_user(0, &frame->uc.uc_flags); | ||
308 | err |= __put_user(0, &frame->uc.uc_link); | 231 | err |= __put_user(0, &frame->uc.uc_link); |
309 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 232 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
310 | err |= __put_user(sas_ss_flags(regs->sp), | 233 | err |= __put_user(sas_ss_flags(regs->sp), |
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 03df8e45e5a1..da5a5964fccb 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -1228,7 +1228,6 @@ void __init trap_init(void) | |||
1228 | 1228 | ||
1229 | set_bit(SYSCALL_VECTOR, used_vectors); | 1229 | set_bit(SYSCALL_VECTOR, used_vectors); |
1230 | 1230 | ||
1231 | init_thread_xstate(); | ||
1232 | /* | 1231 | /* |
1233 | * Should be a barrier for any external CPU state: | 1232 | * Should be a barrier for any external CPU state: |
1234 | */ | 1233 | */ |
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 513caaca7115..38eb76156a47 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c | |||
@@ -1134,7 +1134,7 @@ asmlinkage void math_state_restore(void) | |||
1134 | /* | 1134 | /* |
1135 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | 1135 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. |
1136 | */ | 1136 | */ |
1137 | if (unlikely(restore_fpu_checking(&me->thread.xstate->fxsave))) { | 1137 | if (unlikely(restore_fpu_checking(me))) { |
1138 | stts(); | 1138 | stts(); |
1139 | force_sig(SIGSEGV, me); | 1139 | force_sig(SIGSEGV, me); |
1140 | return; | 1140 | return; |
@@ -1173,10 +1173,6 @@ void __init trap_init(void) | |||
1173 | set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall); | 1173 | set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall); |
1174 | #endif | 1174 | #endif |
1175 | /* | 1175 | /* |
1176 | * initialize the per thread extended state: | ||
1177 | */ | ||
1178 | init_thread_xstate(); | ||
1179 | /* | ||
1180 | * Should be a barrier for any external CPU state: | 1176 | * Should be a barrier for any external CPU state: |
1181 | */ | 1177 | */ |
1182 | cpu_init(); | 1178 | cpu_init(); |
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c new file mode 100644 index 000000000000..07713d64debe --- /dev/null +++ b/arch/x86/kernel/xsave.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * xsave/xrstor support. | ||
3 | * | ||
4 | * Author: Suresh Siddha <suresh.b.siddha@intel.com> | ||
5 | */ | ||
6 | #include <linux/bootmem.h> | ||
7 | #include <linux/compat.h> | ||
8 | #include <asm/i387.h> | ||
9 | #ifdef CONFIG_IA32_EMULATION | ||
10 | #include <asm/sigcontext32.h> | ||
11 | #endif | ||
12 | #include <asm/xcr.h> | ||
13 | |||
14 | /* | ||
15 | * Supported feature mask by the CPU and the kernel. | ||
16 | */ | ||
17 | u64 pcntxt_mask; | ||
18 | |||
19 | struct _fpx_sw_bytes fx_sw_reserved; | ||
20 | #ifdef CONFIG_IA32_EMULATION | ||
21 | struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
22 | #endif | ||
23 | |||
24 | /* | ||
25 | * Check for the presence of extended state information in the | ||
26 | * user fpstate pointer in the sigcontext. | ||
27 | */ | ||
28 | int check_for_xstate(struct i387_fxsave_struct __user *buf, | ||
29 | void __user *fpstate, | ||
30 | struct _fpx_sw_bytes *fx_sw_user) | ||
31 | { | ||
32 | int min_xstate_size = sizeof(struct i387_fxsave_struct) + | ||
33 | sizeof(struct xsave_hdr_struct); | ||
34 | unsigned int magic2; | ||
35 | int err; | ||
36 | |||
37 | err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0], | ||
38 | sizeof(struct _fpx_sw_bytes)); | ||
39 | |||
40 | if (err) | ||
41 | return err; | ||
42 | |||
43 | /* | ||
44 | * First Magic check failed. | ||
45 | */ | ||
46 | if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1) | ||
47 | return -1; | ||
48 | |||
49 | /* | ||
50 | * Check for error scenarios. | ||
51 | */ | ||
52 | if (fx_sw_user->xstate_size < min_xstate_size || | ||
53 | fx_sw_user->xstate_size > xstate_size || | ||
54 | fx_sw_user->xstate_size > fx_sw_user->extended_size) | ||
55 | return -1; | ||
56 | |||
57 | err = __get_user(magic2, (__u32 *) (((void *)fpstate) + | ||
58 | fx_sw_user->extended_size - | ||
59 | FP_XSTATE_MAGIC2_SIZE)); | ||
60 | /* | ||
61 | * Check for the presence of second magic word at the end of memory | ||
62 | * layout. This detects the case where the user just copied the legacy | ||
63 | * fpstate layout with out copying the extended state information | ||
64 | * in the memory layout. | ||
65 | */ | ||
66 | if (err || magic2 != FP_XSTATE_MAGIC2) | ||
67 | return -1; | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | #ifdef CONFIG_X86_64 | ||
73 | /* | ||
74 | * Signal frame handlers. | ||
75 | */ | ||
76 | |||
77 | int save_i387_xstate(void __user *buf) | ||
78 | { | ||
79 | struct task_struct *tsk = current; | ||
80 | int err = 0; | ||
81 | |||
82 | if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size)) | ||
83 | return -EACCES; | ||
84 | |||
85 | BUG_ON(sig_xstate_size < xstate_size); | ||
86 | |||
87 | if ((unsigned long)buf % 64) | ||
88 | printk("save_i387_xstate: bad fpstate %p\n", buf); | ||
89 | |||
90 | if (!used_math()) | ||
91 | return 0; | ||
92 | clear_used_math(); /* trigger finit */ | ||
93 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | ||
94 | /* | ||
95 | * Start with clearing the user buffer. This will present a | ||
96 | * clean context for the bytes not touched by the fxsave/xsave. | ||
97 | */ | ||
98 | __clear_user(buf, sig_xstate_size); | ||
99 | |||
100 | if (task_thread_info(tsk)->status & TS_XSAVE) | ||
101 | err = xsave_user(buf); | ||
102 | else | ||
103 | err = fxsave_user(buf); | ||
104 | |||
105 | if (err) | ||
106 | return err; | ||
107 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | ||
108 | stts(); | ||
109 | } else { | ||
110 | if (__copy_to_user(buf, &tsk->thread.xstate->fxsave, | ||
111 | xstate_size)) | ||
112 | return -1; | ||
113 | } | ||
114 | |||
115 | if (task_thread_info(tsk)->status & TS_XSAVE) { | ||
116 | struct _fpstate __user *fx = buf; | ||
117 | |||
118 | err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved, | ||
119 | sizeof(struct _fpx_sw_bytes)); | ||
120 | |||
121 | err |= __put_user(FP_XSTATE_MAGIC2, | ||
122 | (__u32 __user *) (buf + sig_xstate_size | ||
123 | - FP_XSTATE_MAGIC2_SIZE)); | ||
124 | } | ||
125 | |||
126 | return 1; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Restore the extended state if present. Otherwise, restore the FP/SSE | ||
131 | * state. | ||
132 | */ | ||
133 | int restore_user_xstate(void __user *buf) | ||
134 | { | ||
135 | struct _fpx_sw_bytes fx_sw_user; | ||
136 | u64 mask; | ||
137 | int err; | ||
138 | |||
139 | if (((unsigned long)buf % 64) || | ||
140 | check_for_xstate(buf, buf, &fx_sw_user)) | ||
141 | goto fx_only; | ||
142 | |||
143 | mask = fx_sw_user.xstate_bv; | ||
144 | |||
145 | /* | ||
146 | * restore the state passed by the user. | ||
147 | */ | ||
148 | err = xrestore_user(buf, mask); | ||
149 | if (err) | ||
150 | return err; | ||
151 | |||
152 | /* | ||
153 | * init the state skipped by the user. | ||
154 | */ | ||
155 | mask = pcntxt_mask & ~mask; | ||
156 | |||
157 | xrstor_state(init_xstate_buf, mask); | ||
158 | |||
159 | return 0; | ||
160 | |||
161 | fx_only: | ||
162 | /* | ||
163 | * couldn't find the extended state information in the | ||
164 | * memory layout. Restore just the FP/SSE and init all | ||
165 | * the other extended state. | ||
166 | */ | ||
167 | xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE); | ||
168 | return fxrstor_checking((__force struct i387_fxsave_struct *)buf); | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * This restores directly out of user space. Exceptions are handled. | ||
173 | */ | ||
174 | int restore_i387_xstate(void __user *buf) | ||
175 | { | ||
176 | struct task_struct *tsk = current; | ||
177 | int err = 0; | ||
178 | |||
179 | if (!buf) { | ||
180 | if (used_math()) | ||
181 | goto clear; | ||
182 | return 0; | ||
183 | } else | ||
184 | if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) | ||
185 | return -EACCES; | ||
186 | |||
187 | if (!used_math()) { | ||
188 | err = init_fpu(tsk); | ||
189 | if (err) | ||
190 | return err; | ||
191 | } | ||
192 | |||
193 | if (!(task_thread_info(current)->status & TS_USEDFPU)) { | ||
194 | clts(); | ||
195 | task_thread_info(current)->status |= TS_USEDFPU; | ||
196 | } | ||
197 | if (task_thread_info(tsk)->status & TS_XSAVE) | ||
198 | err = restore_user_xstate(buf); | ||
199 | else | ||
200 | err = fxrstor_checking((__force struct i387_fxsave_struct *) | ||
201 | buf); | ||
202 | if (unlikely(err)) { | ||
203 | /* | ||
204 | * Encountered an error while doing the restore from the | ||
205 | * user buffer, clear the fpu state. | ||
206 | */ | ||
207 | clear: | ||
208 | clear_fpu(tsk); | ||
209 | clear_used_math(); | ||
210 | } | ||
211 | return err; | ||
212 | } | ||
213 | #endif | ||
214 | |||
215 | /* | ||
216 | * Prepare the SW reserved portion of the fxsave memory layout, indicating | ||
217 | * the presence of the extended state information in the memory layout | ||
218 | * pointed by the fpstate pointer in the sigcontext. | ||
219 | * This will be saved when ever the FP and extended state context is | ||
220 | * saved on the user stack during the signal handler delivery to the user. | ||
221 | */ | ||
222 | void prepare_fx_sw_frame(void) | ||
223 | { | ||
224 | int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) + | ||
225 | FP_XSTATE_MAGIC2_SIZE; | ||
226 | |||
227 | sig_xstate_size = sizeof(struct _fpstate) + size_extended; | ||
228 | |||
229 | #ifdef CONFIG_IA32_EMULATION | ||
230 | sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended; | ||
231 | #endif | ||
232 | |||
233 | memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved)); | ||
234 | |||
235 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; | ||
236 | fx_sw_reserved.extended_size = sig_xstate_size; | ||
237 | fx_sw_reserved.xstate_bv = pcntxt_mask; | ||
238 | fx_sw_reserved.xstate_size = xstate_size; | ||
239 | #ifdef CONFIG_IA32_EMULATION | ||
240 | memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved, | ||
241 | sizeof(struct _fpx_sw_bytes)); | ||
242 | fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size; | ||
243 | #endif | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Represents init state for the supported extended state. | ||
248 | */ | ||
249 | struct xsave_struct *init_xstate_buf; | ||
250 | |||
251 | #ifdef CONFIG_X86_64 | ||
252 | unsigned int sig_xstate_size = sizeof(struct _fpstate); | ||
253 | #endif | ||
254 | |||
255 | /* | ||
256 | * Enable the extended processor state save/restore feature | ||
257 | */ | ||
258 | void __cpuinit xsave_init(void) | ||
259 | { | ||
260 | if (!cpu_has_xsave) | ||
261 | return; | ||
262 | |||
263 | set_in_cr4(X86_CR4_OSXSAVE); | ||
264 | |||
265 | /* | ||
266 | * Enable all the features that the HW is capable of | ||
267 | * and the Linux kernel is aware of. | ||
268 | */ | ||
269 | xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask); | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * setup the xstate image representing the init state | ||
274 | */ | ||
275 | void setup_xstate_init(void) | ||
276 | { | ||
277 | init_xstate_buf = alloc_bootmem(xstate_size); | ||
278 | init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Enable and initialize the xsave feature. | ||
283 | */ | ||
284 | void __init xsave_cntxt_init(void) | ||
285 | { | ||
286 | unsigned int eax, ebx, ecx, edx; | ||
287 | |||
288 | cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); | ||
289 | pcntxt_mask = eax + ((u64)edx << 32); | ||
290 | |||
291 | if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) { | ||
292 | printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n", | ||
293 | pcntxt_mask); | ||
294 | BUG(); | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * for now OS knows only about FP/SSE | ||
299 | */ | ||
300 | pcntxt_mask = pcntxt_mask & XCNTXT_MASK; | ||
301 | xsave_init(); | ||
302 | |||
303 | /* | ||
304 | * Recompute the context size for enabled features | ||
305 | */ | ||
306 | cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); | ||
307 | xstate_size = ebx; | ||
308 | |||
309 | prepare_fx_sw_frame(); | ||
310 | |||
311 | setup_xstate_init(); | ||
312 | |||
313 | printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, " | ||
314 | "cntxt size 0x%x\n", | ||
315 | pcntxt_mask, xstate_size); | ||
316 | } | ||
diff --git a/arch/x86/power/cpu_32.c b/arch/x86/power/cpu_32.c index d3e083dea720..274d06082f48 100644 --- a/arch/x86/power/cpu_32.c +++ b/arch/x86/power/cpu_32.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/suspend.h> | 11 | #include <linux/suspend.h> |
12 | #include <asm/mtrr.h> | 12 | #include <asm/mtrr.h> |
13 | #include <asm/mce.h> | 13 | #include <asm/mce.h> |
14 | #include <asm/xcr.h> | ||
14 | 15 | ||
15 | static struct saved_context saved_context; | 16 | static struct saved_context saved_context; |
16 | 17 | ||
@@ -126,6 +127,12 @@ static void __restore_processor_state(struct saved_context *ctxt) | |||
126 | if (boot_cpu_has(X86_FEATURE_SEP)) | 127 | if (boot_cpu_has(X86_FEATURE_SEP)) |
127 | enable_sep_cpu(); | 128 | enable_sep_cpu(); |
128 | 129 | ||
130 | /* | ||
131 | * restore XCR0 for xsave capable cpu's. | ||
132 | */ | ||
133 | if (cpu_has_xsave) | ||
134 | xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask); | ||
135 | |||
129 | fix_processor_context(); | 136 | fix_processor_context(); |
130 | do_fpu_end(); | 137 | do_fpu_end(); |
131 | mtrr_ap_init(); | 138 | mtrr_ap_init(); |
diff --git a/arch/x86/power/cpu_64.c b/arch/x86/power/cpu_64.c index 66bdfb591fd8..e3b6cf70d62c 100644 --- a/arch/x86/power/cpu_64.c +++ b/arch/x86/power/cpu_64.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/page.h> | 14 | #include <asm/page.h> |
15 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
16 | #include <asm/mtrr.h> | 16 | #include <asm/mtrr.h> |
17 | #include <asm/xcr.h> | ||
17 | 18 | ||
18 | static void fix_processor_context(void); | 19 | static void fix_processor_context(void); |
19 | 20 | ||
@@ -122,6 +123,12 @@ static void __restore_processor_state(struct saved_context *ctxt) | |||
122 | wrmsrl(MSR_GS_BASE, ctxt->gs_base); | 123 | wrmsrl(MSR_GS_BASE, ctxt->gs_base); |
123 | wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); | 124 | wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); |
124 | 125 | ||
126 | /* | ||
127 | * restore XCR0 for xsave capable cpu's. | ||
128 | */ | ||
129 | if (cpu_has_xsave) | ||
130 | xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask); | ||
131 | |||
125 | fix_processor_context(); | 132 | fix_processor_context(); |
126 | 133 | ||
127 | do_fpu_end(); | 134 | do_fpu_end(); |
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h index 1ecdc3ed96e4..9ba862a4eac0 100644 --- a/include/asm-x86/i387.h +++ b/include/asm-x86/i387.h | |||
@@ -19,7 +19,9 @@ | |||
19 | #include <asm/sigcontext.h> | 19 | #include <asm/sigcontext.h> |
20 | #include <asm/user.h> | 20 | #include <asm/user.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | #include <asm/xsave.h> | ||
22 | 23 | ||
24 | extern unsigned int sig_xstate_size; | ||
23 | extern void fpu_init(void); | 25 | extern void fpu_init(void); |
24 | extern void mxcsr_feature_mask_init(void); | 26 | extern void mxcsr_feature_mask_init(void); |
25 | extern int init_fpu(struct task_struct *child); | 27 | extern int init_fpu(struct task_struct *child); |
@@ -31,12 +33,18 @@ extern user_regset_active_fn fpregs_active, xfpregs_active; | |||
31 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; | 33 | 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; | 34 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; |
33 | 35 | ||
36 | extern struct _fpx_sw_bytes fx_sw_reserved; | ||
34 | #ifdef CONFIG_IA32_EMULATION | 37 | #ifdef CONFIG_IA32_EMULATION |
38 | extern unsigned int sig_xstate_ia32_size; | ||
39 | extern struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
35 | struct _fpstate_ia32; | 40 | struct _fpstate_ia32; |
36 | extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); | 41 | struct _xstate_ia32; |
37 | extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); | 42 | extern int save_i387_xstate_ia32(void __user *buf); |
43 | extern int restore_i387_xstate_ia32(void __user *buf); | ||
38 | #endif | 44 | #endif |
39 | 45 | ||
46 | #define X87_FSW_ES (1 << 7) /* Exception Summary */ | ||
47 | |||
40 | #ifdef CONFIG_X86_64 | 48 | #ifdef CONFIG_X86_64 |
41 | 49 | ||
42 | /* Ignore delayed exceptions from user space */ | 50 | /* Ignore delayed exceptions from user space */ |
@@ -47,7 +55,7 @@ static inline void tolerant_fwait(void) | |||
47 | _ASM_EXTABLE(1b, 2b)); | 55 | _ASM_EXTABLE(1b, 2b)); |
48 | } | 56 | } |
49 | 57 | ||
50 | static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | 58 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) |
51 | { | 59 | { |
52 | int err; | 60 | int err; |
53 | 61 | ||
@@ -67,15 +75,31 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | |||
67 | return err; | 75 | return err; |
68 | } | 76 | } |
69 | 77 | ||
70 | #define X87_FSW_ES (1 << 7) /* Exception Summary */ | 78 | static inline int restore_fpu_checking(struct task_struct *tsk) |
79 | { | ||
80 | if (task_thread_info(tsk)->status & TS_XSAVE) | ||
81 | return xrstor_checking(&tsk->thread.xstate->xsave); | ||
82 | else | ||
83 | return fxrstor_checking(&tsk->thread.xstate->fxsave); | ||
84 | } | ||
71 | 85 | ||
72 | /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception | 86 | /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception |
73 | is pending. Clear the x87 state here by setting it to fixed | 87 | is pending. Clear the x87 state here by setting it to fixed |
74 | values. The kernel data segment can be sometimes 0 and sometimes | 88 | values. The kernel data segment can be sometimes 0 and sometimes |
75 | new user value. Both should be ok. | 89 | new user value. Both should be ok. |
76 | Use the PDA as safe address because it should be already in L1. */ | 90 | Use the PDA as safe address because it should be already in L1. */ |
77 | static inline void clear_fpu_state(struct i387_fxsave_struct *fx) | 91 | static inline void clear_fpu_state(struct task_struct *tsk) |
78 | { | 92 | { |
93 | struct xsave_struct *xstate = &tsk->thread.xstate->xsave; | ||
94 | struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; | ||
95 | |||
96 | /* | ||
97 | * xsave header may indicate the init state of the FP. | ||
98 | */ | ||
99 | if ((task_thread_info(tsk)->status & TS_XSAVE) && | ||
100 | !(xstate->xsave_hdr.xstate_bv & XSTATE_FP)) | ||
101 | return; | ||
102 | |||
79 | if (unlikely(fx->swd & X87_FSW_ES)) | 103 | if (unlikely(fx->swd & X87_FSW_ES)) |
80 | asm volatile("fnclex"); | 104 | asm volatile("fnclex"); |
81 | alternative_input(ASM_NOP8 ASM_NOP2, | 105 | alternative_input(ASM_NOP8 ASM_NOP2, |
@@ -84,7 +108,7 @@ static inline void clear_fpu_state(struct i387_fxsave_struct *fx) | |||
84 | X86_FEATURE_FXSAVE_LEAK); | 108 | X86_FEATURE_FXSAVE_LEAK); |
85 | } | 109 | } |
86 | 110 | ||
87 | static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | 111 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) |
88 | { | 112 | { |
89 | int err; | 113 | int err; |
90 | 114 | ||
@@ -108,7 +132,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | |||
108 | return err; | 132 | return err; |
109 | } | 133 | } |
110 | 134 | ||
111 | static inline void __save_init_fpu(struct task_struct *tsk) | 135 | static inline void fxsave(struct task_struct *tsk) |
112 | { | 136 | { |
113 | /* Using "rex64; fxsave %0" is broken because, if the memory operand | 137 | /* Using "rex64; fxsave %0" is broken because, if the memory operand |
114 | uses any extended registers for addressing, a second REX prefix | 138 | uses any extended registers for addressing, a second REX prefix |
@@ -133,7 +157,16 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
133 | : "=m" (tsk->thread.xstate->fxsave) | 157 | : "=m" (tsk->thread.xstate->fxsave) |
134 | : "cdaSDb" (&tsk->thread.xstate->fxsave)); | 158 | : "cdaSDb" (&tsk->thread.xstate->fxsave)); |
135 | #endif | 159 | #endif |
136 | clear_fpu_state(&tsk->thread.xstate->fxsave); | 160 | } |
161 | |||
162 | static inline void __save_init_fpu(struct task_struct *tsk) | ||
163 | { | ||
164 | if (task_thread_info(tsk)->status & TS_XSAVE) | ||
165 | xsave(tsk); | ||
166 | else | ||
167 | fxsave(tsk); | ||
168 | |||
169 | clear_fpu_state(tsk); | ||
137 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 170 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
138 | } | 171 | } |
139 | 172 | ||
@@ -148,6 +181,10 @@ static inline void tolerant_fwait(void) | |||
148 | 181 | ||
149 | static inline void restore_fpu(struct task_struct *tsk) | 182 | static inline void restore_fpu(struct task_struct *tsk) |
150 | { | 183 | { |
184 | if (task_thread_info(tsk)->status & TS_XSAVE) { | ||
185 | xrstor_checking(&tsk->thread.xstate->xsave); | ||
186 | return; | ||
187 | } | ||
151 | /* | 188 | /* |
152 | * The "nop" is needed to make the instructions the same | 189 | * The "nop" is needed to make the instructions the same |
153 | * length. | 190 | * length. |
@@ -173,6 +210,27 @@ static inline void restore_fpu(struct task_struct *tsk) | |||
173 | */ | 210 | */ |
174 | static inline void __save_init_fpu(struct task_struct *tsk) | 211 | static inline void __save_init_fpu(struct task_struct *tsk) |
175 | { | 212 | { |
213 | if (task_thread_info(tsk)->status & TS_XSAVE) { | ||
214 | struct xsave_struct *xstate = &tsk->thread.xstate->xsave; | ||
215 | struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; | ||
216 | |||
217 | xsave(tsk); | ||
218 | |||
219 | /* | ||
220 | * xsave header may indicate the init state of the FP. | ||
221 | */ | ||
222 | if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP)) | ||
223 | goto end; | ||
224 | |||
225 | if (unlikely(fx->swd & X87_FSW_ES)) | ||
226 | asm volatile("fnclex"); | ||
227 | |||
228 | /* | ||
229 | * we can do a simple return here or be paranoid :) | ||
230 | */ | ||
231 | goto clear_state; | ||
232 | } | ||
233 | |||
176 | /* Use more nops than strictly needed in case the compiler | 234 | /* Use more nops than strictly needed in case the compiler |
177 | varies code */ | 235 | varies code */ |
178 | alternative_input( | 236 | alternative_input( |
@@ -182,6 +240,7 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
182 | X86_FEATURE_FXSR, | 240 | X86_FEATURE_FXSR, |
183 | [fx] "m" (tsk->thread.xstate->fxsave), | 241 | [fx] "m" (tsk->thread.xstate->fxsave), |
184 | [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); | 242 | [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); |
243 | clear_state: | ||
185 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | 244 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception |
186 | is pending. Clear the x87 state here by setting it to fixed | 245 | is pending. Clear the x87 state here by setting it to fixed |
187 | values. safe_address is a random variable that should be in L1 */ | 246 | values. safe_address is a random variable that should be in L1 */ |
@@ -191,16 +250,17 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
191 | "fildl %[addr]", /* set F?P to defined value */ | 250 | "fildl %[addr]", /* set F?P to defined value */ |
192 | X86_FEATURE_FXSAVE_LEAK, | 251 | X86_FEATURE_FXSAVE_LEAK, |
193 | [addr] "m" (safe_address)); | 252 | [addr] "m" (safe_address)); |
253 | end: | ||
194 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 254 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
195 | } | 255 | } |
196 | 256 | ||
257 | #endif /* CONFIG_X86_64 */ | ||
258 | |||
197 | /* | 259 | /* |
198 | * Signal frame handlers... | 260 | * Signal frame handlers... |
199 | */ | 261 | */ |
200 | extern int save_i387(struct _fpstate __user *buf); | 262 | extern int save_i387_xstate(void __user *buf); |
201 | extern int restore_i387(struct _fpstate __user *buf); | 263 | extern int restore_i387_xstate(void __user *buf); |
202 | |||
203 | #endif /* CONFIG_X86_64 */ | ||
204 | 264 | ||
205 | static inline void __unlazy_fpu(struct task_struct *tsk) | 265 | static inline void __unlazy_fpu(struct task_struct *tsk) |
206 | { | 266 | { |
diff --git a/include/asm-x86/processor-flags.h b/include/asm-x86/processor-flags.h index 5dd79774f693..dc5f0712f9fa 100644 --- a/include/asm-x86/processor-flags.h +++ b/include/asm-x86/processor-flags.h | |||
@@ -59,6 +59,7 @@ | |||
59 | #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ | 59 | #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ |
60 | #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ | 60 | #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ |
61 | #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ | 61 | #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ |
62 | #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */ | ||
62 | 63 | ||
63 | /* | 64 | /* |
64 | * x86-64 Task Priority Register, CR8 | 65 | * x86-64 Task Priority Register, CR8 |
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h index 10471cfab145..df03c98e38d4 100644 --- a/include/asm-x86/processor.h +++ b/include/asm-x86/processor.h | |||
@@ -326,7 +326,12 @@ struct i387_fxsave_struct { | |||
326 | /* 16*16 bytes for each XMM-reg = 256 bytes: */ | 326 | /* 16*16 bytes for each XMM-reg = 256 bytes: */ |
327 | u32 xmm_space[64]; | 327 | u32 xmm_space[64]; |
328 | 328 | ||
329 | u32 padding[24]; | 329 | u32 padding[12]; |
330 | |||
331 | union { | ||
332 | u32 padding1[12]; | ||
333 | u32 sw_reserved[12]; | ||
334 | }; | ||
330 | 335 | ||
331 | } __attribute__((aligned(16))); | 336 | } __attribute__((aligned(16))); |
332 | 337 | ||
@@ -350,10 +355,23 @@ struct i387_soft_struct { | |||
350 | u32 entry_eip; | 355 | u32 entry_eip; |
351 | }; | 356 | }; |
352 | 357 | ||
358 | struct xsave_hdr_struct { | ||
359 | u64 xstate_bv; | ||
360 | u64 reserved1[2]; | ||
361 | u64 reserved2[5]; | ||
362 | } __attribute__((packed)); | ||
363 | |||
364 | struct xsave_struct { | ||
365 | struct i387_fxsave_struct i387; | ||
366 | struct xsave_hdr_struct xsave_hdr; | ||
367 | /* new processor state extensions will go here */ | ||
368 | } __attribute__ ((packed, aligned (64))); | ||
369 | |||
353 | union thread_xstate { | 370 | union thread_xstate { |
354 | struct i387_fsave_struct fsave; | 371 | struct i387_fsave_struct fsave; |
355 | struct i387_fxsave_struct fxsave; | 372 | struct i387_fxsave_struct fxsave; |
356 | struct i387_soft_struct soft; | 373 | struct i387_soft_struct soft; |
374 | struct xsave_struct xsave; | ||
357 | }; | 375 | }; |
358 | 376 | ||
359 | #ifdef CONFIG_X86_64 | 377 | #ifdef CONFIG_X86_64 |
diff --git a/include/asm-x86/sigcontext.h b/include/asm-x86/sigcontext.h index 24879c85b291..ee813f4fe5d5 100644 --- a/include/asm-x86/sigcontext.h +++ b/include/asm-x86/sigcontext.h | |||
@@ -4,6 +4,40 @@ | |||
4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
5 | #include <asm/types.h> | 5 | #include <asm/types.h> |
6 | 6 | ||
7 | #define FP_XSTATE_MAGIC1 0x46505853U | ||
8 | #define FP_XSTATE_MAGIC2 0x46505845U | ||
9 | #define FP_XSTATE_MAGIC2_SIZE sizeof(FP_XSTATE_MAGIC2) | ||
10 | |||
11 | /* | ||
12 | * bytes 464..511 in the current 512byte layout of fxsave/fxrstor frame | ||
13 | * are reserved for SW usage. On cpu's supporting xsave/xrstor, these bytes | ||
14 | * are used to extended the fpstate pointer in the sigcontext, which now | ||
15 | * includes the extended state information along with fpstate information. | ||
16 | * | ||
17 | * Presence of FP_XSTATE_MAGIC1 at the beginning of this SW reserved | ||
18 | * area and FP_XSTATE_MAGIC2 at the end of memory layout | ||
19 | * (extended_size - FP_XSTATE_MAGIC2_SIZE) indicates the presence of the | ||
20 | * extended state information in the memory layout pointed by the fpstate | ||
21 | * pointer in sigcontext. | ||
22 | */ | ||
23 | struct _fpx_sw_bytes { | ||
24 | __u32 magic1; /* FP_XSTATE_MAGIC1 */ | ||
25 | __u32 extended_size; /* total size of the layout referred by | ||
26 | * fpstate pointer in the sigcontext. | ||
27 | */ | ||
28 | __u64 xstate_bv; | ||
29 | /* feature bit mask (including fp/sse/extended | ||
30 | * state) that is present in the memory | ||
31 | * layout. | ||
32 | */ | ||
33 | __u32 xstate_size; /* actual xsave state size, based on the | ||
34 | * features saved in the layout. | ||
35 | * 'extended_size' will be greater than | ||
36 | * 'xstate_size'. | ||
37 | */ | ||
38 | __u32 padding[7]; /* for future use. */ | ||
39 | }; | ||
40 | |||
7 | #ifdef __i386__ | 41 | #ifdef __i386__ |
8 | /* | 42 | /* |
9 | * As documented in the iBCS2 standard.. | 43 | * As documented in the iBCS2 standard.. |
@@ -53,7 +87,13 @@ struct _fpstate { | |||
53 | unsigned long reserved; | 87 | unsigned long reserved; |
54 | struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ | 88 | struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ |
55 | struct _xmmreg _xmm[8]; | 89 | struct _xmmreg _xmm[8]; |
56 | unsigned long padding[56]; | 90 | unsigned long padding1[44]; |
91 | |||
92 | union { | ||
93 | unsigned long padding2[12]; | ||
94 | struct _fpx_sw_bytes sw_reserved; /* represents the extended | ||
95 | * state info */ | ||
96 | }; | ||
57 | }; | 97 | }; |
58 | 98 | ||
59 | #define X86_FXSR_MAGIC 0x0000 | 99 | #define X86_FXSR_MAGIC 0x0000 |
@@ -79,7 +119,15 @@ struct sigcontext { | |||
79 | unsigned long flags; | 119 | unsigned long flags; |
80 | unsigned long sp_at_signal; | 120 | unsigned long sp_at_signal; |
81 | unsigned short ss, __ssh; | 121 | unsigned short ss, __ssh; |
82 | struct _fpstate __user *fpstate; | 122 | |
123 | /* | ||
124 | * fpstate is really (struct _fpstate *) or (struct _xstate *) | ||
125 | * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved | ||
126 | * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end | ||
127 | * of extended memory layout. See comments at the defintion of | ||
128 | * (struct _fpx_sw_bytes) | ||
129 | */ | ||
130 | void __user *fpstate; /* zero when no FPU/extended context */ | ||
83 | unsigned long oldmask; | 131 | unsigned long oldmask; |
84 | unsigned long cr2; | 132 | unsigned long cr2; |
85 | }; | 133 | }; |
@@ -130,7 +178,12 @@ struct _fpstate { | |||
130 | __u32 mxcsr_mask; | 178 | __u32 mxcsr_mask; |
131 | __u32 st_space[32]; /* 8*16 bytes for each FP-reg */ | 179 | __u32 st_space[32]; /* 8*16 bytes for each FP-reg */ |
132 | __u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg */ | 180 | __u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg */ |
133 | __u32 reserved2[24]; | 181 | __u32 reserved2[12]; |
182 | union { | ||
183 | __u32 reserved3[12]; | ||
184 | struct _fpx_sw_bytes sw_reserved; /* represents the extended | ||
185 | * state information */ | ||
186 | }; | ||
134 | }; | 187 | }; |
135 | 188 | ||
136 | #ifdef __KERNEL__ | 189 | #ifdef __KERNEL__ |
@@ -161,7 +214,15 @@ struct sigcontext { | |||
161 | unsigned long trapno; | 214 | unsigned long trapno; |
162 | unsigned long oldmask; | 215 | unsigned long oldmask; |
163 | unsigned long cr2; | 216 | unsigned long cr2; |
164 | struct _fpstate __user *fpstate; /* zero when no FPU context */ | 217 | |
218 | /* | ||
219 | * fpstate is really (struct _fpstate *) or (struct _xstate *) | ||
220 | * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved | ||
221 | * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end | ||
222 | * of extended memory layout. See comments at the defintion of | ||
223 | * (struct _fpx_sw_bytes) | ||
224 | */ | ||
225 | void __user *fpstate; /* zero when no FPU/extended context */ | ||
165 | unsigned long reserved1[8]; | 226 | unsigned long reserved1[8]; |
166 | }; | 227 | }; |
167 | #else /* __KERNEL__ */ | 228 | #else /* __KERNEL__ */ |
@@ -202,4 +263,22 @@ struct sigcontext { | |||
202 | 263 | ||
203 | #endif /* !__i386__ */ | 264 | #endif /* !__i386__ */ |
204 | 265 | ||
266 | struct _xsave_hdr { | ||
267 | __u64 xstate_bv; | ||
268 | __u64 reserved1[2]; | ||
269 | __u64 reserved2[5]; | ||
270 | }; | ||
271 | |||
272 | /* | ||
273 | * Extended state pointed by the fpstate pointer in the sigcontext. | ||
274 | * In addition to the fpstate, information encoded in the xstate_hdr | ||
275 | * indicates the presence of other extended state information | ||
276 | * supported by the processor and OS. | ||
277 | */ | ||
278 | struct _xstate { | ||
279 | struct _fpstate fpstate; | ||
280 | struct _xsave_hdr xstate_hdr; | ||
281 | /* new processor state extensions go here */ | ||
282 | }; | ||
283 | |||
205 | #endif /* ASM_X86__SIGCONTEXT_H */ | 284 | #endif /* ASM_X86__SIGCONTEXT_H */ |
diff --git a/include/asm-x86/sigcontext32.h b/include/asm-x86/sigcontext32.h index 4e2ec732dd01..8c347032c2f2 100644 --- a/include/asm-x86/sigcontext32.h +++ b/include/asm-x86/sigcontext32.h | |||
@@ -40,7 +40,11 @@ struct _fpstate_ia32 { | |||
40 | __u32 reserved; | 40 | __u32 reserved; |
41 | struct _fpxreg _fxsr_st[8]; | 41 | struct _fpxreg _fxsr_st[8]; |
42 | struct _xmmreg _xmm[8]; /* It's actually 16 */ | 42 | struct _xmmreg _xmm[8]; /* It's actually 16 */ |
43 | __u32 padding[56]; | 43 | __u32 padding[44]; |
44 | union { | ||
45 | __u32 padding2[12]; | ||
46 | struct _fpx_sw_bytes sw_reserved; | ||
47 | }; | ||
44 | }; | 48 | }; |
45 | 49 | ||
46 | struct sigcontext_ia32 { | 50 | struct sigcontext_ia32 { |
diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h index e64be8863b76..30586f2ee558 100644 --- a/include/asm-x86/thread_info.h +++ b/include/asm-x86/thread_info.h | |||
@@ -239,6 +239,7 @@ static inline struct thread_info *stack_thread_info(void) | |||
239 | #define TS_POLLING 0x0004 /* true if in idle loop | 239 | #define TS_POLLING 0x0004 /* true if in idle loop |
240 | and not sleeping */ | 240 | and not sleeping */ |
241 | #define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */ | 241 | #define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */ |
242 | #define TS_XSAVE 0x0010 /* Use xsave/xrstor */ | ||
242 | 243 | ||
243 | #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) | 244 | #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) |
244 | 245 | ||
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/xcr.h b/include/asm-x86/xcr.h new file mode 100644 index 000000000000..f2cba4e79a23 --- /dev/null +++ b/include/asm-x86/xcr.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright 2008 rPath, Inc. - All Rights Reserved | ||
4 | * | ||
5 | * This file is part of the Linux kernel, and is made available under | ||
6 | * the terms of the GNU General Public License version 2 or (at your | ||
7 | * option) any later version; incorporated herein by reference. | ||
8 | * | ||
9 | * ----------------------------------------------------------------------- */ | ||
10 | |||
11 | /* | ||
12 | * asm-x86/xcr.h | ||
13 | * | ||
14 | * Definitions for the eXtended Control Register instructions | ||
15 | */ | ||
16 | |||
17 | #ifndef _ASM_X86_XCR_H | ||
18 | #define _ASM_X86_XCR_H | ||
19 | |||
20 | #define XCR_XFEATURE_ENABLED_MASK 0x00000000 | ||
21 | |||
22 | #ifdef __KERNEL__ | ||
23 | # ifndef __ASSEMBLY__ | ||
24 | |||
25 | #include <linux/types.h> | ||
26 | |||
27 | static inline u64 xgetbv(u32 index) | ||
28 | { | ||
29 | u32 eax, edx; | ||
30 | |||
31 | asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */ | ||
32 | : "=a" (eax), "=d" (edx) | ||
33 | : "c" (index)); | ||
34 | return eax + ((u64)edx << 32); | ||
35 | } | ||
36 | |||
37 | static inline void xsetbv(u32 index, u64 value) | ||
38 | { | ||
39 | u32 eax = value; | ||
40 | u32 edx = value >> 32; | ||
41 | |||
42 | asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */ | ||
43 | : : "a" (eax), "d" (edx), "c" (index)); | ||
44 | } | ||
45 | |||
46 | # endif /* __ASSEMBLY__ */ | ||
47 | #endif /* __KERNEL__ */ | ||
48 | |||
49 | #endif /* _ASM_X86_XCR_H */ | ||
diff --git a/include/asm-x86/xsave.h b/include/asm-x86/xsave.h new file mode 100644 index 000000000000..08e9a1ac07a9 --- /dev/null +++ b/include/asm-x86/xsave.h | |||
@@ -0,0 +1,118 @@ | |||
1 | #ifndef __ASM_X86_XSAVE_H | ||
2 | #define __ASM_X86_XSAVE_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <asm/processor.h> | ||
6 | #include <asm/i387.h> | ||
7 | |||
8 | #define XSTATE_FP 0x1 | ||
9 | #define XSTATE_SSE 0x2 | ||
10 | |||
11 | #define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE) | ||
12 | |||
13 | #define FXSAVE_SIZE 512 | ||
14 | |||
15 | /* | ||
16 | * These are the features that the OS can handle currently. | ||
17 | */ | ||
18 | #define XCNTXT_MASK (XSTATE_FP | XSTATE_SSE) | ||
19 | |||
20 | #ifdef CONFIG_X86_64 | ||
21 | #define REX_PREFIX "0x48, " | ||
22 | #else | ||
23 | #define REX_PREFIX | ||
24 | #endif | ||
25 | |||
26 | extern unsigned int xstate_size; | ||
27 | extern u64 pcntxt_mask; | ||
28 | extern struct xsave_struct *init_xstate_buf; | ||
29 | |||
30 | extern void xsave_cntxt_init(void); | ||
31 | extern void xsave_init(void); | ||
32 | extern int init_fpu(struct task_struct *child); | ||
33 | extern int check_for_xstate(struct i387_fxsave_struct __user *buf, | ||
34 | void __user *fpstate, | ||
35 | struct _fpx_sw_bytes *sw); | ||
36 | |||
37 | static inline int xrstor_checking(struct xsave_struct *fx) | ||
38 | { | ||
39 | int err; | ||
40 | |||
41 | asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" | ||
42 | "2:\n" | ||
43 | ".section .fixup,\"ax\"\n" | ||
44 | "3: movl $-1,%[err]\n" | ||
45 | " jmp 2b\n" | ||
46 | ".previous\n" | ||
47 | _ASM_EXTABLE(1b, 3b) | ||
48 | : [err] "=r" (err) | ||
49 | : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0) | ||
50 | : "memory"); | ||
51 | |||
52 | return err; | ||
53 | } | ||
54 | |||
55 | static inline int xsave_user(struct xsave_struct __user *buf) | ||
56 | { | ||
57 | int err; | ||
58 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" | ||
59 | "2:\n" | ||
60 | ".section .fixup,\"ax\"\n" | ||
61 | "3: movl $-1,%[err]\n" | ||
62 | " jmp 2b\n" | ||
63 | ".previous\n" | ||
64 | ".section __ex_table,\"a\"\n" | ||
65 | _ASM_ALIGN "\n" | ||
66 | _ASM_PTR "1b,3b\n" | ||
67 | ".previous" | ||
68 | : [err] "=r" (err) | ||
69 | : "D" (buf), "a" (-1), "d" (-1), "0" (0) | ||
70 | : "memory"); | ||
71 | if (unlikely(err) && __clear_user(buf, xstate_size)) | ||
72 | err = -EFAULT; | ||
73 | /* No need to clear here because the caller clears USED_MATH */ | ||
74 | return err; | ||
75 | } | ||
76 | |||
77 | static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask) | ||
78 | { | ||
79 | int err; | ||
80 | struct xsave_struct *xstate = ((__force struct xsave_struct *)buf); | ||
81 | u32 lmask = mask; | ||
82 | u32 hmask = mask >> 32; | ||
83 | |||
84 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n" | ||
85 | "2:\n" | ||
86 | ".section .fixup,\"ax\"\n" | ||
87 | "3: movl $-1,%[err]\n" | ||
88 | " jmp 2b\n" | ||
89 | ".previous\n" | ||
90 | ".section __ex_table,\"a\"\n" | ||
91 | _ASM_ALIGN "\n" | ||
92 | _ASM_PTR "1b,3b\n" | ||
93 | ".previous" | ||
94 | : [err] "=r" (err) | ||
95 | : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0) | ||
96 | : "memory"); /* memory required? */ | ||
97 | return err; | ||
98 | } | ||
99 | |||
100 | static inline void xrstor_state(struct xsave_struct *fx, u64 mask) | ||
101 | { | ||
102 | u32 lmask = mask; | ||
103 | u32 hmask = mask >> 32; | ||
104 | |||
105 | asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" | ||
106 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
107 | : "memory"); | ||
108 | } | ||
109 | |||
110 | static inline void xsave(struct task_struct *tsk) | ||
111 | { | ||
112 | /* This, however, we can work around by forcing the compiler to select | ||
113 | an addressing mode that doesn't require extended registers. */ | ||
114 | __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27" | ||
115 | : : "D" (&(tsk->thread.xstate->xsave)), | ||
116 | "a" (-1), "d"(-1) : "memory"); | ||
117 | } | ||
118 | #endif | ||