⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal32.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  $Id: signal32.c,v 1.74 2002/02/09 19:49:30 davem Exp $ *  arch/sparc64/kernel/signal32.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) *  Copyright (C) 1997,1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz) */#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_lock.h>#include <linux/binfmts.h>#include <linux/compat.h>#include <linux/bitops.h>#include <asm/uaccess.h>#include <asm/ptrace.h>#include <asm/svr4.h>#include <asm/pgtable.h>#include <asm/psrcompat.h>#include <asm/fpumacro.h>#include <asm/visasm.h>#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))int do_signal32(sigset_t *oldset, struct pt_regs *regs,		unsigned long orig_o0, int ret_from_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_sframe32 {	struct reg_window32 sig_window;	int sig_num;	int sig_code;	/* struct sigcontext32 * */ u32 sig_scptr;	int sig_address;	struct sigcontext32 sig_context;	unsigned int extramask[_COMPAT_NSIG_WORDS - 1];};/* This magic should be in g_upper[0] for all upper parts * to be valid. */#define SIGINFO_EXTRA_V8PLUS_MAGIC	0x130e269typedef struct {	unsigned int g_upper[8];	unsigned int o_upper[8];	unsigned int asi;} siginfo_extra_v8plus_t;/*  * 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_frame32 {	struct sparc_stackf32	ss;	__siginfo32_t		info;	/* __siginfo_fpu32_t * */ u32 fpu_save;	unsigned int		insns[2];	unsigned int		extramask[_COMPAT_NSIG_WORDS - 1];	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */	/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */	siginfo_extra_v8plus_t	v8plus;	__siginfo_fpu_t		fpu_state;};typedef struct compat_siginfo{	int si_signo;	int si_errno;	int si_code;	union {		int _pad[SI_PAD_SIZE32];		/* kill() */		struct {			compat_pid_t _pid;		/* sender's pid */			unsigned int _uid;		/* sender's uid */		} _kill;		/* POSIX.1b timers */		struct {			compat_timer_t _tid;			/* timer id */			int _overrun;			/* overrun count */			compat_sigval_t _sigval;		/* same as below */			int _sys_private;		/* not to be passed to user */		} _timer;		/* POSIX.1b signals */		struct {			compat_pid_t _pid;		/* sender's pid */			unsigned int _uid;		/* sender's uid */			compat_sigval_t _sigval;		} _rt;		/* SIGCHLD */		struct {			compat_pid_t _pid;		/* which child */			unsigned int _uid;		/* sender's uid */			int _status;			/* exit code */			compat_clock_t _utime;			compat_clock_t _stime;		} _sigchld;		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */		struct {			u32 _addr; /* faulting insn/memory ref. */			int _trapno;		} _sigfault;		/* SIGPOLL */		struct {			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */			int _fd;		} _sigpoll;	} _sifields;}compat_siginfo_t;struct rt_signal_frame32 {	struct sparc_stackf32	ss;	compat_siginfo_t	info;	struct pt_regs32	regs;	compat_sigset_t		mask;	/* __siginfo_fpu32_t * */ u32 fpu_save;	unsigned int		insns[2];	stack_t32		stack;	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */	/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */	siginfo_extra_v8plus_t	v8plus;	__siginfo_fpu_t		fpu_state;};/* Align macros */#define SF_ALIGNEDSZ  (((sizeof(struct signal_sframe32) + 7) & (~7)))#define NF_ALIGNEDSZ  (((sizeof(struct new_signal_frame32) + 7) & (~7)))#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame32) + 7) & (~7)))int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from){	int err;	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))		return -EFAULT;	/* If you change siginfo_t structure, please be sure	   this code is fixed accordingly.	   It should never copy any pad contained in the structure	   to avoid security leaks, but must copy the generic	   3 ints plus the relevant union member.	   This routine must convert siginfo from 64bit to 32bit as well	   at the same time.  */	err = __put_user(from->si_signo, &to->si_signo);	err |= __put_user(from->si_errno, &to->si_errno);	err |= __put_user((short)from->si_code, &to->si_code);	if (from->si_code < 0)		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);	else {		switch (from->si_code >> 16) {		case __SI_TIMER >> 16:			err |= __put_user(from->si_tid, &to->si_tid);			err |= __put_user(from->si_overrun, &to->si_overrun);			err |= __put_user(from->si_int, &to->si_int);			break;		case __SI_CHLD >> 16:			err |= __put_user(from->si_utime, &to->si_utime);			err |= __put_user(from->si_stime, &to->si_stime);			err |= __put_user(from->si_status, &to->si_status);		default:			err |= __put_user(from->si_pid, &to->si_pid);			err |= __put_user(from->si_uid, &to->si_uid);			break;		case __SI_FAULT >> 16:			err |= __put_user(from->si_trapno, &to->si_trapno);			err |= __put_user((unsigned long)from->si_addr, &to->si_addr);			break;		case __SI_POLL >> 16:			err |= __put_user(from->si_band, &to->si_band);			err |= __put_user(from->si_fd, &to->si_fd);			break;		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */		case __SI_MESGQ >> 16:			err |= __put_user(from->si_pid, &to->si_pid);			err |= __put_user(from->si_uid, &to->si_uid);			err |= __put_user(from->si_int, &to->si_int);			break;		}	}	return err;}/* CAUTION: This is just a very minimalist implementation for the *          sake of compat_sys_rt_sigqueueinfo() */int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from){	if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t)))		return -EFAULT;	if (copy_from_user(to, from, 3*sizeof(int)) ||	    copy_from_user(to->_sifields._pad, from->_sifields._pad,			   SI_PAD_SIZE))		return -EFAULT;	return 0;}/* * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... */asmlinkage void _sigpause32_common(compat_old_sigset_t set, struct pt_regs *regs){	sigset_t saveset;	set &= _BLOCKABLE;	spin_lock_irq(&current->sighand->siglock);	saveset = current->blocked;	siginitset(&current->blocked, set);	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);		regs->tpc = regs->tnpc;	regs->tnpc += 4;	if (test_thread_flag(TIF_32BIT)) {		regs->tpc &= 0xffffffff;		regs->tnpc &= 0xffffffff;	}	/* 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->tstate |= TSTATE_ICARRY;		regs->u_regs[UREG_I0] = EINTR;		if (do_signal32(&saveset, regs, 0, 0))			return;	}}asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *regs){	sigset_t oldset, set;	compat_sigset_t set32;        	/* XXX: Don't preclude handling different sized sigset_t's.  */	if (((compat_size_t)sigsetsize) != sizeof(sigset_t)) {		regs->tstate |= TSTATE_ICARRY;		regs->u_regs[UREG_I0] = EINVAL;		return;	}	if (copy_from_user(&set32, compat_ptr(uset), sizeof(set32))) {		regs->tstate |= TSTATE_ICARRY;		regs->u_regs[UREG_I0] = EFAULT;		return;	}	switch (_NSIG_WORDS) {	case 4: set.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32);	case 3: set.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32);	case 2: set.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32);	case 1: set.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32);	}	sigdelsetmask(&set, ~_BLOCKABLE);	spin_lock_irq(&current->sighand->siglock);	oldset = current->blocked;	current->blocked = set;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);		regs->tpc = regs->tnpc;	regs->tnpc += 4;	if (test_thread_flag(TIF_32BIT)) {		regs->tpc &= 0xffffffff;		regs->tnpc &= 0xffffffff;	}	/* 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->tstate |= TSTATE_ICARRY;		regs->u_regs[UREG_I0] = EINTR;		if (do_signal32(&oldset, regs, 0, 0))			return;	}}static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu){	unsigned long *fpregs = current_thread_info()->fpregs;	unsigned long fprs;	int err;		err = __get_user(fprs, &fpu->si_fprs);	fprs_write(0);	regs->tstate &= ~TSTATE_PEF;	if (fprs & FPRS_DL)		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));	if (fprs & FPRS_DU)		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);	current_thread_info()->fpsaved[0] |= fprs;	return err;}void do_new_sigreturn32(struct pt_regs *regs){	struct new_signal_frame32 __user *sf;	unsigned int psr;	unsigned pc, npc, fpu_save;	sigset_t set;	unsigned seta[_COMPAT_NSIG_WORDS];	int err, i;		regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;	sf = (struct new_signal_frame32 __user *) regs->u_regs[UREG_FP];	/* 1. Make sure we are not getting garbage from the user */	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||	    (((unsigned long) sf) & 3))		goto segv;	get_user(pc, &sf->info.si_regs.pc);	__get_user(npc, &sf->info.si_regs.npc);	if ((pc | npc) & 3)		goto segv;	if (test_thread_flag(TIF_32BIT)) {		pc &= 0xffffffff;		npc &= 0xffffffff;	}	regs->tpc = pc;	regs->tnpc = npc;	/* 2. Restore the state */	err = __get_user(regs->y, &sf->info.si_regs.y);	err |= __get_user(psr, &sf->info.si_regs.psr);	for (i = UREG_G1; i <= UREG_I7; i++)		err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);	if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {		err |= __get_user(i, &sf->v8plus.g_upper[0]);		if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {			unsigned long asi;			for (i = UREG_G1; i <= UREG_I7; i++)				err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);			err |= __get_user(asi, &sf->v8plus.asi);			regs->tstate &= ~TSTATE_ASI;			regs->tstate |= ((asi & 0xffUL) << 24UL);		}	}	/* User can only change condition codes in %tstate. */	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);	regs->tstate |= psr_to_tstate_icc(psr);	err |= __get_user(fpu_save, &sf->fpu_save);	if (fpu_save)		err |= restore_fpu_state32(regs, &sf->fpu_state);	err |= __get_user(seta[0], &sf->info.si_mask);	err |= copy_from_user(seta+1, &sf->extramask,			      (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));	if (err)	    	goto segv;	switch (_NSIG_WORDS) {		case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);		case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);		case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);		case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);	}	sigdelsetmask(&set, ~_BLOCKABLE);	spin_lock_irq(&current->sighand->siglock);	current->blocked = set;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);	return;segv:	force_sig(SIGSEGV, current);}asmlinkage void do_sigreturn32(struct pt_regs *regs){	struct sigcontext32 __user *scptr;	unsigned int pc, npc, psr;	sigset_t set;	unsigned int seta[_COMPAT_NSIG_WORDS];	int err;	/* Always make any pending restarted system calls return -EINTR */	current_thread_info()->restart_block.fn = do_no_restart_syscall;	synchronize_user_stack();	if (test_thread_flag(TIF_NEWSIGNALS)) {		do_new_sigreturn32(regs);		return;	}	scptr = (struct sigcontext32 __user *)		(regs->u_regs[UREG_I0] & 0x00000000ffffffffUL);	/* Check sanity of the user arg. */	if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||	    (((unsigned long) scptr) & 3))		goto segv;	err = __get_user(pc, &scptr->sigc_pc);	err |= __get_user(npc, &scptr->sigc_npc);	if ((pc | npc) & 3)		goto segv; /* Nice try. */	err |= __get_user(seta[0], &scptr->sigc_mask);	/* Note that scptr + 1 points to extramask */	err |= copy_from_user(seta+1, scptr + 1,			      (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));	if (err)	    	goto segv;	switch (_NSIG_WORDS) {		case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);		case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);		case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);		case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);	}	sigdelsetmask(&set, ~_BLOCKABLE);	spin_lock_irq(&current->sighand->siglock);	current->blocked = set;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);		if (test_thread_flag(TIF_32BIT)) {		pc &= 0xffffffff;		npc &= 0xffffffff;	}	regs->tpc = pc;	regs->tnpc = npc;	err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);	err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);	err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);	/* User can only change condition codes in %tstate. */	err |= __get_user(psr, &scptr->sigc_psr);	if (err)		goto segv;	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);	regs->tstate |= psr_to_tstate_icc(psr);	return;segv:	force_sig(SIGSEGV, current);}asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -