Commit b832c335 authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] ppc64: fix signal handler arguments

This is the first of 3 patches from David Woodhouse which fix various
problems with signal handling on ppc64.  (This is David's patch plus a
couple of comment fixes from me.)

Without this patch, a signal handler that is called as a result of delivery
of a signal while a process is waiting in sigsuspend() will have wrong
values given to it for the second and third arguments.  The reason is that
we were returning to userspace via the syscall return path, which doesn't
bother to restore r4 and r5.  This patch arranges for the return to
userspace to be done via ret_from_except in this case, which restores all
registers.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f6febf2c
...@@ -265,16 +265,21 @@ _GLOBAL(save_nvgprs) ...@@ -265,16 +265,21 @@ _GLOBAL(save_nvgprs)
_GLOBAL(ppc32_sigsuspend) _GLOBAL(ppc32_sigsuspend)
bl .save_nvgprs bl .save_nvgprs
bl .sys32_sigsuspend bl .sys32_sigsuspend
b syscall_exit b 70f
_GLOBAL(ppc64_rt_sigsuspend) _GLOBAL(ppc64_rt_sigsuspend)
bl .save_nvgprs bl .save_nvgprs
bl .sys_rt_sigsuspend bl .sys_rt_sigsuspend
b syscall_exit b 70f
_GLOBAL(ppc32_rt_sigsuspend) _GLOBAL(ppc32_rt_sigsuspend)
bl .save_nvgprs bl .save_nvgprs
bl .sys32_rt_sigsuspend bl .sys32_rt_sigsuspend
/* If sigsuspend() returns zero, we are going into a signal handler */
70: cmpdi 0,r3,0
beq .ret_from_except
/* If it returned -EINTR, we need to return via syscall_exit to set
the SO bit in cr0 and potentially stop for ptrace. */
b syscall_exit b syscall_exit
_GLOBAL(ppc_fork) _GLOBAL(ppc_fork)
......
...@@ -98,7 +98,7 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int ...@@ -98,7 +98,7 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
schedule(); schedule();
if (do_signal(&saveset, regs)) if (do_signal(&saveset, regs))
return regs->gpr[3]; return 0;
} }
} }
......
...@@ -284,14 +284,12 @@ long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, ...@@ -284,14 +284,12 @@ long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
schedule(); schedule();
if (do_signal32(&saveset, regs)) if (do_signal32(&saveset, regs))
/* /*
* If a signal handler needs to be called, * Returning 0 means we return to userspace via
* do_signal32() has set R3 to the signal number (the * ret_from_except and thus restore all user
* first argument of the signal handler), so don't * registers from *regs. This is what we need
* overwrite that with EINTR ! * to do when a signal has been delivered.
* In the other cases, do_signal32() doesn't touch
* R3, so it's still set to -EINTR (see above).
*/ */
return regs->gpr[3]; return 0;
} }
} }
...@@ -587,14 +585,12 @@ int sys32_rt_sigsuspend(compat_sigset_t __user * unewset, size_t sigsetsize, int ...@@ -587,14 +585,12 @@ int sys32_rt_sigsuspend(compat_sigset_t __user * unewset, size_t sigsetsize, int
schedule(); schedule();
if (do_signal32(&saveset, regs)) if (do_signal32(&saveset, regs))
/* /*
* If a signal handler needs to be called, * Returning 0 means we return to userspace via
* do_signal32() has set R3 to the signal number (the * ret_from_except and thus restore all user
* first argument of the signal handler), so don't * registers from *regs. This is what we need
* overwrite that with EINTR ! * to do when a signal has been delivered.
* In the other cases, do_signal32() doesn't touch
* R3, so it's still set to -EINTR (see above).
*/ */
return regs->gpr[3]; return 0;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment