/* $Id: signal.c,v 1.110 2002/02/08 03:57:14 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/tty.h>
#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/ptrace.h>
#include <asm/svr4.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h> /* flush_sig_insns */
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
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
* expects it to look which is basically:
*
* ---------------------------------- <-- %sp at signal time
* Struct sigcontext
* Signal address
* Ptr to sigcontext area above
* Signal code
* The signal number itself
* One register window
* ---------------------------------- <-- New %sp
*/
struct signal_sframe {
struct reg_window sig_window;
int sig_num;
int sig_code;
struct sigcontext __user *sig_scptr;
int sig_address;
struct sigcontext sig_context;
unsigned int extramask[_NSIG_WORDS - 1];
};
/*
* And the new one, intended to be used for Linux applications only
* (we have enough in there to work with clone).
* All the interesting bits are in the info field.
*/
struct new_signal_frame {
struct sparc_stackf ss;
__siginfo_t info;
__siginfo_fpu_t __user *fpu_save;
unsigned long insns[2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
struct rt_signal_frame {
struct sparc_stackf ss;
siginfo_t info;
struct pt_regs regs;
sigset_t mask;
__siginfo_fpu_t __user *fpu_save;
unsigned int insns[2];
stack_t stack;
unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
/* Align macros */
#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7)))
#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)
{
sigset_t saveset;
set &= _BLOCKABLE;
spin_lock_irq(¤t->sighand->siglock);
saveset = current->blocked;
siginitset(¤t->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(&saveset,