xref: /openbmc/linux/arch/alpha/kernel/signal.c (revision 50ececcf)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/alpha/kernel/signal.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1995  Linus Torvalds
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *  1997-11-02  Modified for POSIX.1b signals by Richard Henderson
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/sched.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/signal.h>
121da177e4SLinus Torvalds #include <linux/errno.h>
131da177e4SLinus Torvalds #include <linux/wait.h>
141da177e4SLinus Torvalds #include <linux/ptrace.h>
151da177e4SLinus Torvalds #include <linux/unistd.h>
161da177e4SLinus Torvalds #include <linux/mm.h>
171da177e4SLinus Torvalds #include <linux/smp.h>
181da177e4SLinus Torvalds #include <linux/stddef.h>
191da177e4SLinus Torvalds #include <linux/tty.h>
201da177e4SLinus Torvalds #include <linux/binfmts.h>
211da177e4SLinus Torvalds #include <linux/bitops.h>
22e5d9a90cSIvan Kokshaysky #include <linux/syscalls.h>
23733e5e4bSDavid Howells #include <linux/tracehook.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <asm/uaccess.h>
261da177e4SLinus Torvalds #include <asm/sigcontext.h>
271da177e4SLinus Torvalds #include <asm/ucontext.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include "proto.h"
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #define DEBUG_SIG 0
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds asmlinkage void ret_from_sys_call(void);
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds /*
391da177e4SLinus Torvalds  * The OSF/1 sigprocmask calling sequence is different from the
401da177e4SLinus Torvalds  * C sigprocmask() sequence..
411da177e4SLinus Torvalds  */
42c52c2ddcSAl Viro SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask)
431da177e4SLinus Torvalds {
44c52c2ddcSAl Viro 	sigset_t oldmask;
45c52c2ddcSAl Viro 	sigset_t mask;
46c52c2ddcSAl Viro 	unsigned long res;
471da177e4SLinus Torvalds 
4887400e54SLinus Torvalds 	siginitset(&mask, newmask & _BLOCKABLE);
490f44fbd2SLinus Torvalds 	res = sigprocmask(how, &mask, &oldmask);
50c52c2ddcSAl Viro 	if (!res) {
51c52c2ddcSAl Viro 		force_successful_syscall_return();
520f44fbd2SLinus Torvalds 		res = oldmask.sig[0];
531da177e4SLinus Torvalds 	}
54c52c2ddcSAl Viro 	return res;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
57e5d9a90cSIvan Kokshaysky SYSCALL_DEFINE3(osf_sigaction, int, sig,
58e5d9a90cSIvan Kokshaysky 		const struct osf_sigaction __user *, act,
59e5d9a90cSIvan Kokshaysky 		struct osf_sigaction __user *, oact)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
621da177e4SLinus Torvalds 	int ret;
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	if (act) {
651da177e4SLinus Torvalds 		old_sigset_t mask;
661da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
671da177e4SLinus Torvalds 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
6818e6bfa9SAl Viro 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
6918e6bfa9SAl Viro 		    __get_user(mask, &act->sa_mask))
701da177e4SLinus Torvalds 			return -EFAULT;
711da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
721da177e4SLinus Torvalds 		new_ka.ka_restorer = NULL;
731da177e4SLinus Torvalds 	}
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	if (!ret && oact) {
781da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
791da177e4SLinus Torvalds 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
8018e6bfa9SAl Viro 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
8118e6bfa9SAl Viro 		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
821da177e4SLinus Torvalds 			return -EFAULT;
831da177e4SLinus Torvalds 	}
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	return ret;
861da177e4SLinus Torvalds }
871da177e4SLinus Torvalds 
88e5d9a90cSIvan Kokshaysky SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
89e5d9a90cSIvan Kokshaysky 		struct sigaction __user *, oact,
90e5d9a90cSIvan Kokshaysky 		size_t, sigsetsize, void __user *, restorer)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
931da177e4SLinus Torvalds 	int ret;
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds 	/* XXX: Don't preclude handling different sized sigset_t's.  */
961da177e4SLinus Torvalds 	if (sigsetsize != sizeof(sigset_t))
971da177e4SLinus Torvalds 		return -EINVAL;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	if (act) {
1001da177e4SLinus Torvalds 		new_ka.ka_restorer = restorer;
1011da177e4SLinus Torvalds 		if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
1021da177e4SLinus Torvalds 			return -EFAULT;
1031da177e4SLinus Torvalds 	}
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	if (!ret && oact) {
1081da177e4SLinus Torvalds 		if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
1091da177e4SLinus Torvalds 			return -EFAULT;
1101da177e4SLinus Torvalds 	}
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 	return ret;
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds /*
1161da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
1171da177e4SLinus Torvalds  */
118392fb6e3SAl Viro SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
1191da177e4SLinus Torvalds {
1202561b069SMatt Fleming 	sigset_t blocked;
1212561b069SMatt Fleming 	siginitset(&blocked, mask);
12268f3f16dSAl Viro 	return sigsuspend(&blocked);
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds /*
1261da177e4SLinus Torvalds  * Do a signal return; undo the signal stack.
1271da177e4SLinus Torvalds  */
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds #if _NSIG_WORDS > 1
1301da177e4SLinus Torvalds # error "Non SA_SIGINFO frame needs rearranging"
1311da177e4SLinus Torvalds #endif
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds struct sigframe
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	struct sigcontext sc;
1361da177e4SLinus Torvalds 	unsigned int retcode[3];
1371da177e4SLinus Torvalds };
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds struct rt_sigframe
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds 	struct siginfo info;
1421da177e4SLinus Torvalds 	struct ucontext uc;
1431da177e4SLinus Torvalds 	unsigned int retcode[3];
1441da177e4SLinus Torvalds };
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /* If this changes, userland unwinders that Know Things about our signal
1471da177e4SLinus Torvalds    frame will break.  Do not undertake lightly.  It also implies an ABI
1481da177e4SLinus Torvalds    change wrt the size of siginfo_t, which may cause some pain.  */
1491da177e4SLinus Torvalds extern char compile_time_assert
1501da177e4SLinus Torvalds         [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1];
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds #define INSN_MOV_R30_R16	0x47fe0410
1531da177e4SLinus Torvalds #define INSN_LDI_R0		0x201f0000
1541da177e4SLinus Torvalds #define INSN_CALLSYS		0x00000083
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds static long
157b960f303SAl Viro restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
1581da177e4SLinus Torvalds {
1591da177e4SLinus Torvalds 	unsigned long usp;
160b960f303SAl Viro 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
1611da177e4SLinus Torvalds 	long i, err = __get_user(regs->pc, &sc->sc_pc);
1621da177e4SLinus Torvalds 
1632deba1bdSAl Viro 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
1642deba1bdSAl Viro 
1651da177e4SLinus Torvalds 	sw->r26 = (unsigned long) ret_from_sys_call;
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	err |= __get_user(regs->r0, sc->sc_regs+0);
1681da177e4SLinus Torvalds 	err |= __get_user(regs->r1, sc->sc_regs+1);
1691da177e4SLinus Torvalds 	err |= __get_user(regs->r2, sc->sc_regs+2);
1701da177e4SLinus Torvalds 	err |= __get_user(regs->r3, sc->sc_regs+3);
1711da177e4SLinus Torvalds 	err |= __get_user(regs->r4, sc->sc_regs+4);
1721da177e4SLinus Torvalds 	err |= __get_user(regs->r5, sc->sc_regs+5);
1731da177e4SLinus Torvalds 	err |= __get_user(regs->r6, sc->sc_regs+6);
1741da177e4SLinus Torvalds 	err |= __get_user(regs->r7, sc->sc_regs+7);
1751da177e4SLinus Torvalds 	err |= __get_user(regs->r8, sc->sc_regs+8);
1761da177e4SLinus Torvalds 	err |= __get_user(sw->r9, sc->sc_regs+9);
1771da177e4SLinus Torvalds 	err |= __get_user(sw->r10, sc->sc_regs+10);
1781da177e4SLinus Torvalds 	err |= __get_user(sw->r11, sc->sc_regs+11);
1791da177e4SLinus Torvalds 	err |= __get_user(sw->r12, sc->sc_regs+12);
1801da177e4SLinus Torvalds 	err |= __get_user(sw->r13, sc->sc_regs+13);
1811da177e4SLinus Torvalds 	err |= __get_user(sw->r14, sc->sc_regs+14);
1821da177e4SLinus Torvalds 	err |= __get_user(sw->r15, sc->sc_regs+15);
1831da177e4SLinus Torvalds 	err |= __get_user(regs->r16, sc->sc_regs+16);
1841da177e4SLinus Torvalds 	err |= __get_user(regs->r17, sc->sc_regs+17);
1851da177e4SLinus Torvalds 	err |= __get_user(regs->r18, sc->sc_regs+18);
1861da177e4SLinus Torvalds 	err |= __get_user(regs->r19, sc->sc_regs+19);
1871da177e4SLinus Torvalds 	err |= __get_user(regs->r20, sc->sc_regs+20);
1881da177e4SLinus Torvalds 	err |= __get_user(regs->r21, sc->sc_regs+21);
1891da177e4SLinus Torvalds 	err |= __get_user(regs->r22, sc->sc_regs+22);
1901da177e4SLinus Torvalds 	err |= __get_user(regs->r23, sc->sc_regs+23);
1911da177e4SLinus Torvalds 	err |= __get_user(regs->r24, sc->sc_regs+24);
1921da177e4SLinus Torvalds 	err |= __get_user(regs->r25, sc->sc_regs+25);
1931da177e4SLinus Torvalds 	err |= __get_user(regs->r26, sc->sc_regs+26);
1941da177e4SLinus Torvalds 	err |= __get_user(regs->r27, sc->sc_regs+27);
1951da177e4SLinus Torvalds 	err |= __get_user(regs->r28, sc->sc_regs+28);
1961da177e4SLinus Torvalds 	err |= __get_user(regs->gp, sc->sc_regs+29);
1971da177e4SLinus Torvalds 	err |= __get_user(usp, sc->sc_regs+30);
1981da177e4SLinus Torvalds 	wrusp(usp);
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	for (i = 0; i < 31; i++)
2011da177e4SLinus Torvalds 		err |= __get_user(sw->fp[i], sc->sc_fpregs+i);
2021da177e4SLinus Torvalds 	err |= __get_user(sw->fp[31], &sc->sc_fpcr);
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	return err;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds /* Note that this syscall is also used by setcontext(3) to install
2081da177e4SLinus Torvalds    a given sigcontext.  This because it's impossible to set *all*
2091da177e4SLinus Torvalds    registers and transfer control from userland.  */
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds asmlinkage void
212b960f303SAl Viro do_sigreturn(struct sigcontext __user *sc)
2131da177e4SLinus Torvalds {
214b960f303SAl Viro 	struct pt_regs *regs = current_pt_regs();
2151da177e4SLinus Torvalds 	sigset_t set;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	/* Verify that it's a good sigcontext before using it */
2181da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
2191da177e4SLinus Torvalds 		goto give_sigsegv;
2201da177e4SLinus Torvalds 	if (__get_user(set.sig[0], &sc->sc_mask))
2211da177e4SLinus Torvalds 		goto give_sigsegv;
2221da177e4SLinus Torvalds 
2232561b069SMatt Fleming 	set_current_blocked(&set);
2241da177e4SLinus Torvalds 
225b960f303SAl Viro 	if (restore_sigcontext(sc, regs))
2261da177e4SLinus Torvalds 		goto give_sigsegv;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	/* Send SIGTRAP if we're single-stepping: */
2291da177e4SLinus Torvalds 	if (ptrace_cancel_bpt (current)) {
2301da177e4SLinus Torvalds 		siginfo_t info;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 		info.si_signo = SIGTRAP;
2331da177e4SLinus Torvalds 		info.si_errno = 0;
2341da177e4SLinus Torvalds 		info.si_code = TRAP_BRKPT;
2351da177e4SLinus Torvalds 		info.si_addr = (void __user *) regs->pc;
2361da177e4SLinus Torvalds 		info.si_trapno = 0;
2371da177e4SLinus Torvalds 		send_sig_info(SIGTRAP, &info, current);
2381da177e4SLinus Torvalds 	}
2391da177e4SLinus Torvalds 	return;
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds give_sigsegv:
2421da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
2431da177e4SLinus Torvalds }
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds asmlinkage void
246b960f303SAl Viro do_rt_sigreturn(struct rt_sigframe __user *frame)
2471da177e4SLinus Torvalds {
248b960f303SAl Viro 	struct pt_regs *regs = current_pt_regs();
2491da177e4SLinus Torvalds 	sigset_t set;
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	/* Verify that it's a good ucontext_t before using it */
2521da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, &frame->uc, sizeof(frame->uc)))
2531da177e4SLinus Torvalds 		goto give_sigsegv;
2541da177e4SLinus Torvalds 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
2551da177e4SLinus Torvalds 		goto give_sigsegv;
2561da177e4SLinus Torvalds 
2572561b069SMatt Fleming 	set_current_blocked(&set);
2581da177e4SLinus Torvalds 
259b960f303SAl Viro 	if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
2601da177e4SLinus Torvalds 		goto give_sigsegv;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	/* Send SIGTRAP if we're single-stepping: */
2631da177e4SLinus Torvalds 	if (ptrace_cancel_bpt (current)) {
2641da177e4SLinus Torvalds 		siginfo_t info;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 		info.si_signo = SIGTRAP;
2671da177e4SLinus Torvalds 		info.si_errno = 0;
2681da177e4SLinus Torvalds 		info.si_code = TRAP_BRKPT;
2691da177e4SLinus Torvalds 		info.si_addr = (void __user *) regs->pc;
2701da177e4SLinus Torvalds 		info.si_trapno = 0;
2711da177e4SLinus Torvalds 		send_sig_info(SIGTRAP, &info, current);
2721da177e4SLinus Torvalds 	}
2731da177e4SLinus Torvalds 	return;
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds give_sigsegv:
2761da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds /*
2811da177e4SLinus Torvalds  * Set up a signal frame.
2821da177e4SLinus Torvalds  */
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds static inline void __user *
2851da177e4SLinus Torvalds get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
2861da177e4SLinus Torvalds {
287d09042daSLaurent MEYER 	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
2881da177e4SLinus Torvalds 		sp = current->sas_ss_sp + current->sas_ss_size;
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	return (void __user *)((sp - frame_size) & -32ul);
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds static long
2941da177e4SLinus Torvalds setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
295d9d0738aSAl Viro 		 unsigned long mask, unsigned long sp)
2961da177e4SLinus Torvalds {
297d9d0738aSAl Viro 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
2981da177e4SLinus Torvalds 	long i, err = 0;
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
3011da177e4SLinus Torvalds 	err |= __put_user(mask, &sc->sc_mask);
3021da177e4SLinus Torvalds 	err |= __put_user(regs->pc, &sc->sc_pc);
3031da177e4SLinus Torvalds 	err |= __put_user(8, &sc->sc_ps);
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	err |= __put_user(regs->r0 , sc->sc_regs+0);
3061da177e4SLinus Torvalds 	err |= __put_user(regs->r1 , sc->sc_regs+1);
3071da177e4SLinus Torvalds 	err |= __put_user(regs->r2 , sc->sc_regs+2);
3081da177e4SLinus Torvalds 	err |= __put_user(regs->r3 , sc->sc_regs+3);
3091da177e4SLinus Torvalds 	err |= __put_user(regs->r4 , sc->sc_regs+4);
3101da177e4SLinus Torvalds 	err |= __put_user(regs->r5 , sc->sc_regs+5);
3111da177e4SLinus Torvalds 	err |= __put_user(regs->r6 , sc->sc_regs+6);
3121da177e4SLinus Torvalds 	err |= __put_user(regs->r7 , sc->sc_regs+7);
3131da177e4SLinus Torvalds 	err |= __put_user(regs->r8 , sc->sc_regs+8);
3141da177e4SLinus Torvalds 	err |= __put_user(sw->r9   , sc->sc_regs+9);
3151da177e4SLinus Torvalds 	err |= __put_user(sw->r10  , sc->sc_regs+10);
3161da177e4SLinus Torvalds 	err |= __put_user(sw->r11  , sc->sc_regs+11);
3171da177e4SLinus Torvalds 	err |= __put_user(sw->r12  , sc->sc_regs+12);
3181da177e4SLinus Torvalds 	err |= __put_user(sw->r13  , sc->sc_regs+13);
3191da177e4SLinus Torvalds 	err |= __put_user(sw->r14  , sc->sc_regs+14);
3201da177e4SLinus Torvalds 	err |= __put_user(sw->r15  , sc->sc_regs+15);
3211da177e4SLinus Torvalds 	err |= __put_user(regs->r16, sc->sc_regs+16);
3221da177e4SLinus Torvalds 	err |= __put_user(regs->r17, sc->sc_regs+17);
3231da177e4SLinus Torvalds 	err |= __put_user(regs->r18, sc->sc_regs+18);
3241da177e4SLinus Torvalds 	err |= __put_user(regs->r19, sc->sc_regs+19);
3251da177e4SLinus Torvalds 	err |= __put_user(regs->r20, sc->sc_regs+20);
3261da177e4SLinus Torvalds 	err |= __put_user(regs->r21, sc->sc_regs+21);
3271da177e4SLinus Torvalds 	err |= __put_user(regs->r22, sc->sc_regs+22);
3281da177e4SLinus Torvalds 	err |= __put_user(regs->r23, sc->sc_regs+23);
3291da177e4SLinus Torvalds 	err |= __put_user(regs->r24, sc->sc_regs+24);
3301da177e4SLinus Torvalds 	err |= __put_user(regs->r25, sc->sc_regs+25);
3311da177e4SLinus Torvalds 	err |= __put_user(regs->r26, sc->sc_regs+26);
3321da177e4SLinus Torvalds 	err |= __put_user(regs->r27, sc->sc_regs+27);
3331da177e4SLinus Torvalds 	err |= __put_user(regs->r28, sc->sc_regs+28);
3341da177e4SLinus Torvalds 	err |= __put_user(regs->gp , sc->sc_regs+29);
3351da177e4SLinus Torvalds 	err |= __put_user(sp, sc->sc_regs+30);
3361da177e4SLinus Torvalds 	err |= __put_user(0, sc->sc_regs+31);
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	for (i = 0; i < 31; i++)
3391da177e4SLinus Torvalds 		err |= __put_user(sw->fp[i], sc->sc_fpregs+i);
3401da177e4SLinus Torvalds 	err |= __put_user(0, sc->sc_fpregs+31);
3411da177e4SLinus Torvalds 	err |= __put_user(sw->fp[31], &sc->sc_fpcr);
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0);
3441da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1);
3451da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2);
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	return err;
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds 
350b927b3e2SRichard Henderson static int
3511da177e4SLinus Torvalds setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
352d9d0738aSAl Viro 	    struct pt_regs *regs)
3531da177e4SLinus Torvalds {
3541da177e4SLinus Torvalds 	unsigned long oldsp, r26, err = 0;
3551da177e4SLinus Torvalds 	struct sigframe __user *frame;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	oldsp = rdusp();
3581da177e4SLinus Torvalds 	frame = get_sigframe(ka, oldsp, sizeof(*frame));
3591da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
360cbdfb9ffSAl Viro 		return -EFAULT;
3611da177e4SLinus Torvalds 
362d9d0738aSAl Viro 	err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp);
3631da177e4SLinus Torvalds 	if (err)
364cbdfb9ffSAl Viro 		return -EFAULT;
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub
3671da177e4SLinus Torvalds 	   already in userspace.  */
3681da177e4SLinus Torvalds 	if (ka->ka_restorer) {
3691da177e4SLinus Torvalds 		r26 = (unsigned long) ka->ka_restorer;
3701da177e4SLinus Torvalds 	} else {
3711da177e4SLinus Torvalds 		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
3721da177e4SLinus Torvalds 		err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
3731da177e4SLinus Torvalds 		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
3741da177e4SLinus Torvalds 		imb();
3751da177e4SLinus Torvalds 		r26 = (unsigned long) frame->retcode;
3761da177e4SLinus Torvalds 	}
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	/* Check that everything was written properly.  */
3791da177e4SLinus Torvalds 	if (err)
380cbdfb9ffSAl Viro 		return err;
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	/* "Return" to the handler */
3831da177e4SLinus Torvalds 	regs->r26 = r26;
3841da177e4SLinus Torvalds 	regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
3851da177e4SLinus Torvalds 	regs->r16 = sig;			/* a0: signal number */
3861da177e4SLinus Torvalds 	regs->r17 = 0;				/* a1: exception code */
3871da177e4SLinus Torvalds 	regs->r18 = (unsigned long) &frame->sc;	/* a2: sigcontext pointer */
3881da177e4SLinus Torvalds 	wrusp((unsigned long) frame);
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds #if DEBUG_SIG
3911da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
3921da177e4SLinus Torvalds 		current->comm, current->pid, frame, regs->pc, regs->r26);
3931da177e4SLinus Torvalds #endif
394b927b3e2SRichard Henderson 	return 0;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds 
397b927b3e2SRichard Henderson static int
3981da177e4SLinus Torvalds setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
399d9d0738aSAl Viro 	       sigset_t *set, struct pt_regs *regs)
4001da177e4SLinus Torvalds {
4011da177e4SLinus Torvalds 	unsigned long oldsp, r26, err = 0;
4021da177e4SLinus Torvalds 	struct rt_sigframe __user *frame;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	oldsp = rdusp();
4051da177e4SLinus Torvalds 	frame = get_sigframe(ka, oldsp, sizeof(*frame));
4061da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
407cbdfb9ffSAl Viro 		return -EFAULT;
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 	err |= copy_siginfo_to_user(&frame->info, info);
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	/* Create the ucontext.  */
4121da177e4SLinus Torvalds 	err |= __put_user(0, &frame->uc.uc_flags);
4131da177e4SLinus Torvalds 	err |= __put_user(0, &frame->uc.uc_link);
4141da177e4SLinus Torvalds 	err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
41550ececcfSAl Viro 	err |= __save_altstack(&frame->uc.uc_stack, oldsp);
416d9d0738aSAl Viro 	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs,
4171da177e4SLinus Torvalds 				set->sig[0], oldsp);
4181da177e4SLinus Torvalds 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
4191da177e4SLinus Torvalds 	if (err)
420cbdfb9ffSAl Viro 		return -EFAULT;
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub
4231da177e4SLinus Torvalds 	   already in userspace.  */
4241da177e4SLinus Torvalds 	if (ka->ka_restorer) {
4251da177e4SLinus Torvalds 		r26 = (unsigned long) ka->ka_restorer;
4261da177e4SLinus Torvalds 	} else {
4271da177e4SLinus Torvalds 		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
4281da177e4SLinus Torvalds 		err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
4291da177e4SLinus Torvalds 				  frame->retcode+1);
4301da177e4SLinus Torvalds 		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
4311da177e4SLinus Torvalds 		imb();
4321da177e4SLinus Torvalds 		r26 = (unsigned long) frame->retcode;
4331da177e4SLinus Torvalds 	}
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds 	if (err)
436cbdfb9ffSAl Viro 		return -EFAULT;
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	/* "Return" to the handler */
4391da177e4SLinus Torvalds 	regs->r26 = r26;
4401da177e4SLinus Torvalds 	regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
4411da177e4SLinus Torvalds 	regs->r16 = sig;			  /* a0: signal number */
4421da177e4SLinus Torvalds 	regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
4431da177e4SLinus Torvalds 	regs->r18 = (unsigned long) &frame->uc;	  /* a2: ucontext pointer */
4441da177e4SLinus Torvalds 	wrusp((unsigned long) frame);
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds #if DEBUG_SIG
4471da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
4481da177e4SLinus Torvalds 		current->comm, current->pid, frame, regs->pc, regs->r26);
4491da177e4SLinus Torvalds #endif
4501da177e4SLinus Torvalds 
451b927b3e2SRichard Henderson 	return 0;
4521da177e4SLinus Torvalds }
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds /*
4561da177e4SLinus Torvalds  * OK, we're invoking a handler.
4571da177e4SLinus Torvalds  */
458cbdfb9ffSAl Viro static inline void
4591da177e4SLinus Torvalds handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
460d9d0738aSAl Viro 	      struct pt_regs * regs)
4611da177e4SLinus Torvalds {
462b7f9a11aSAl Viro 	sigset_t *oldset = sigmask_to_save();
463b927b3e2SRichard Henderson 	int ret;
464b927b3e2SRichard Henderson 
4651da177e4SLinus Torvalds 	if (ka->sa.sa_flags & SA_SIGINFO)
466d9d0738aSAl Viro 		ret = setup_rt_frame(sig, ka, info, oldset, regs);
4671da177e4SLinus Torvalds 	else
468d9d0738aSAl Viro 		ret = setup_frame(sig, ka, oldset, regs);
4691da177e4SLinus Torvalds 
470cbdfb9ffSAl Viro 	if (ret) {
471cbdfb9ffSAl Viro 		force_sigsegv(sig, current);
472cbdfb9ffSAl Viro 		return;
473cbdfb9ffSAl Viro 	}
474efee984cSAl Viro 	signal_delivered(sig, info, ka, regs, 0);
475b927b3e2SRichard Henderson }
476b927b3e2SRichard Henderson 
4771da177e4SLinus Torvalds static inline void
4781da177e4SLinus Torvalds syscall_restart(unsigned long r0, unsigned long r19,
4791da177e4SLinus Torvalds 		struct pt_regs *regs, struct k_sigaction *ka)
4801da177e4SLinus Torvalds {
4811da177e4SLinus Torvalds 	switch (regs->r0) {
4821da177e4SLinus Torvalds 	case ERESTARTSYS:
4831da177e4SLinus Torvalds 		if (!(ka->sa.sa_flags & SA_RESTART)) {
4841da177e4SLinus Torvalds 		case ERESTARTNOHAND:
4851da177e4SLinus Torvalds 			regs->r0 = EINTR;
4861da177e4SLinus Torvalds 			break;
4871da177e4SLinus Torvalds 		}
4881da177e4SLinus Torvalds 		/* fallthrough */
4891da177e4SLinus Torvalds 	case ERESTARTNOINTR:
4901da177e4SLinus Torvalds 		regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
4911da177e4SLinus Torvalds 		regs->r19 = r19;
4921da177e4SLinus Torvalds 		regs->pc -= 4;
4931da177e4SLinus Torvalds 		break;
4941da177e4SLinus Torvalds 	case ERESTART_RESTARTBLOCK:
4951da177e4SLinus Torvalds 		regs->r0 = EINTR;
4961da177e4SLinus Torvalds 		break;
4971da177e4SLinus Torvalds 	}
4981da177e4SLinus Torvalds }
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds /*
5021da177e4SLinus Torvalds  * Note that 'init' is a special process: it doesn't get signals it doesn't
5031da177e4SLinus Torvalds  * want to handle. Thus you cannot kill init even with a SIGKILL even by
5041da177e4SLinus Torvalds  * mistake.
5051da177e4SLinus Torvalds  *
5061da177e4SLinus Torvalds  * Note that we go through the signals twice: once to check the signals that
5071da177e4SLinus Torvalds  * the kernel can handle, and then we build all the user-level signal handling
5081da177e4SLinus Torvalds  * stack-frames in one go after that.
5091da177e4SLinus Torvalds  *
5101da177e4SLinus Torvalds  * "r0" and "r19" are the registers we need to restore for system call
5111da177e4SLinus Torvalds  * restart. "r0" is also used as an indicator whether we can restart at
5121da177e4SLinus Torvalds  * all (if we get here from anything but a syscall return, it will be 0)
5131da177e4SLinus Torvalds  */
514b927b3e2SRichard Henderson static void
515d9d0738aSAl Viro do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
5161da177e4SLinus Torvalds {
5171da177e4SLinus Torvalds 	siginfo_t info;
5181da177e4SLinus Torvalds 	int signr;
5191da177e4SLinus Torvalds 	unsigned long single_stepping = ptrace_cancel_bpt(current);
5201da177e4SLinus Torvalds 	struct k_sigaction ka;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	/* This lets the debugger run, ... */
5231da177e4SLinus Torvalds 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
524b927b3e2SRichard Henderson 
5251da177e4SLinus Torvalds 	/* ... so re-check the single stepping. */
5261da177e4SLinus Torvalds 	single_stepping |= ptrace_cancel_bpt(current);
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	if (signr > 0) {
5291da177e4SLinus Torvalds 		/* Whee!  Actually deliver the signal.  */
530b927b3e2SRichard Henderson 		if (r0)
531b927b3e2SRichard Henderson 			syscall_restart(r0, r19, regs, &ka);
532d9d0738aSAl Viro 		handle_signal(signr, &ka, &info, regs);
5331da177e4SLinus Torvalds 		if (single_stepping)
5341da177e4SLinus Torvalds 			ptrace_set_bpt(current); /* re-set bpt */
535b927b3e2SRichard Henderson 		return;
5361da177e4SLinus Torvalds 	}
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	if (r0) {
5391da177e4SLinus Torvalds 	  	switch (regs->r0) {
5401da177e4SLinus Torvalds 		case ERESTARTNOHAND:
5411da177e4SLinus Torvalds 		case ERESTARTSYS:
5421da177e4SLinus Torvalds 		case ERESTARTNOINTR:
5431da177e4SLinus Torvalds 			/* Reset v0 and a3 and replay syscall.  */
5441da177e4SLinus Torvalds 			regs->r0 = r0;
5451da177e4SLinus Torvalds 			regs->r19 = r19;
5461da177e4SLinus Torvalds 			regs->pc -= 4;
5471da177e4SLinus Torvalds 			break;
5481da177e4SLinus Torvalds 		case ERESTART_RESTARTBLOCK:
5491da177e4SLinus Torvalds 			/* Force v0 to the restart syscall and reply.  */
5501da177e4SLinus Torvalds 			regs->r0 = __NR_restart_syscall;
5511da177e4SLinus Torvalds 			regs->pc -= 4;
5521da177e4SLinus Torvalds 			break;
5531da177e4SLinus Torvalds 		}
5541da177e4SLinus Torvalds 	}
555b927b3e2SRichard Henderson 
556b927b3e2SRichard Henderson 	/* If there's no signal to deliver, we just restore the saved mask.  */
55751a7b448SAl Viro 	restore_saved_sigmask();
5581da177e4SLinus Torvalds 	if (single_stepping)
5591da177e4SLinus Torvalds 		ptrace_set_bpt(current);	/* re-set breakpoint */
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds void
563cb450766SAl Viro do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
564b927b3e2SRichard Henderson 		 unsigned long r0, unsigned long r19)
5651da177e4SLinus Torvalds {
5666972d6f2SAl Viro 	do {
5676972d6f2SAl Viro 		if (thread_flags & _TIF_NEED_RESCHED) {
5686972d6f2SAl Viro 			schedule();
5696972d6f2SAl Viro 		} else {
5706972d6f2SAl Viro 			local_irq_enable();
5716972d6f2SAl Viro 			if (thread_flags & _TIF_SIGPENDING) {
572d9d0738aSAl Viro 				do_signal(regs, r0, r19);
5736972d6f2SAl Viro 				r0 = 0;
5746972d6f2SAl Viro 			} else {
575d0420c83SDavid Howells 				clear_thread_flag(TIF_NOTIFY_RESUME);
576d0420c83SDavid Howells 				tracehook_notify_resume(regs);
577d0420c83SDavid Howells 			}
5781da177e4SLinus Torvalds 		}
5796972d6f2SAl Viro 		local_irq_disable();
5806972d6f2SAl Viro 		thread_flags = current_thread_info()->flags;
5816972d6f2SAl Viro 	} while (thread_flags & _TIF_WORK_MASK);
5826972d6f2SAl Viro }
583