summaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/kernel/signal.c')
-rw-r--r--arch/tile/kernel/signal.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index fb28e85ae3ae..1260321155f1 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(&current->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, &current->saved_sigmask, NULL);
}
+
+done:
+ /* Avoid double syscall restart if there are nested signals. */
+ regs->faultnum = INT_SWINT_1_SIGRETURN;
}