diff options
Diffstat (limited to 'arch/microblaze/kernel/signal.c')
| -rw-r--r-- | arch/microblaze/kernel/signal.c | 171 | 
1 files changed, 35 insertions, 136 deletions
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 4c0e6521b11..1c80e4fc40c 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -21,7 +21,6 @@  #include <linux/sched.h>  #include <linux/mm.h>  #include <linux/smp.h> -#include <linux/smp_lock.h>  #include <linux/kernel.h>  #include <linux/signal.h>  #include <linux/errno.h> @@ -45,91 +44,8 @@  asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall); -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -asmlinkage int -sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs) -{ -	sigset_t saveset; - -	mask &= _BLOCKABLE; -	spin_lock_irq(¤t->sighand->siglock); -	saveset = current->blocked; -	siginitset(¤t->blocked, mask); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); - -	regs->r3 = -EINTR; -	while (1) { -		current->state = TASK_INTERRUPTIBLE; -		schedule(); -		if (do_signal(regs, &saveset, 1)) -			return -EINTR; -	} -} - -asmlinkage int -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, -		struct pt_regs *regs) -{ -	sigset_t saveset, newset; - -	/* XXX: Don't preclude handling different sized sigset_t's. */ -	if (sigsetsize != sizeof(sigset_t)) -		return -EINVAL; - -	if (copy_from_user(&newset, unewset, sizeof(newset))) -		return -EFAULT; -	sigdelsetmask(&newset, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	saveset = current->blocked; -	current->blocked = newset; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); - -	regs->r3 = -EINTR; -	while (1) { -		current->state = TASK_INTERRUPTIBLE; -		schedule(); -		if (do_signal(regs, &saveset, 1)) -			return -EINTR; -	} -} - -asmlinkage int -sys_sigaction(int sig, const struct old_sigaction *act, -		struct old_sigaction *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 +asmlinkage long  sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,  		struct pt_regs *regs)  { @@ -139,7 +55,6 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,  /*   * Do a signal return; undo the signal stack.   */ -  struct sigframe {  	struct sigcontext sc;  	unsigned long extramask[_NSIG_WORDS-1]; @@ -176,40 +91,7 @@ static int restore_sigcontext(struct pt_regs *regs,  	return err;  } -asmlinkage int sys_sigreturn(struct pt_regs *regs) -{ -	struct sigframe *frame = -			(struct sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE); - -	sigset_t set; -	int rval; - -	if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) -		goto badframe; - -	if (__get_user(set.sig[0], &frame->sc.oldmask) -		|| (_NSIG_WORDS > 1 -		&& __copy_from_user(&set.sig[1], &frame->extramask, -					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); - -	if (restore_sigcontext(regs, &frame->sc, &rval)) -		goto badframe; -	return rval; - -badframe: -	force_sig(SIGSEGV, current); -	return 0; -} - -asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)  {  	struct rt_sigframe __user *frame =  		(struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE); @@ -324,21 +206,17 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	/* Set up to return from userspace. If provided, use a stub  	 already in userspace. */  	/* minus 8 is offset to cater for "rtsd r15,8" */ -	if (ka->sa.sa_flags & SA_RESTORER) { -		regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8; -	} else { -		/* addi r12, r0, __NR_sigreturn */ -		err |= __put_user(0x31800000 | __NR_rt_sigreturn , -				frame->tramp + 0); -		/* brki r14, 0x8 */ -		err |= __put_user(0xb9cc0008, frame->tramp + 1); +	/* addi r12, r0, __NR_sigreturn */ +	err |= __put_user(0x31800000 | __NR_rt_sigreturn , +			frame->tramp + 0); +	/* brki r14, 0x8 */ +	err |= __put_user(0xb9cc0008, frame->tramp + 1); -		/* Return from sighandler will jump to the tramp. -		 Negative 8 offset because return is rtsd r15, 8 */ -		regs->r15 = ((unsigned long)frame->tramp)-8; +	/* Return from sighandler will jump to the tramp. +	 Negative 8 offset because return is rtsd r15, 8 */ +	regs->r15 = ((unsigned long)frame->tramp)-8; -		__invalidate_cache_sigtramp((unsigned long)frame->tramp); -	} +	__invalidate_cache_sigtramp((unsigned long)frame->tramp);  	if (err)  		goto give_sigsegv; @@ -405,7 +283,7 @@ do_restart:   * OK, we're invoking a handler   */ -static void +static int  handle_signal(unsigned long sig, struct k_sigaction *ka,  		siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)  { @@ -426,6 +304,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,  		recalc_sigpending();  		spin_unlock_irq(¤t->sighand->siglock);  	} +	return 1;  }  /* @@ -456,7 +335,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)  	if (kernel_mode(regs))  		return 1; -	if (!oldset) +	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); @@ -464,13 +345,31 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)  		/* Whee! Actually deliver the signal. */  		if (in_syscall)  			handle_restart(regs, &ka, 1); -		handle_signal(signr, &ka, &info, oldset, regs); +		if (handle_signal(signr, &ka, &info, oldset, regs)) { +			/* +			 * 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; +		}  		return 1;  	}  	if (in_syscall)  		handle_restart(regs, NULL, 0); +	/* +	 * 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); +	} +  	/* Did we come from a system call? */  	return 0;  }  |