diff options
Diffstat (limited to 'arch/sparc/kernel/signal.c')
-rw-r--r-- | arch/sparc/kernel/signal.c | 307 |
1 files changed, 10 insertions, 297 deletions
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 9994cac95078..1f730619a24a 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c | |||
@@ -22,7 +22,6 @@ | |||
22 | 22 | ||
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <asm/ptrace.h> | 24 | #include <asm/ptrace.h> |
25 | #include <asm/svr4.h> | ||
26 | #include <asm/pgalloc.h> | 25 | #include <asm/pgalloc.h> |
27 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
28 | #include <asm/cacheflush.h> /* flush_sig_insns */ | 27 | #include <asm/cacheflush.h> /* flush_sig_insns */ |
@@ -454,7 +453,6 @@ setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *old | |||
454 | break; | 453 | break; |
455 | case SIGSYS: | 454 | case SIGSYS: |
456 | if (info->si_code == (__SI_FAULT|0x100)) { | 455 | if (info->si_code == (__SI_FAULT|0x100)) { |
457 | /* See sys_sunos.c */ | ||
458 | sig_code = info->si_trapno; | 456 | sig_code = info->si_trapno; |
459 | break; | 457 | break; |
460 | } | 458 | } |
@@ -676,291 +674,17 @@ sigsegv: | |||
676 | force_sigsegv(signo, current); | 674 | force_sigsegv(signo, current); |
677 | } | 675 | } |
678 | 676 | ||
679 | /* Setup a Solaris stack frame */ | ||
680 | static inline void | ||
681 | setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, | ||
682 | struct pt_regs *regs, int signr, sigset_t *oldset) | ||
683 | { | ||
684 | svr4_signal_frame_t __user *sfp; | ||
685 | svr4_gregset_t __user *gr; | ||
686 | svr4_siginfo_t __user *si; | ||
687 | svr4_mcontext_t __user *mc; | ||
688 | svr4_gwindows_t __user *gw; | ||
689 | svr4_ucontext_t __user *uc; | ||
690 | svr4_sigset_t setv; | ||
691 | struct thread_info *tp = current_thread_info(); | ||
692 | int window = 0, err; | ||
693 | |||
694 | synchronize_user_stack(); | ||
695 | sfp = (svr4_signal_frame_t __user *) | ||
696 | get_sigframe(sa, regs, SVR4_SF_ALIGNED + sizeof(struct reg_window)); | ||
697 | |||
698 | if (invalid_frame_pointer(sfp, sizeof(*sfp))) | ||
699 | goto sigill_and_return; | ||
700 | |||
701 | /* Start with a clean frame pointer and fill it */ | ||
702 | err = __clear_user(sfp, sizeof(*sfp)); | ||
703 | |||
704 | /* Setup convenience variables */ | ||
705 | si = &sfp->si; | ||
706 | uc = &sfp->uc; | ||
707 | gw = &sfp->gw; | ||
708 | mc = &uc->mcontext; | ||
709 | gr = &mc->greg; | ||
710 | |||
711 | /* FIXME: where am I supposed to put this? | ||
712 | * sc->sigc_onstack = old_status; | ||
713 | * anyways, it does not look like it is used for anything at all. | ||
714 | */ | ||
715 | setv.sigbits[0] = oldset->sig[0]; | ||
716 | setv.sigbits[1] = oldset->sig[1]; | ||
717 | if (_NSIG_WORDS >= 4) { | ||
718 | setv.sigbits[2] = oldset->sig[2]; | ||
719 | setv.sigbits[3] = oldset->sig[3]; | ||
720 | err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); | ||
721 | } else | ||
722 | err |= __copy_to_user(&uc->sigmask, &setv, | ||
723 | 2 * sizeof(unsigned int)); | ||
724 | |||
725 | /* Store registers */ | ||
726 | err |= __put_user(regs->pc, &((*gr)[SVR4_PC])); | ||
727 | err |= __put_user(regs->npc, &((*gr)[SVR4_NPC])); | ||
728 | err |= __put_user(regs->psr, &((*gr)[SVR4_PSR])); | ||
729 | err |= __put_user(regs->y, &((*gr)[SVR4_Y])); | ||
730 | |||
731 | /* Copy g[1..7] and o[0..7] registers */ | ||
732 | err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs[UREG_G1], | ||
733 | sizeof(long) * 7); | ||
734 | err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs[UREG_I0], | ||
735 | sizeof(long) * 8); | ||
736 | |||
737 | /* Setup sigaltstack */ | ||
738 | err |= __put_user(current->sas_ss_sp, &uc->stack.sp); | ||
739 | err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); | ||
740 | err |= __put_user(current->sas_ss_size, &uc->stack.size); | ||
741 | |||
742 | /* Save the currently window file: */ | ||
743 | |||
744 | /* 1. Link sfp->uc->gwins to our windows */ | ||
745 | err |= __put_user(gw, &mc->gwin); | ||
746 | |||
747 | /* 2. Number of windows to restore at setcontext(): */ | ||
748 | err |= __put_user(tp->w_saved, &gw->count); | ||
749 | |||
750 | /* 3. Save each valid window | ||
751 | * Currently, it makes a copy of the windows from the kernel copy. | ||
752 | * David's code for SunOS, makes the copy but keeps the pointer to | ||
753 | * the kernel. My version makes the pointer point to a userland | ||
754 | * copy of those. Mhm, I wonder if I shouldn't just ignore those | ||
755 | * on setcontext and use those that are on the kernel, the signal | ||
756 | * handler should not be modyfing those, mhm. | ||
757 | * | ||
758 | * These windows are just used in case synchronize_user_stack failed | ||
759 | * to flush the user windows. | ||
760 | */ | ||
761 | for (window = 0; window < tp->w_saved; window++) { | ||
762 | err |= __put_user((int __user *) &(gw->win[window]), &gw->winptr[window]); | ||
763 | err |= __copy_to_user(&gw->win[window], | ||
764 | &tp->reg_window[window], | ||
765 | sizeof(svr4_rwindow_t)); | ||
766 | err |= __put_user(0, gw->winptr[window]); | ||
767 | } | ||
768 | |||
769 | /* 4. We just pay attention to the gw->count field on setcontext */ | ||
770 | tp->w_saved = 0; /* So process is allowed to execute. */ | ||
771 | |||
772 | /* Setup the signal information. Solaris expects a bunch of | ||
773 | * information to be passed to the signal handler, we don't provide | ||
774 | * that much currently, should use siginfo. | ||
775 | */ | ||
776 | err |= __put_user(signr, &si->siginfo.signo); | ||
777 | err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); | ||
778 | if (err) | ||
779 | goto sigsegv; | ||
780 | |||
781 | regs->u_regs[UREG_FP] = (unsigned long) sfp; | ||
782 | regs->pc = (unsigned long) sa->sa_handler; | ||
783 | regs->npc = (regs->pc + 4); | ||
784 | |||
785 | /* Arguments passed to signal handler */ | ||
786 | if (regs->u_regs[14]){ | ||
787 | struct reg_window __user *rw = (struct reg_window __user *) | ||
788 | regs->u_regs[14]; | ||
789 | |||
790 | err |= __put_user(signr, &rw->ins[0]); | ||
791 | err |= __put_user(si, &rw->ins[1]); | ||
792 | err |= __put_user(uc, &rw->ins[2]); | ||
793 | err |= __put_user(sfp, &rw->ins[6]); /* frame pointer */ | ||
794 | if (err) | ||
795 | goto sigsegv; | ||
796 | |||
797 | regs->u_regs[UREG_I0] = signr; | ||
798 | regs->u_regs[UREG_I1] = (unsigned long) si; | ||
799 | regs->u_regs[UREG_I2] = (unsigned long) uc; | ||
800 | } | ||
801 | return; | ||
802 | |||
803 | sigill_and_return: | ||
804 | do_exit(SIGILL); | ||
805 | sigsegv: | ||
806 | force_sigsegv(signr, current); | ||
807 | } | ||
808 | |||
809 | asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs) | ||
810 | { | ||
811 | svr4_gregset_t __user *gr; | ||
812 | svr4_mcontext_t __user *mc; | ||
813 | svr4_sigset_t setv; | ||
814 | int err = 0; | ||
815 | |||
816 | synchronize_user_stack(); | ||
817 | |||
818 | if (current_thread_info()->w_saved) | ||
819 | return -EFAULT; | ||
820 | |||
821 | err = clear_user(uc, sizeof(*uc)); | ||
822 | if (err) | ||
823 | return -EFAULT; | ||
824 | |||
825 | /* Setup convenience variables */ | ||
826 | mc = &uc->mcontext; | ||
827 | gr = &mc->greg; | ||
828 | |||
829 | setv.sigbits[0] = current->blocked.sig[0]; | ||
830 | setv.sigbits[1] = current->blocked.sig[1]; | ||
831 | if (_NSIG_WORDS >= 4) { | ||
832 | setv.sigbits[2] = current->blocked.sig[2]; | ||
833 | setv.sigbits[3] = current->blocked.sig[3]; | ||
834 | err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); | ||
835 | } else | ||
836 | err |= __copy_to_user(&uc->sigmask, &setv, | ||
837 | 2 * sizeof(unsigned int)); | ||
838 | |||
839 | /* Store registers */ | ||
840 | err |= __put_user(regs->pc, &uc->mcontext.greg[SVR4_PC]); | ||
841 | err |= __put_user(regs->npc, &uc->mcontext.greg[SVR4_NPC]); | ||
842 | err |= __put_user(regs->psr, &uc->mcontext.greg[SVR4_PSR]); | ||
843 | err |= __put_user(regs->y, &uc->mcontext.greg[SVR4_Y]); | ||
844 | |||
845 | /* Copy g[1..7] and o[0..7] registers */ | ||
846 | err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs[UREG_G1], | ||
847 | sizeof(uint) * 7); | ||
848 | err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs[UREG_I0], | ||
849 | sizeof(uint) * 8); | ||
850 | |||
851 | /* Setup sigaltstack */ | ||
852 | err |= __put_user(current->sas_ss_sp, &uc->stack.sp); | ||
853 | err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); | ||
854 | err |= __put_user(current->sas_ss_size, &uc->stack.size); | ||
855 | |||
856 | /* The register file is not saved | ||
857 | * we have already stuffed all of it with sync_user_stack | ||
858 | */ | ||
859 | return (err ? -EFAULT : 0); | ||
860 | } | ||
861 | |||
862 | /* Set the context for a svr4 application, this is Solaris way to sigreturn */ | ||
863 | asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs) | ||
864 | { | ||
865 | svr4_gregset_t __user *gr; | ||
866 | unsigned long pc, npc, psr; | ||
867 | mm_segment_t old_fs; | ||
868 | sigset_t set; | ||
869 | svr4_sigset_t setv; | ||
870 | int err; | ||
871 | stack_t st; | ||
872 | |||
873 | /* Fixme: restore windows, or is this already taken care of in | ||
874 | * svr4_setup_frame when sync_user_windows is done? | ||
875 | */ | ||
876 | flush_user_windows(); | ||
877 | |||
878 | if (current_thread_info()->w_saved) | ||
879 | goto sigsegv_and_return; | ||
880 | |||
881 | if (((unsigned long) c) & 3) | ||
882 | goto sigsegv_and_return; | ||
883 | |||
884 | if (!__access_ok((unsigned long)c, sizeof(*c))) | ||
885 | goto sigsegv_and_return; | ||
886 | |||
887 | /* Check for valid PC and nPC */ | ||
888 | gr = &c->mcontext.greg; | ||
889 | err = __get_user(pc, &((*gr)[SVR4_PC])); | ||
890 | err |= __get_user(npc, &((*gr)[SVR4_NPC])); | ||
891 | |||
892 | if ((pc | npc) & 3) | ||
893 | goto sigsegv_and_return; | ||
894 | |||
895 | /* Retrieve information from passed ucontext */ | ||
896 | /* note that nPC is ored a 1, this is used to inform entry.S */ | ||
897 | /* that we don't want it to mess with our PC and nPC */ | ||
898 | |||
899 | /* This is pretty much atomic, no amount locking would prevent | ||
900 | * the races which exist anyways. | ||
901 | */ | ||
902 | err |= __copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t)); | ||
903 | |||
904 | err |= __get_user(st.ss_sp, &c->stack.sp); | ||
905 | err |= __get_user(st.ss_flags, &c->stack.flags); | ||
906 | err |= __get_user(st.ss_size, &c->stack.size); | ||
907 | |||
908 | if (err) | ||
909 | goto sigsegv_and_return; | ||
910 | |||
911 | /* It is more difficult to avoid calling this function than to | ||
912 | call it and ignore errors. */ | ||
913 | old_fs = get_fs(); | ||
914 | set_fs(KERNEL_DS); | ||
915 | do_sigaltstack((const stack_t __user *) &st, NULL, | ||
916 | regs->u_regs[UREG_I6]); | ||
917 | set_fs(old_fs); | ||
918 | |||
919 | set.sig[0] = setv.sigbits[0]; | ||
920 | set.sig[1] = setv.sigbits[1]; | ||
921 | if (_NSIG_WORDS >= 4) { | ||
922 | set.sig[2] = setv.sigbits[2]; | ||
923 | set.sig[3] = setv.sigbits[3]; | ||
924 | } | ||
925 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
926 | spin_lock_irq(¤t->sighand->siglock); | ||
927 | current->blocked = set; | ||
928 | recalc_sigpending(); | ||
929 | spin_unlock_irq(¤t->sighand->siglock); | ||
930 | regs->pc = pc; | ||
931 | regs->npc = npc | 1; | ||
932 | err |= __get_user(regs->y, &((*gr)[SVR4_Y])); | ||
933 | err |= __get_user(psr, &((*gr)[SVR4_PSR])); | ||
934 | regs->psr &= ~(PSR_ICC); | ||
935 | regs->psr |= (psr & PSR_ICC); | ||
936 | |||
937 | /* Restore g[1..7] and o[0..7] registers */ | ||
938 | err |= __copy_from_user(®s->u_regs[UREG_G1], &(*gr)[SVR4_G1], | ||
939 | sizeof(long) * 7); | ||
940 | err |= __copy_from_user(®s->u_regs[UREG_I0], &(*gr)[SVR4_O0], | ||
941 | sizeof(long) * 8); | ||
942 | return (err ? -EFAULT : 0); | ||
943 | |||
944 | sigsegv_and_return: | ||
945 | force_sig(SIGSEGV, current); | ||
946 | return -EFAULT; | ||
947 | } | ||
948 | |||
949 | static inline void | 677 | static inline void |
950 | handle_signal(unsigned long signr, struct k_sigaction *ka, | 678 | handle_signal(unsigned long signr, struct k_sigaction *ka, |
951 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, | 679 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) |
952 | int svr4_signal) | ||
953 | { | 680 | { |
954 | if (svr4_signal) | 681 | if (ka->sa.sa_flags & SA_SIGINFO) |
955 | setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); | 682 | new_setup_rt_frame(ka, regs, signr, oldset, info); |
956 | else { | 683 | else if (current->thread.new_signal) |
957 | if (ka->sa.sa_flags & SA_SIGINFO) | 684 | new_setup_frame(ka, regs, signr, oldset); |
958 | new_setup_rt_frame(ka, regs, signr, oldset, info); | 685 | else |
959 | else if (current->thread.new_signal) | 686 | setup_frame(&ka->sa, regs, signr, oldset, info); |
960 | new_setup_frame(ka, regs, signr, oldset); | 687 | |
961 | else | ||
962 | setup_frame(&ka->sa, regs, signr, oldset, info); | ||
963 | } | ||
964 | spin_lock_irq(¤t->sighand->siglock); | 688 | spin_lock_irq(¤t->sighand->siglock); |
965 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 689 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
966 | if (!(ka->sa.sa_flags & SA_NOMASK)) | 690 | if (!(ka->sa.sa_flags & SA_NOMASK)) |
@@ -1002,17 +726,6 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest | |||
1002 | int signr; | 726 | int signr; |
1003 | sigset_t *oldset; | 727 | sigset_t *oldset; |
1004 | 728 | ||
1005 | /* | ||
1006 | * XXX Disable svr4 signal handling until solaris emulation works. | ||
1007 | * It is buggy - Anton | ||
1008 | */ | ||
1009 | #define SVR4_SIGNAL_BROKEN 1 | ||
1010 | #ifdef SVR4_SIGNAL_BROKEN | ||
1011 | int svr4_signal = 0; | ||
1012 | #else | ||
1013 | int svr4_signal = current->personality == PER_SVR4; | ||
1014 | #endif | ||
1015 | |||
1016 | cookie.restart_syscall = restart_syscall; | 729 | cookie.restart_syscall = restart_syscall; |
1017 | cookie.orig_i0 = orig_i0; | 730 | cookie.orig_i0 = orig_i0; |
1018 | 731 | ||
@@ -1025,8 +738,8 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest | |||
1025 | if (signr > 0) { | 738 | if (signr > 0) { |
1026 | if (cookie.restart_syscall) | 739 | if (cookie.restart_syscall) |
1027 | syscall_restart(cookie.orig_i0, regs, &ka.sa); | 740 | syscall_restart(cookie.orig_i0, regs, &ka.sa); |
1028 | handle_signal(signr, &ka, &info, oldset, | 741 | handle_signal(signr, &ka, &info, oldset, regs); |
1029 | regs, svr4_signal); | 742 | |
1030 | /* a signal was successfully delivered; the saved | 743 | /* a signal was successfully delivered; the saved |
1031 | * sigmask will have been stored in the signal frame, | 744 | * sigmask will have been stored in the signal frame, |
1032 | * and will be restored by sigreturn, so we can simply | 745 | * and will be restored by sigreturn, so we can simply |