diff options
Diffstat (limited to 'arch/sh/kernel/signal_32.c')
| -rw-r--r-- | arch/sh/kernel/signal_32.c | 182 | 
1 files changed, 32 insertions, 150 deletions
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 579cd2ca358..594cd371aa2 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -22,10 +22,8 @@  #include <linux/elf.h>  #include <linux/personality.h>  #include <linux/binfmts.h> -#include <linux/freezer.h>  #include <linux/io.h>  #include <linux/tracehook.h> -#include <asm/system.h>  #include <asm/ucontext.h>  #include <asm/uaccess.h>  #include <asm/pgtable.h> @@ -33,8 +31,6 @@  #include <asm/syscalls.h>  #include <asm/fpu.h> -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -  struct fdpic_func_descriptor {  	unsigned long	text;  	unsigned long	GOT; @@ -51,71 +47,6 @@ struct fdpic_func_descriptor {  #define UNWINDGUARD 64  /* - * Atomically swap in the new signal mask, and wait for a signal. - */ -asmlinkage int -sys_sigsuspend(old_sigset_t mask, -	       unsigned long r5, unsigned long r6, unsigned long r7, -	       struct pt_regs __regs) -{ -	mask &= _BLOCKABLE; -	spin_lock_irq(¤t->sighand->siglock); -	current->saved_sigmask = current->blocked; -	siginitset(¤t->blocked, mask); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); - -	current->state = TASK_INTERRUPTIBLE; -	schedule(); -	set_restore_sigmask(); - -	return -ERESTARTNOHAND; -} - -asmlinkage int -sys_sigaction(int sig, const struct old_sigaction __user *act, -	      struct old_sigaction __user *oact) -{ -	struct k_sigaction new_ka, old_ka; -	int ret; - -	if (act) { -		old_sigset_t mask; -		if (!access_ok(VERIFY_READ, act, sizeof(*act)) || -		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) || -		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) -			return -EFAULT; -		__get_user(new_ka.sa.sa_flags, &act->sa_flags); -		__get_user(mask, &act->sa_mask); -		siginitset(&new_ka.sa.sa_mask, mask); -	} - -	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - -	if (!ret && oact) { -		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || -		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || -		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) -			return -EFAULT; -		__put_user(old_ka.sa.sa_flags, &oact->sa_flags); -		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); -	} - -	return ret; -} - -asmlinkage int -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, -		unsigned long r6, unsigned long r7, -		struct pt_regs __regs) -{ -	struct pt_regs *regs = RELOC_HIDE(&__regs, 0); - -	return do_sigaltstack(uss, uoss, regs->regs[15]); -} - - -/*   * Do a signal return; undo the signal stack.   */ @@ -162,12 +93,11 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc,  	if (!(boot_cpu_data.flags & CPU_HAS_FPU))  		return 0; -	if (!used_math()) { -		__put_user(0, &sc->sc_ownedfp); -		return 0; -	} +	if (!used_math()) +		return __put_user(0, &sc->sc_ownedfp); -	__put_user(1, &sc->sc_ownedfp); +	if (__put_user(1, &sc->sc_ownedfp)) +		return -EFAULT;  	/* This will cause a "finit" to be triggered by the next  	   attempted FPU operation by the 'current' process. @@ -207,7 +137,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p  		regs->sr |= SR_FD; /* Release FPU */  		clear_fpu(tsk, regs);  		clear_used_math(); -		__get_user (owned_fp, &sc->sc_ownedfp); +		err |= __get_user (owned_fp, &sc->sc_ownedfp);  		if (owned_fp)  			err |= restore_sigcontext_fpu(sc);  	} @@ -218,11 +148,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p  	return err;  } -asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, -			     unsigned long r6, unsigned long r7, -			     struct pt_regs __regs) +asmlinkage int sys_sigreturn(void)  { -	struct pt_regs *regs = RELOC_HIDE(&__regs, 0); +	struct pt_regs *regs = current_pt_regs();  	struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15];  	sigset_t set;  	int r0; @@ -239,12 +167,7 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,  				    sizeof(frame->extramask))))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE); - -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->sc, &r0))  		goto badframe; @@ -255,11 +178,9 @@ badframe:  	return 0;  } -asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, -				unsigned long r6, unsigned long r7, -				struct pt_regs __regs) +asmlinkage int sys_rt_sigreturn(void)  { -	struct pt_regs *regs = RELOC_HIDE(&__regs, 0); +	struct pt_regs *regs = current_pt_regs();  	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15];  	sigset_t set;  	int r0; @@ -273,17 +194,12 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,  	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))  		goto badframe; -	if (do_sigaltstack(&frame->uc.uc_stack, NULL, -			   regs->regs[15]) == -EFAULT) +	if (restore_altstack(&frame->uc.uc_stack))  		goto badframe;  	return r0; @@ -405,11 +321,14 @@ static int setup_frame(int sig, struct k_sigaction *ka,  		struct fdpic_func_descriptor __user *funcptr =  			(struct fdpic_func_descriptor __user *)ka->sa.sa_handler; -		__get_user(regs->pc, &funcptr->text); -		__get_user(regs->regs[12], &funcptr->GOT); +		err |= __get_user(regs->pc, &funcptr->text); +		err |= __get_user(regs->regs[12], &funcptr->GOT);  	} else  		regs->pc = (unsigned long)ka->sa.sa_handler; +	if (err) +		goto give_sigsegv; +  	set_fs(USER_DS);  	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", @@ -445,11 +364,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	/* Create the ucontext.  */  	err |= __put_user(0, &frame->uc.uc_flags);  	err |= __put_user(NULL, &frame->uc.uc_link); -	err |= __put_user((void *)current->sas_ss_sp, -			  &frame->uc.uc_stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->regs[15]), -			  &frame->uc.uc_stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); +	err |= __save_altstack(&frame->uc.uc_stack, regs->regs[15]);  	err |= setup_sigcontext(&frame->uc.uc_mcontext,  			        regs, set->sig[0]);  	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); @@ -489,11 +404,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		struct fdpic_func_descriptor __user *funcptr =  			(struct fdpic_func_descriptor __user *)ka->sa.sa_handler; -		__get_user(regs->pc, &funcptr->text); -		__get_user(regs->regs[12], &funcptr->GOT); +		err |= __get_user(regs->pc, &funcptr->text); +		err |= __get_user(regs->regs[12], &funcptr->GOT);  	} else  		regs->pc = (unsigned long)ka->sa.sa_handler; +	if (err) +		goto give_sigsegv; +  	set_fs(USER_DS);  	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", @@ -536,10 +454,11 @@ handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs,  /*   * OK, we're invoking a handler   */ -static int +static void  handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, -	      sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0) +	      struct pt_regs *regs, unsigned int save_r0)  { +	sigset_t *oldset = sigmask_to_save();  	int ret;  	/* Set up the stack frame */ @@ -548,19 +467,10 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,  	else  		ret = setup_frame(sig, ka, oldset, regs); -	if (ka->sa.sa_flags & SA_ONESHOT) -		ka->sa.sa_handler = SIG_DFL; - -	if (ret == 0) { -		spin_lock_irq(¤t->sighand->siglock); -		sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); -		if (!(ka->sa.sa_flags & SA_NODEFER)) -			sigaddset(¤t->blocked,sig); -		recalc_sigpending(); -		spin_unlock_irq(¤t->sighand->siglock); -	} - -	return ret; +	if (ret) +		return; +	signal_delivered(sig, info, ka, regs, +			test_thread_flag(TIF_SINGLESTEP));  }  /* @@ -577,7 +487,6 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)  	siginfo_t info;  	int signr;  	struct k_sigaction ka; -	sigset_t *oldset;  	/*  	 * We want the common case to go fast, which @@ -588,37 +497,15 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)  	if (!user_mode(regs))  		return; -	if (try_to_freeze()) -		goto no_signal; - -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) -		oldset = ¤t->saved_sigmask; -	else -		oldset = ¤t->blocked; -  	signr = get_signal_to_deliver(&info, &ka, regs, NULL);  	if (signr > 0) {  		handle_syscall_restart(save_r0, regs, &ka.sa);  		/* Whee!  Actually deliver the signal.  */ -		if (handle_signal(signr, &ka, &info, oldset, -				  regs, save_r0) == 0) { -			/* -			 * A signal was successfully delivered; the saved -			 * sigmask will have been stored in the signal frame, -			 * and will be restored by sigreturn, so we can simply -			 * clear the TS_RESTORE_SIGMASK flag -			 */ -			current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - -			tracehook_signal_handler(signr, &info, &ka, regs, -					test_thread_flag(TIF_SINGLESTEP)); -		} - +		handle_signal(signr, &ka, &info, regs, save_r0);  		return;  	} -no_signal:  	/* Did we come from a system call? */  	if (regs->tra >= 0) {  		/* Restart the system call - no handlers present */ @@ -637,10 +524,7 @@ no_signal:  	 * If there's no signal to deliver, we just put the saved sigmask  	 * back.  	 */ -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) { -		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -	} +	restore_saved_sigmask();  }  asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, @@ -653,7 +537,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,  	if (thread_info_flags & _TIF_NOTIFY_RESUME) {  		clear_thread_flag(TIF_NOTIFY_RESUME);  		tracehook_notify_resume(regs); -		if (current->replacement_session_keyring) -			key_replace_session_keyring();  	}  }  | 
