diff options
Diffstat (limited to 'arch/tile/kernel/signal.c')
| -rw-r--r-- | arch/tile/kernel/signal.c | 20 | 
1 files changed, 12 insertions, 8 deletions
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index fb28e85ae3a..1260321155f 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c @@ -16,7 +16,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> @@ -53,7 +52,7 @@ SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,   */  int restore_sigcontext(struct pt_regs *regs, -		       struct sigcontext __user *sc, long *pr0) +		       struct sigcontext __user *sc)  {  	int err = 0;  	int i; @@ -71,19 +70,20 @@ int restore_sigcontext(struct pt_regs *regs,  	for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)  		err |= __get_user(regs->regs[i], &sc->gregs[i]); +	/* Ensure that the PL is always set to USER_PL. */ +	regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1)); +  	regs->faultnum = INT_SWINT_1_SIGRETURN; -	err |= __get_user(*pr0, &sc->gregs[0]);  	return err;  } -/* sigreturn() returns long since it restores r0 in the interrupted code. */ +/* The assembly shim for this function arranges to ignore the return value. */  SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)  {  	struct rt_sigframe __user *frame =  		(struct rt_sigframe __user *)(regs->sp);  	sigset_t set; -	long r0;  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))  		goto badframe; @@ -96,13 +96,13 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)  	recalc_sigpending();  	spin_unlock_irq(¤t->sighand->siglock); -	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) +	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))  		goto badframe;  	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)  		goto badframe; -	return r0; +	return 0;  badframe:  	force_sig(SIGSEGV, current); @@ -330,7 +330,7 @@ void do_signal(struct pt_regs *regs)  			current_thread_info()->status &= ~TS_RESTORE_SIGMASK;  		} -		return; +		goto done;  	}  	/* Did we come from a system call? */ @@ -358,4 +358,8 @@ void do_signal(struct pt_regs *regs)  		current_thread_info()->status &= ~TS_RESTORE_SIGMASK;  		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);  	} + +done: +	/* Avoid double syscall restart if there are nested signals. */ +	regs->faultnum = INT_SWINT_1_SIGRETURN;  }  |