#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/binfmts.h> /* do_coredum */
+#include <linux/bitops.h>
#include <asm/uaccess.h>
-#include <asm/bitops.h>
#include <asm/ptrace.h>
#include <asm/svr4.h>
#include <asm/pgalloc.h>
void *fpqueue, unsigned long *fpqdepth);
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
- unsigned long orig_o0, int restart_syscall);
-
/* Signal frames: the original one (compatible with SunOS):
*
* Set up a signal frame... Make the stack look the way SunOS
#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
-/*
- * atomically swap in the new signal mask, and wait for a signal.
- * This is really tricky on the Sparc, watch out...
- */
-asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs)
+static int _sigpause_common(old_sigset_t set)
{
- sigset_t saveset;
-
set &= _BLOCKABLE;
spin_lock_irq(¤t->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
siginitset(¤t->blocked, set);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- regs->pc = regs->npc;
- regs->npc += 4;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
- /* Condition codes and return value where set here for sigpause,
- * and so got used by setup_frame, which again causes sigreturn()
- * to return -EINTR.
- */
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- /*
- * Return -EINTR and set condition code here,
- * so the interrupted system call actually returns
- * these.
- */
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(&saveset, regs, 0, 0))
- return;
- }
-}
-
-asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
-{
- _sigpause_common(set, regs);
+ return -ERESTARTNOHAND;
}
-asmlinkage void do_sigsuspend (struct pt_regs *regs)
+asmlinkage int sys_sigpause(unsigned int set)
{
- _sigpause_common(regs->u_regs[UREG_I0], regs);
+ return _sigpause_common(set);
}
-asmlinkage void do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
- struct pt_regs *regs)
+asmlinkage int sys_sigsuspend(old_sigset_t set)
{
- sigset_t oldset, set;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t)) {
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EINVAL;
- return;
- }
-
- if (copy_from_user(&set, uset, sizeof(set))) {
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EFAULT;
- return;
- }
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- oldset = current->blocked;
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- regs->pc = regs->npc;
- regs->npc += 4;
-
- /* Condition codes and return value where set here for sigpause,
- * and so got used by setup_frame, which again causes sigreturn()
- * to return -EINTR.
- */
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- /*
- * Return -EINTR and set condition code here,
- * so the interrupted system call actually returns
- * these.
- */
- regs->psr |= PSR_C;
- regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(&oldset, regs, 0, 0))
- return;
- }
+ return _sigpause_common(set);
}
static inline int
regs->psr &= ~PSR_EF;
#else
if (current == last_task_used_math) {
- last_task_used_math = 0;
+ last_task_used_math = NULL;
regs->psr &= ~PSR_EF;
}
#endif
- current->used_math = 1;
+ set_used_math();
clear_tsk_thread_flag(current, TIF_USEDFPU);
- if (verify_area(VERIFY_READ, fpu, sizeof(*fpu)))
+ if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
return -EFAULT;
err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
sf = (struct new_signal_frame __user *) regs->u_regs[UREG_FP];
/* 1. Make sure we are not getting garbage from the user */
- if (verify_area(VERIFY_READ, sf, sizeof(*sf)))
+ if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
goto segv_and_exit;
if (((unsigned long) sf) & 3)
return;
segv_and_exit:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_sigreturn(struct pt_regs *regs)
scptr = (struct sigcontext __user *) regs->u_regs[UREG_I0];
/* Check sanity of the user arg. */
- if (verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext)) ||
+ if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext)) ||
(((unsigned long) scptr) & 3))
goto segv_and_exit;
return;
segv_and_exit:
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
synchronize_user_stack();
sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
- if (verify_area(VERIFY_READ, sf, sizeof(*sf)) ||
+ if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
(((unsigned long) sf) & 0x03))
goto segv;
spin_unlock_irq(¤t->sighand->siglock);
return;
segv:
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
/* Checks if the fp is valid */
unsigned long pc = regs->pc;
unsigned long npc = regs->npc;
struct thread_info *tp = current_thread_info();
- void *sig_address;
+ void __user *sig_address;
int sig_code;
synchronize_user_stack();
sig_address = NULL;
}
}
- err |= __put_user((long)sig_address, &sframep->sig_address);
+ err |= __put_user((unsigned long)sig_address, &sframep->sig_address);
err |= __put_user(sig_code, &sframep->sig_code);
err |= __put_user(sc, &sframep->sig_scptr);
if (err)
sigill_and_return:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
put_psr(get_psr() | PSR_EF);
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
- last_task_used_math = 0;
+ last_task_used_math = NULL;
regs->psr &= ~(PSR_EF);
}
#endif
¤t->thread.fpqueue[0],
((sizeof(unsigned long) +
(sizeof(unsigned long *)))*16));
- current->used_math = 0;
+ clear_used_math();
return err;
}
synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
- if (!current->used_math)
+ if (!used_math())
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct new_signal_frame __user *)
err |= __put_user(0, &sf->extra_size);
- if (current->used_math) {
+ if (used_math()) {
err |= save_fpu_state(regs, &sf->fpu_state);
err |= __put_user(&sf->fpu_state, &sf->fpu_save);
} else {
regs->u_regs[UREG_FP] = (unsigned long) sf;
regs->u_regs[UREG_I0] = signo;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+ regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
/* 4. signal handler */
regs->pc = (unsigned long) ka->sa.sa_handler;
sigill_and_return:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signo, current);
}
static inline void
synchronize_user_stack();
sigframe_size = RT_ALIGNEDSZ;
- if (!current->used_math)
+ if (!used_math())
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct rt_signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
err |= __put_user(regs->npc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
psr = regs->psr;
- if (current->used_math)
+ if (used_math())
psr |= PSR_EF;
err |= __put_user(psr, &sf->regs.psr);
err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
regs->u_regs[UREG_FP] = (unsigned long) sf;
regs->u_regs[UREG_I0] = signo;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+ regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
regs->pc = (unsigned long) ka->sa.sa_handler;
regs->npc = (regs->pc + 4);
sigill:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signo, current);
}
/* Setup a Solaris stack frame */
* to flush the user windows.
*/
for (window = 0; window < tp->w_saved; window++) {
- err |= __put_user((int *) &(gw->win[window]), &gw->winptr[window]);
+ err |= __put_user((int __user *) &(gw->win[window]), &gw->winptr[window]);
err |= __copy_to_user(&gw->win[window],
&tp->reg_window[window],
sizeof(svr4_rwindow_t));
sigill_and_return:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs)
synchronize_user_stack();
if (current_thread_info()->w_saved)
- goto sigsegv_and_return;
+ return -EFAULT;
err = clear_user(uc, sizeof(*uc));
if (err)
* we have already stuffed all of it with sync_user_stack
*/
return (err ? -EFAULT : 0);
-
-sigsegv_and_return:
- do_exit(SIGSEGV);
}
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
return (err ? -EFAULT : 0);
sigsegv_and_return:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
}
static inline void
else
setup_frame(&ka->sa, regs, signr, oldset, info);
}
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
- if (!(ka->sa.sa_flags & SA_NOMASK)) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NOMASK))
sigaddset(¤t->blocked, signr);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
}
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
- unsigned long orig_i0, int restart_syscall)
+asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall)
{
siginfo_t info;
struct sparc_deliver_cookie cookie;
+ struct k_sigaction ka;
int signr;
+ sigset_t *oldset;
/*
* XXX Disable svr4 signal handling until solaris emulation works.
cookie.restart_syscall = restart_syscall;
cookie.orig_i0 = orig_i0;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
oldset = ¤t->blocked;
- signr = get_signal_to_deliver(&info, regs, &cookie);
+ signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
if (signr > 0) {
- struct k_sigaction *ka;
-
- ka = ¤t->sighand->action[signr-1];
-
if (cookie.restart_syscall)
- syscall_restart(cookie.orig_i0, regs, &ka->sa);
- handle_signal(signr, ka, &info, oldset, regs, svr4_signal);
- return 1;
+ syscall_restart(cookie.orig_i0, regs, &ka.sa);
+ handle_signal(signr, &ka, &info, oldset,
+ regs, svr4_signal);
+ /* 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 TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ return;
}
if (cookie.restart_syscall &&
(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
regs->pc -= 4;
regs->npc -= 4;
}
- return 0;
+
+ /* if there's no signal to deliver, we just put the saved sigmask
+ * back
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+ }
}
asmlinkage int