diff options
Diffstat (limited to 'arch/x86')
-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 |
12 files changed, 545 insertions, 166 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(); |