diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2012-09-21 20:18:44 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-09-21 20:18:44 -0400 |
commit | 49b8c695e331c9685e6ffdbf34872509d77c8459 (patch) | |
tree | d4afdfae0115b2ab56687d23d6329d6ad934788f /arch/x86/kernel/signal.c | |
parent | e59d1b0a24199db01978e6c1e89859eda93ce683 (diff) | |
parent | b1a74bf8212367be2b1d6685c11a84e056eaaaf1 (diff) |
Merge branch 'x86/fpu' into x86/smap
Reason for merge:
x86/fpu changed the structure of some of the code that x86/smap
changes; mostly fpu-internal.h but also minor changes to the
signal code.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Resolved Conflicts:
arch/x86/ia32/ia32_signal.c
arch/x86/include/asm/fpu-internal.h
arch/x86/kernel/signal.c
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 215 |
1 files changed, 91 insertions, 124 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 932612887e92..036bddb46236 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -118,7 +118,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
118 | get_user_ex(*pax, &sc->ax); | 118 | get_user_ex(*pax, &sc->ax); |
119 | } get_user_catch(err); | 119 | } get_user_catch(err); |
120 | 120 | ||
121 | err |= restore_i387_xstate(buf); | 121 | err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32)); |
122 | 122 | ||
123 | return err; | 123 | return err; |
124 | } | 124 | } |
@@ -207,35 +207,32 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
207 | void __user **fpstate) | 207 | void __user **fpstate) |
208 | { | 208 | { |
209 | /* Default to using normal stack */ | 209 | /* Default to using normal stack */ |
210 | unsigned long math_size = 0; | ||
210 | unsigned long sp = regs->sp; | 211 | unsigned long sp = regs->sp; |
212 | unsigned long buf_fx = 0; | ||
211 | int onsigstack = on_sig_stack(sp); | 213 | int onsigstack = on_sig_stack(sp); |
212 | 214 | ||
213 | #ifdef CONFIG_X86_64 | ||
214 | /* redzone */ | 215 | /* redzone */ |
215 | sp -= 128; | 216 | if (config_enabled(CONFIG_X86_64)) |
216 | #endif /* CONFIG_X86_64 */ | 217 | sp -= 128; |
217 | 218 | ||
218 | if (!onsigstack) { | 219 | if (!onsigstack) { |
219 | /* This is the X/Open sanctioned signal stack switching. */ | 220 | /* This is the X/Open sanctioned signal stack switching. */ |
220 | if (ka->sa.sa_flags & SA_ONSTACK) { | 221 | if (ka->sa.sa_flags & SA_ONSTACK) { |
221 | if (current->sas_ss_size) | 222 | if (current->sas_ss_size) |
222 | sp = current->sas_ss_sp + current->sas_ss_size; | 223 | sp = current->sas_ss_sp + current->sas_ss_size; |
223 | } else { | 224 | } else if (config_enabled(CONFIG_X86_32) && |
224 | #ifdef CONFIG_X86_32 | 225 | (regs->ss & 0xffff) != __USER_DS && |
225 | /* This is the legacy signal stack switching. */ | 226 | !(ka->sa.sa_flags & SA_RESTORER) && |
226 | if ((regs->ss & 0xffff) != __USER_DS && | 227 | ka->sa.sa_restorer) { |
227 | !(ka->sa.sa_flags & SA_RESTORER) && | 228 | /* This is the legacy signal stack switching. */ |
228 | ka->sa.sa_restorer) | ||
229 | sp = (unsigned long) ka->sa.sa_restorer; | 229 | sp = (unsigned long) ka->sa.sa_restorer; |
230 | #endif /* CONFIG_X86_32 */ | ||
231 | } | 230 | } |
232 | } | 231 | } |
233 | 232 | ||
234 | if (used_math()) { | 233 | if (used_math()) { |
235 | sp -= sig_xstate_size; | 234 | sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32), |
236 | #ifdef CONFIG_X86_64 | 235 | &buf_fx, &math_size); |
237 | sp = round_down(sp, 64); | ||
238 | #endif /* CONFIG_X86_64 */ | ||
239 | *fpstate = (void __user *)sp; | 236 | *fpstate = (void __user *)sp; |
240 | } | 237 | } |
241 | 238 | ||
@@ -248,8 +245,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
248 | if (onsigstack && !likely(on_sig_stack(sp))) | 245 | if (onsigstack && !likely(on_sig_stack(sp))) |
249 | return (void __user *)-1L; | 246 | return (void __user *)-1L; |
250 | 247 | ||
251 | /* save i387 state */ | 248 | /* save i387 and extended state */ |
252 | if (used_math() && save_i387_xstate(*fpstate) < 0) | 249 | if (used_math() && |
250 | save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0) | ||
253 | return (void __user *)-1L; | 251 | return (void __user *)-1L; |
254 | 252 | ||
255 | return (void __user *)sp; | 253 | return (void __user *)sp; |
@@ -385,7 +383,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
385 | */ | 383 | */ |
386 | put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); | 384 | put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); |
387 | } put_user_catch(err); | 385 | } put_user_catch(err); |
388 | 386 | ||
389 | err |= copy_siginfo_to_user(&frame->info, info); | 387 | err |= copy_siginfo_to_user(&frame->info, info); |
390 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | 388 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
391 | regs, set->sig[0]); | 389 | regs, set->sig[0]); |
@@ -477,6 +475,75 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
477 | } | 475 | } |
478 | #endif /* CONFIG_X86_32 */ | 476 | #endif /* CONFIG_X86_32 */ |
479 | 477 | ||
478 | static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, | ||
479 | siginfo_t *info, compat_sigset_t *set, | ||
480 | struct pt_regs *regs) | ||
481 | { | ||
482 | #ifdef CONFIG_X86_X32_ABI | ||
483 | struct rt_sigframe_x32 __user *frame; | ||
484 | void __user *restorer; | ||
485 | int err = 0; | ||
486 | void __user *fpstate = NULL; | ||
487 | |||
488 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | ||
489 | |||
490 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
491 | return -EFAULT; | ||
492 | |||
493 | if (ka->sa.sa_flags & SA_SIGINFO) { | ||
494 | if (copy_siginfo_to_user32(&frame->info, info)) | ||
495 | return -EFAULT; | ||
496 | } | ||
497 | |||
498 | put_user_try { | ||
499 | /* Create the ucontext. */ | ||
500 | if (cpu_has_xsave) | ||
501 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
502 | else | ||
503 | put_user_ex(0, &frame->uc.uc_flags); | ||
504 | put_user_ex(0, &frame->uc.uc_link); | ||
505 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
506 | put_user_ex(sas_ss_flags(regs->sp), | ||
507 | &frame->uc.uc_stack.ss_flags); | ||
508 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
509 | put_user_ex(0, &frame->uc.uc__pad0); | ||
510 | |||
511 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
512 | restorer = ka->sa.sa_restorer; | ||
513 | } else { | ||
514 | /* could use a vstub here */ | ||
515 | restorer = NULL; | ||
516 | err |= -EFAULT; | ||
517 | } | ||
518 | put_user_ex(restorer, &frame->pretcode); | ||
519 | } put_user_catch(err); | ||
520 | |||
521 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
522 | regs, set->sig[0]); | ||
523 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
524 | |||
525 | if (err) | ||
526 | return -EFAULT; | ||
527 | |||
528 | /* Set up registers for signal handler */ | ||
529 | regs->sp = (unsigned long) frame; | ||
530 | regs->ip = (unsigned long) ka->sa.sa_handler; | ||
531 | |||
532 | /* We use the x32 calling convention here... */ | ||
533 | regs->di = sig; | ||
534 | regs->si = (unsigned long) &frame->info; | ||
535 | regs->dx = (unsigned long) &frame->uc; | ||
536 | |||
537 | loadsegment(ds, __USER_DS); | ||
538 | loadsegment(es, __USER_DS); | ||
539 | |||
540 | regs->cs = __USER_CS; | ||
541 | regs->ss = __USER_DS; | ||
542 | #endif /* CONFIG_X86_X32_ABI */ | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
480 | #ifdef CONFIG_X86_32 | 547 | #ifdef CONFIG_X86_32 |
481 | /* | 548 | /* |
482 | * Atomically swap in the new signal mask, and wait for a signal. | 549 | * Atomically swap in the new signal mask, and wait for a signal. |
@@ -615,55 +682,22 @@ static int signr_convert(int sig) | |||
615 | return sig; | 682 | return sig; |
616 | } | 683 | } |
617 | 684 | ||
618 | #ifdef CONFIG_X86_32 | ||
619 | |||
620 | #define is_ia32 1 | ||
621 | #define ia32_setup_frame __setup_frame | ||
622 | #define ia32_setup_rt_frame __setup_rt_frame | ||
623 | |||
624 | #else /* !CONFIG_X86_32 */ | ||
625 | |||
626 | #ifdef CONFIG_IA32_EMULATION | ||
627 | #define is_ia32 test_thread_flag(TIF_IA32) | ||
628 | #else /* !CONFIG_IA32_EMULATION */ | ||
629 | #define is_ia32 0 | ||
630 | #endif /* CONFIG_IA32_EMULATION */ | ||
631 | |||
632 | #ifdef CONFIG_X86_X32_ABI | ||
633 | #define is_x32 test_thread_flag(TIF_X32) | ||
634 | |||
635 | static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, | ||
636 | siginfo_t *info, compat_sigset_t *set, | ||
637 | struct pt_regs *regs); | ||
638 | #else /* !CONFIG_X86_X32_ABI */ | ||
639 | #define is_x32 0 | ||
640 | #endif /* CONFIG_X86_X32_ABI */ | ||
641 | |||
642 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
643 | sigset_t *set, struct pt_regs *regs); | ||
644 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
645 | sigset_t *set, struct pt_regs *regs); | ||
646 | |||
647 | #endif /* CONFIG_X86_32 */ | ||
648 | |||
649 | static int | 685 | static int |
650 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 686 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
651 | struct pt_regs *regs) | 687 | struct pt_regs *regs) |
652 | { | 688 | { |
653 | int usig = signr_convert(sig); | 689 | int usig = signr_convert(sig); |
654 | sigset_t *set = sigmask_to_save(); | 690 | sigset_t *set = sigmask_to_save(); |
691 | compat_sigset_t *cset = (compat_sigset_t *) set; | ||
655 | 692 | ||
656 | /* Set up the stack frame */ | 693 | /* Set up the stack frame */ |
657 | if (is_ia32) { | 694 | if (is_ia32_frame()) { |
658 | if (ka->sa.sa_flags & SA_SIGINFO) | 695 | if (ka->sa.sa_flags & SA_SIGINFO) |
659 | return ia32_setup_rt_frame(usig, ka, info, set, regs); | 696 | return ia32_setup_rt_frame(usig, ka, info, cset, regs); |
660 | else | 697 | else |
661 | return ia32_setup_frame(usig, ka, set, regs); | 698 | return ia32_setup_frame(usig, ka, cset, regs); |
662 | #ifdef CONFIG_X86_X32_ABI | 699 | } else if (is_x32_frame()) { |
663 | } else if (is_x32) { | 700 | return x32_setup_rt_frame(usig, ka, info, cset, regs); |
664 | return x32_setup_rt_frame(usig, ka, info, | ||
665 | (compat_sigset_t *)set, regs); | ||
666 | #endif | ||
667 | } else { | 701 | } else { |
668 | return __setup_rt_frame(sig, ka, info, set, regs); | 702 | return __setup_rt_frame(sig, ka, info, set, regs); |
669 | } | 703 | } |
@@ -827,73 +861,6 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | |||
827 | } | 861 | } |
828 | 862 | ||
829 | #ifdef CONFIG_X86_X32_ABI | 863 | #ifdef CONFIG_X86_X32_ABI |
830 | static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, | ||
831 | siginfo_t *info, compat_sigset_t *set, | ||
832 | struct pt_regs *regs) | ||
833 | { | ||
834 | struct rt_sigframe_x32 __user *frame; | ||
835 | void __user *restorer; | ||
836 | int err = 0; | ||
837 | void __user *fpstate = NULL; | ||
838 | |||
839 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | ||
840 | |||
841 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
842 | return -EFAULT; | ||
843 | |||
844 | if (ka->sa.sa_flags & SA_SIGINFO) { | ||
845 | if (copy_siginfo_to_user32(&frame->info, info)) | ||
846 | return -EFAULT; | ||
847 | } | ||
848 | |||
849 | put_user_try { | ||
850 | /* Create the ucontext. */ | ||
851 | if (cpu_has_xsave) | ||
852 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
853 | else | ||
854 | put_user_ex(0, &frame->uc.uc_flags); | ||
855 | put_user_ex(0, &frame->uc.uc_link); | ||
856 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
857 | put_user_ex(sas_ss_flags(regs->sp), | ||
858 | &frame->uc.uc_stack.ss_flags); | ||
859 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
860 | put_user_ex(0, &frame->uc.uc__pad0); | ||
861 | |||
862 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
863 | restorer = ka->sa.sa_restorer; | ||
864 | } else { | ||
865 | /* could use a vstub here */ | ||
866 | restorer = NULL; | ||
867 | err |= -EFAULT; | ||
868 | } | ||
869 | put_user_ex(restorer, &frame->pretcode); | ||
870 | } put_user_catch(err); | ||
871 | |||
872 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
873 | regs, set->sig[0]); | ||
874 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
875 | |||
876 | if (err) | ||
877 | return -EFAULT; | ||
878 | |||
879 | /* Set up registers for signal handler */ | ||
880 | regs->sp = (unsigned long) frame; | ||
881 | regs->ip = (unsigned long) ka->sa.sa_handler; | ||
882 | |||
883 | /* We use the x32 calling convention here... */ | ||
884 | regs->di = sig; | ||
885 | regs->si = (unsigned long) &frame->info; | ||
886 | regs->dx = (unsigned long) &frame->uc; | ||
887 | |||
888 | loadsegment(ds, __USER_DS); | ||
889 | loadsegment(es, __USER_DS); | ||
890 | |||
891 | regs->cs = __USER_CS; | ||
892 | regs->ss = __USER_DS; | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs) | 864 | asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs) |
898 | { | 865 | { |
899 | struct rt_sigframe_x32 __user *frame; | 866 | struct rt_sigframe_x32 __user *frame; |