#include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
+#include <linux/bitops.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
* operation, as all of this is local to this thread.
*/
asmlinkage unsigned long
-osf_sigprocmask(int how, unsigned long newmask, long a2, long a3,
- long a4, long a5, struct pt_regs regs)
+do_osf_sigprocmask(int how, unsigned long newmask, struct pt_regs *regs)
{
unsigned long oldmask = -EINVAL;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- (®s)->r0 = 0; /* special no error return */
+ regs->r0 = 0; /* special no error return */
}
return oldmask;
}
asmlinkage int
-osf_sigaction(int sig, const struct osf_sigaction *act,
- struct osf_sigaction *oact)
+osf_sigaction(int sig, const struct osf_sigaction __user *act,
+ struct osf_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
int ret;
}
asmlinkage long
-sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
- size_t sigsetsize, void *restorer)
+sys_rt_sigaction(int sig, const struct sigaction __user *act,
+ struct sigaction __user *oact,
+ size_t sigsetsize, void __user *restorer)
{
struct k_sigaction new_ka, old_ka;
int ret;
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
-do_sigsuspend(old_sigset_t mask, struct pt_regs *reg, struct switch_stack *sw)
+do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
{
sigset_t oldset;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+ /* Indicate EINTR on return from any possible signal handler,
+ which will not come back through here, but via sigreturn. */
+ regs->r0 = EINTR;
+ regs->r19 = 1;
+
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&oldset, reg, sw, 0, 0))
+ if (do_signal(&oldset, regs, sw, 0, 0))
return -EINTR;
}
}
asmlinkage int
-do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize,
- struct pt_regs *reg, struct switch_stack *sw)
+do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
+ struct pt_regs *regs, struct switch_stack *sw)
{
sigset_t oldset, set;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+ /* Indicate EINTR on return from any possible signal handler,
+ which will not come back through here, but via sigreturn. */
+ regs->r0 = EINTR;
+ regs->r19 = 1;
+
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&oldset, reg, sw, 0, 0))
+ if (do_signal(&oldset, regs, sw, 0, 0))
return -EINTR;
}
}
asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
{
return do_sigaltstack(uss, uoss, rdusp());
}
unsigned int retcode[3];
};
+/* If this changes, userland unwinders that Know Things about our signal
+ frame will break. Do not undertake lightly. It also implies an ABI
+ change wrt the size of siginfo_t, which may cause some pain. */
+extern char compile_time_assert
+ [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1];
+
#define INSN_MOV_R30_R16 0x47fe0410
#define INSN_LDI_R0 0x201f0000
#define INSN_CALLSYS 0x00000083
static long
-restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
struct switch_stack *sw)
{
unsigned long usp;
registers and transfer control from userland. */
asmlinkage void
-do_sigreturn(struct sigcontext *sc, struct pt_regs *regs,
+do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs,
struct switch_stack *sw)
{
sigset_t set;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
- info.si_addr = (void *) regs->pc;
+ info.si_addr = (void __user *) regs->pc;
info.si_trapno = 0;
send_sig_info(SIGTRAP, &info, current);
}
}
asmlinkage void
-do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
+do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs,
struct switch_stack *sw)
{
sigset_t set;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
- info.si_addr = (void *) regs->pc;
+ info.si_addr = (void __user *) regs->pc;
info.si_trapno = 0;
send_sig_info(SIGTRAP, &info, current);
}
* Set up a signal frame.
*/
-static inline void *
+static inline void __user *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
{
if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
- return (void *)((sp - frame_size) & -32ul);
+ return (void __user *)((sp - frame_size) & -32ul);
}
static long
-setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
struct switch_stack *sw, unsigned long mask, unsigned long sp)
{
long i, err = 0;
struct pt_regs *regs, struct switch_stack * sw)
{
unsigned long oldsp, r26, err = 0;
- struct sigframe *frame;
+ struct sigframe __user *frame;
oldsp = rdusp();
frame = get_sigframe(ka, oldsp, sizeof(*frame));
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void
sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
{
unsigned long oldsp, r26, err = 0;
- struct rt_sigframe *frame;
+ struct rt_sigframe __user *frame;
oldsp = rdusp();
frame = get_sigframe(ka, oldsp, sizeof(*frame));
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
siginfo_t info;
int signr;
unsigned long single_stepping = ptrace_cancel_bpt(current);
+ struct k_sigaction ka;
if (!oldset)
oldset = ¤t->blocked;
/* This lets the debugger run, ... */
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
/* ... so re-check the single stepping. */
single_stepping |= ptrace_cancel_bpt(current);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- struct k_sigaction *ka = ¤t->sighand->action[signr-1];
-
- if (r0) syscall_restart(r0, r19, regs, ka);
- handle_signal(signr, ka, &info, oldset, regs, sw);
+ if (r0) syscall_restart(r0, r19, regs, &ka);
+ handle_signal(signr, &ka, &info, oldset, regs, sw);
if (single_stepping)
ptrace_set_bpt(current); /* re-set bpt */
return 1;