xref: /openbmc/linux/arch/alpha/kernel/signal.c (revision 7de5f68d)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/arch/alpha/kernel/signal.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1995  Linus Torvalds
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  1997-11-02  Modified for POSIX.1b signals by Richard Henderson
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
103f07c014SIngo Molnar #include <linux/sched/signal.h>
1168db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/signal.h>
141da177e4SLinus Torvalds #include <linux/errno.h>
151da177e4SLinus Torvalds #include <linux/wait.h>
161da177e4SLinus Torvalds #include <linux/ptrace.h>
171da177e4SLinus Torvalds #include <linux/unistd.h>
181da177e4SLinus Torvalds #include <linux/mm.h>
191da177e4SLinus Torvalds #include <linux/smp.h>
201da177e4SLinus Torvalds #include <linux/stddef.h>
211da177e4SLinus Torvalds #include <linux/tty.h>
221da177e4SLinus Torvalds #include <linux/binfmts.h>
231da177e4SLinus Torvalds #include <linux/bitops.h>
24e5d9a90cSIvan Kokshaysky #include <linux/syscalls.h>
25733e5e4bSDavid Howells #include <linux/tracehook.h>
261da177e4SLinus Torvalds 
277c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
281da177e4SLinus Torvalds #include <asm/sigcontext.h>
291da177e4SLinus Torvalds #include <asm/ucontext.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include "proto.h"
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #define DEBUG_SIG 0
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds asmlinkage void ret_from_sys_call(void);
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds /*
411da177e4SLinus Torvalds  * The OSF/1 sigprocmask calling sequence is different from the
421da177e4SLinus Torvalds  * C sigprocmask() sequence..
431da177e4SLinus Torvalds  */
44c52c2ddcSAl Viro SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask)
451da177e4SLinus Torvalds {
46c52c2ddcSAl Viro 	sigset_t oldmask;
47c52c2ddcSAl Viro 	sigset_t mask;
48c52c2ddcSAl Viro 	unsigned long res;
491da177e4SLinus Torvalds 
5087400e54SLinus Torvalds 	siginitset(&mask, newmask & _BLOCKABLE);
510f44fbd2SLinus Torvalds 	res = sigprocmask(how, &mask, &oldmask);
52c52c2ddcSAl Viro 	if (!res) {
53c52c2ddcSAl Viro 		force_successful_syscall_return();
540f44fbd2SLinus Torvalds 		res = oldmask.sig[0];
551da177e4SLinus Torvalds 	}
56c52c2ddcSAl Viro 	return res;
571da177e4SLinus Torvalds }
581da177e4SLinus Torvalds 
59e5d9a90cSIvan Kokshaysky SYSCALL_DEFINE3(osf_sigaction, int, sig,
60e5d9a90cSIvan Kokshaysky 		const struct osf_sigaction __user *, act,
61e5d9a90cSIvan Kokshaysky 		struct osf_sigaction __user *, oact)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
641da177e4SLinus Torvalds 	int ret;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	if (act) {
671da177e4SLinus Torvalds 		old_sigset_t mask;
6896d4f267SLinus Torvalds 		if (!access_ok(act, sizeof(*act)) ||
691da177e4SLinus Torvalds 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
7018e6bfa9SAl Viro 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
7118e6bfa9SAl Viro 		    __get_user(mask, &act->sa_mask))
721da177e4SLinus Torvalds 			return -EFAULT;
731da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
741da177e4SLinus Torvalds 		new_ka.ka_restorer = NULL;
751da177e4SLinus Torvalds 	}
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	if (!ret && oact) {
8096d4f267SLinus Torvalds 		if (!access_ok(oact, sizeof(*oact)) ||
811da177e4SLinus Torvalds 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
8218e6bfa9SAl Viro 		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
8318e6bfa9SAl Viro 		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
841da177e4SLinus Torvalds 			return -EFAULT;
851da177e4SLinus Torvalds 	}
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	return ret;
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
90e5d9a90cSIvan Kokshaysky SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
91e5d9a90cSIvan Kokshaysky 		struct sigaction __user *, oact,
92e5d9a90cSIvan Kokshaysky 		size_t, sigsetsize, void __user *, restorer)
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
951da177e4SLinus Torvalds 	int ret;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	/* XXX: Don't preclude handling different sized sigset_t's.  */
981da177e4SLinus Torvalds 	if (sigsetsize != sizeof(sigset_t))
991da177e4SLinus Torvalds 		return -EINVAL;
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	if (act) {
1021da177e4SLinus Torvalds 		new_ka.ka_restorer = restorer;
1031da177e4SLinus Torvalds 		if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
1041da177e4SLinus Torvalds 			return -EFAULT;
1051da177e4SLinus Torvalds 	}
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	if (!ret && oact) {
1101da177e4SLinus Torvalds 		if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
1111da177e4SLinus Torvalds 			return -EFAULT;
1121da177e4SLinus Torvalds 	}
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	return ret;
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds /*
1181da177e4SLinus Torvalds  * Do a signal return; undo the signal stack.
1191da177e4SLinus Torvalds  */
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds #if _NSIG_WORDS > 1
1221da177e4SLinus Torvalds # error "Non SA_SIGINFO frame needs rearranging"
1231da177e4SLinus Torvalds #endif
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds struct sigframe
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds 	struct sigcontext sc;
1281da177e4SLinus Torvalds 	unsigned int retcode[3];
1291da177e4SLinus Torvalds };
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds struct rt_sigframe
1321da177e4SLinus Torvalds {
1331da177e4SLinus Torvalds 	struct siginfo info;
1341da177e4SLinus Torvalds 	struct ucontext uc;
1351da177e4SLinus Torvalds 	unsigned int retcode[3];
1361da177e4SLinus Torvalds };
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds /* If this changes, userland unwinders that Know Things about our signal
1391da177e4SLinus Torvalds    frame will break.  Do not undertake lightly.  It also implies an ABI
1401da177e4SLinus Torvalds    change wrt the size of siginfo_t, which may cause some pain.  */
1411da177e4SLinus Torvalds extern char compile_time_assert
1421da177e4SLinus Torvalds         [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1];
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds #define INSN_MOV_R30_R16	0x47fe0410
1451da177e4SLinus Torvalds #define INSN_LDI_R0		0x201f0000
1461da177e4SLinus Torvalds #define INSN_CALLSYS		0x00000083
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds static long
149b960f303SAl Viro restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	unsigned long usp;
152b960f303SAl Viro 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
1531da177e4SLinus Torvalds 	long i, err = __get_user(regs->pc, &sc->sc_pc);
1541da177e4SLinus Torvalds 
155f56141e3SAndy Lutomirski 	current->restart_block.fn = do_no_restart_syscall;
1562deba1bdSAl Viro 
1571da177e4SLinus Torvalds 	sw->r26 = (unsigned long) ret_from_sys_call;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	err |= __get_user(regs->r0, sc->sc_regs+0);
1601da177e4SLinus Torvalds 	err |= __get_user(regs->r1, sc->sc_regs+1);
1611da177e4SLinus Torvalds 	err |= __get_user(regs->r2, sc->sc_regs+2);
1621da177e4SLinus Torvalds 	err |= __get_user(regs->r3, sc->sc_regs+3);
1631da177e4SLinus Torvalds 	err |= __get_user(regs->r4, sc->sc_regs+4);
1641da177e4SLinus Torvalds 	err |= __get_user(regs->r5, sc->sc_regs+5);
1651da177e4SLinus Torvalds 	err |= __get_user(regs->r6, sc->sc_regs+6);
1661da177e4SLinus Torvalds 	err |= __get_user(regs->r7, sc->sc_regs+7);
1671da177e4SLinus Torvalds 	err |= __get_user(regs->r8, sc->sc_regs+8);
1681da177e4SLinus Torvalds 	err |= __get_user(sw->r9, sc->sc_regs+9);
1691da177e4SLinus Torvalds 	err |= __get_user(sw->r10, sc->sc_regs+10);
1701da177e4SLinus Torvalds 	err |= __get_user(sw->r11, sc->sc_regs+11);
1711da177e4SLinus Torvalds 	err |= __get_user(sw->r12, sc->sc_regs+12);
1721da177e4SLinus Torvalds 	err |= __get_user(sw->r13, sc->sc_regs+13);
1731da177e4SLinus Torvalds 	err |= __get_user(sw->r14, sc->sc_regs+14);
1741da177e4SLinus Torvalds 	err |= __get_user(sw->r15, sc->sc_regs+15);
1751da177e4SLinus Torvalds 	err |= __get_user(regs->r16, sc->sc_regs+16);
1761da177e4SLinus Torvalds 	err |= __get_user(regs->r17, sc->sc_regs+17);
1771da177e4SLinus Torvalds 	err |= __get_user(regs->r18, sc->sc_regs+18);
1781da177e4SLinus Torvalds 	err |= __get_user(regs->r19, sc->sc_regs+19);
1791da177e4SLinus Torvalds 	err |= __get_user(regs->r20, sc->sc_regs+20);
1801da177e4SLinus Torvalds 	err |= __get_user(regs->r21, sc->sc_regs+21);
1811da177e4SLinus Torvalds 	err |= __get_user(regs->r22, sc->sc_regs+22);
1821da177e4SLinus Torvalds 	err |= __get_user(regs->r23, sc->sc_regs+23);
1831da177e4SLinus Torvalds 	err |= __get_user(regs->r24, sc->sc_regs+24);
1841da177e4SLinus Torvalds 	err |= __get_user(regs->r25, sc->sc_regs+25);
1851da177e4SLinus Torvalds 	err |= __get_user(regs->r26, sc->sc_regs+26);
1861da177e4SLinus Torvalds 	err |= __get_user(regs->r27, sc->sc_regs+27);
1871da177e4SLinus Torvalds 	err |= __get_user(regs->r28, sc->sc_regs+28);
1881da177e4SLinus Torvalds 	err |= __get_user(regs->gp, sc->sc_regs+29);
1891da177e4SLinus Torvalds 	err |= __get_user(usp, sc->sc_regs+30);
1901da177e4SLinus Torvalds 	wrusp(usp);
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	for (i = 0; i < 31; i++)
1931da177e4SLinus Torvalds 		err |= __get_user(sw->fp[i], sc->sc_fpregs+i);
1941da177e4SLinus Torvalds 	err |= __get_user(sw->fp[31], &sc->sc_fpcr);
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	return err;
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds /* Note that this syscall is also used by setcontext(3) to install
2001da177e4SLinus Torvalds    a given sigcontext.  This because it's impossible to set *all*
2011da177e4SLinus Torvalds    registers and transfer control from userland.  */
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds asmlinkage void
204b960f303SAl Viro do_sigreturn(struct sigcontext __user *sc)
2051da177e4SLinus Torvalds {
206b960f303SAl Viro 	struct pt_regs *regs = current_pt_regs();
2071da177e4SLinus Torvalds 	sigset_t set;
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/* Verify that it's a good sigcontext before using it */
21096d4f267SLinus Torvalds 	if (!access_ok(sc, sizeof(*sc)))
2111da177e4SLinus Torvalds 		goto give_sigsegv;
2121da177e4SLinus Torvalds 	if (__get_user(set.sig[0], &sc->sc_mask))
2131da177e4SLinus Torvalds 		goto give_sigsegv;
2141da177e4SLinus Torvalds 
2152561b069SMatt Fleming 	set_current_blocked(&set);
2161da177e4SLinus Torvalds 
217b960f303SAl Viro 	if (restore_sigcontext(sc, regs))
2181da177e4SLinus Torvalds 		goto give_sigsegv;
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 	/* Send SIGTRAP if we're single-stepping: */
2211da177e4SLinus Torvalds 	if (ptrace_cancel_bpt (current)) {
222*7de5f68dSEric W. Biederman 		send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *) regs->pc,
2235f50245bSEric W. Biederman 			       current);
2241da177e4SLinus Torvalds 	}
2251da177e4SLinus Torvalds 	return;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds give_sigsegv:
2283cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds asmlinkage void
232b960f303SAl Viro do_rt_sigreturn(struct rt_sigframe __user *frame)
2331da177e4SLinus Torvalds {
234b960f303SAl Viro 	struct pt_regs *regs = current_pt_regs();
2351da177e4SLinus Torvalds 	sigset_t set;
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds 	/* Verify that it's a good ucontext_t before using it */
23896d4f267SLinus Torvalds 	if (!access_ok(&frame->uc, sizeof(frame->uc)))
2391da177e4SLinus Torvalds 		goto give_sigsegv;
2401da177e4SLinus Torvalds 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
2411da177e4SLinus Torvalds 		goto give_sigsegv;
2421da177e4SLinus Torvalds 
2432561b069SMatt Fleming 	set_current_blocked(&set);
2441da177e4SLinus Torvalds 
245b960f303SAl Viro 	if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
2461da177e4SLinus Torvalds 		goto give_sigsegv;
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	/* Send SIGTRAP if we're single-stepping: */
2491da177e4SLinus Torvalds 	if (ptrace_cancel_bpt (current)) {
250*7de5f68dSEric W. Biederman 		send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *) regs->pc,
2515f50245bSEric W. Biederman 			       current);
2521da177e4SLinus Torvalds 	}
2531da177e4SLinus Torvalds 	return;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds give_sigsegv:
2563cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds /*
2611da177e4SLinus Torvalds  * Set up a signal frame.
2621da177e4SLinus Torvalds  */
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds static inline void __user *
265cfd60c07SAl Viro get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size)
2661da177e4SLinus Torvalds {
267cfd60c07SAl Viro 	return (void __user *)((sigsp(sp, ksig) - frame_size) & -32ul);
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds static long
2711da177e4SLinus Torvalds setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
272d9d0738aSAl Viro 		 unsigned long mask, unsigned long sp)
2731da177e4SLinus Torvalds {
274d9d0738aSAl Viro 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
2751da177e4SLinus Torvalds 	long i, err = 0;
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
2781da177e4SLinus Torvalds 	err |= __put_user(mask, &sc->sc_mask);
2791da177e4SLinus Torvalds 	err |= __put_user(regs->pc, &sc->sc_pc);
2801da177e4SLinus Torvalds 	err |= __put_user(8, &sc->sc_ps);
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	err |= __put_user(regs->r0 , sc->sc_regs+0);
2831da177e4SLinus Torvalds 	err |= __put_user(regs->r1 , sc->sc_regs+1);
2841da177e4SLinus Torvalds 	err |= __put_user(regs->r2 , sc->sc_regs+2);
2851da177e4SLinus Torvalds 	err |= __put_user(regs->r3 , sc->sc_regs+3);
2861da177e4SLinus Torvalds 	err |= __put_user(regs->r4 , sc->sc_regs+4);
2871da177e4SLinus Torvalds 	err |= __put_user(regs->r5 , sc->sc_regs+5);
2881da177e4SLinus Torvalds 	err |= __put_user(regs->r6 , sc->sc_regs+6);
2891da177e4SLinus Torvalds 	err |= __put_user(regs->r7 , sc->sc_regs+7);
2901da177e4SLinus Torvalds 	err |= __put_user(regs->r8 , sc->sc_regs+8);
2911da177e4SLinus Torvalds 	err |= __put_user(sw->r9   , sc->sc_regs+9);
2921da177e4SLinus Torvalds 	err |= __put_user(sw->r10  , sc->sc_regs+10);
2931da177e4SLinus Torvalds 	err |= __put_user(sw->r11  , sc->sc_regs+11);
2941da177e4SLinus Torvalds 	err |= __put_user(sw->r12  , sc->sc_regs+12);
2951da177e4SLinus Torvalds 	err |= __put_user(sw->r13  , sc->sc_regs+13);
2961da177e4SLinus Torvalds 	err |= __put_user(sw->r14  , sc->sc_regs+14);
2971da177e4SLinus Torvalds 	err |= __put_user(sw->r15  , sc->sc_regs+15);
2981da177e4SLinus Torvalds 	err |= __put_user(regs->r16, sc->sc_regs+16);
2991da177e4SLinus Torvalds 	err |= __put_user(regs->r17, sc->sc_regs+17);
3001da177e4SLinus Torvalds 	err |= __put_user(regs->r18, sc->sc_regs+18);
3011da177e4SLinus Torvalds 	err |= __put_user(regs->r19, sc->sc_regs+19);
3021da177e4SLinus Torvalds 	err |= __put_user(regs->r20, sc->sc_regs+20);
3031da177e4SLinus Torvalds 	err |= __put_user(regs->r21, sc->sc_regs+21);
3041da177e4SLinus Torvalds 	err |= __put_user(regs->r22, sc->sc_regs+22);
3051da177e4SLinus Torvalds 	err |= __put_user(regs->r23, sc->sc_regs+23);
3061da177e4SLinus Torvalds 	err |= __put_user(regs->r24, sc->sc_regs+24);
3071da177e4SLinus Torvalds 	err |= __put_user(regs->r25, sc->sc_regs+25);
3081da177e4SLinus Torvalds 	err |= __put_user(regs->r26, sc->sc_regs+26);
3091da177e4SLinus Torvalds 	err |= __put_user(regs->r27, sc->sc_regs+27);
3101da177e4SLinus Torvalds 	err |= __put_user(regs->r28, sc->sc_regs+28);
3111da177e4SLinus Torvalds 	err |= __put_user(regs->gp , sc->sc_regs+29);
3121da177e4SLinus Torvalds 	err |= __put_user(sp, sc->sc_regs+30);
3131da177e4SLinus Torvalds 	err |= __put_user(0, sc->sc_regs+31);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	for (i = 0; i < 31; i++)
3161da177e4SLinus Torvalds 		err |= __put_user(sw->fp[i], sc->sc_fpregs+i);
3171da177e4SLinus Torvalds 	err |= __put_user(0, sc->sc_fpregs+31);
3181da177e4SLinus Torvalds 	err |= __put_user(sw->fp[31], &sc->sc_fpcr);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0);
3211da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1);
3221da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2);
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	return err;
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds 
327b927b3e2SRichard Henderson static int
328cfd60c07SAl Viro setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
3291da177e4SLinus Torvalds {
3301da177e4SLinus Torvalds 	unsigned long oldsp, r26, err = 0;
3311da177e4SLinus Torvalds 	struct sigframe __user *frame;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	oldsp = rdusp();
334cfd60c07SAl Viro 	frame = get_sigframe(ksig, oldsp, sizeof(*frame));
33596d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
336cbdfb9ffSAl Viro 		return -EFAULT;
3371da177e4SLinus Torvalds 
338d9d0738aSAl Viro 	err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp);
3391da177e4SLinus Torvalds 	if (err)
340cbdfb9ffSAl Viro 		return -EFAULT;
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub
3431da177e4SLinus Torvalds 	   already in userspace.  */
344cfd60c07SAl Viro 	r26 = (unsigned long) ksig->ka.ka_restorer;
345cfd60c07SAl Viro 	if (!r26) {
3461da177e4SLinus Torvalds 		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
3471da177e4SLinus Torvalds 		err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
3481da177e4SLinus Torvalds 		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
3491da177e4SLinus Torvalds 		imb();
3501da177e4SLinus Torvalds 		r26 = (unsigned long) frame->retcode;
3511da177e4SLinus Torvalds 	}
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	/* Check that everything was written properly.  */
3541da177e4SLinus Torvalds 	if (err)
355cbdfb9ffSAl Viro 		return err;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	/* "Return" to the handler */
3581da177e4SLinus Torvalds 	regs->r26 = r26;
359cfd60c07SAl Viro 	regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
360cfd60c07SAl Viro 	regs->r16 = ksig->sig;			/* a0: signal number */
3611da177e4SLinus Torvalds 	regs->r17 = 0;				/* a1: exception code */
3621da177e4SLinus Torvalds 	regs->r18 = (unsigned long) &frame->sc;	/* a2: sigcontext pointer */
3631da177e4SLinus Torvalds 	wrusp((unsigned long) frame);
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds #if DEBUG_SIG
3661da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
3671da177e4SLinus Torvalds 		current->comm, current->pid, frame, regs->pc, regs->r26);
3681da177e4SLinus Torvalds #endif
369b927b3e2SRichard Henderson 	return 0;
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
372b927b3e2SRichard Henderson static int
373cfd60c07SAl Viro setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
3741da177e4SLinus Torvalds {
3751da177e4SLinus Torvalds 	unsigned long oldsp, r26, err = 0;
3761da177e4SLinus Torvalds 	struct rt_sigframe __user *frame;
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	oldsp = rdusp();
379cfd60c07SAl Viro 	frame = get_sigframe(ksig, oldsp, sizeof(*frame));
38096d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
381cbdfb9ffSAl Viro 		return -EFAULT;
3821da177e4SLinus Torvalds 
383cfd60c07SAl Viro 	err |= copy_siginfo_to_user(&frame->info, &ksig->info);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	/* Create the ucontext.  */
3861da177e4SLinus Torvalds 	err |= __put_user(0, &frame->uc.uc_flags);
3871da177e4SLinus Torvalds 	err |= __put_user(0, &frame->uc.uc_link);
3881da177e4SLinus Torvalds 	err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
38950ececcfSAl Viro 	err |= __save_altstack(&frame->uc.uc_stack, oldsp);
390d9d0738aSAl Viro 	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs,
3911da177e4SLinus Torvalds 				set->sig[0], oldsp);
3921da177e4SLinus Torvalds 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
3931da177e4SLinus Torvalds 	if (err)
394cbdfb9ffSAl Viro 		return -EFAULT;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub
3971da177e4SLinus Torvalds 	   already in userspace.  */
398cfd60c07SAl Viro 	r26 = (unsigned long) ksig->ka.ka_restorer;
399cfd60c07SAl Viro 	if (!r26) {
4001da177e4SLinus Torvalds 		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
4011da177e4SLinus Torvalds 		err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
4021da177e4SLinus Torvalds 				  frame->retcode+1);
4031da177e4SLinus Torvalds 		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
4041da177e4SLinus Torvalds 		imb();
4051da177e4SLinus Torvalds 		r26 = (unsigned long) frame->retcode;
4061da177e4SLinus Torvalds 	}
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 	if (err)
409cbdfb9ffSAl Viro 		return -EFAULT;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	/* "Return" to the handler */
4121da177e4SLinus Torvalds 	regs->r26 = r26;
413cfd60c07SAl Viro 	regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
414cfd60c07SAl Viro 	regs->r16 = ksig->sig;			  /* a0: signal number */
4151da177e4SLinus Torvalds 	regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
4161da177e4SLinus Torvalds 	regs->r18 = (unsigned long) &frame->uc;	  /* a2: ucontext pointer */
4171da177e4SLinus Torvalds 	wrusp((unsigned long) frame);
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds #if DEBUG_SIG
4201da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
4211da177e4SLinus Torvalds 		current->comm, current->pid, frame, regs->pc, regs->r26);
4221da177e4SLinus Torvalds #endif
4231da177e4SLinus Torvalds 
424b927b3e2SRichard Henderson 	return 0;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds /*
4291da177e4SLinus Torvalds  * OK, we're invoking a handler.
4301da177e4SLinus Torvalds  */
431cbdfb9ffSAl Viro static inline void
432cfd60c07SAl Viro handle_signal(struct ksignal *ksig, struct pt_regs *regs)
4331da177e4SLinus Torvalds {
434b7f9a11aSAl Viro 	sigset_t *oldset = sigmask_to_save();
435b927b3e2SRichard Henderson 	int ret;
436b927b3e2SRichard Henderson 
437cfd60c07SAl Viro 	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
438cfd60c07SAl Viro 		ret = setup_rt_frame(ksig, oldset, regs);
4391da177e4SLinus Torvalds 	else
440cfd60c07SAl Viro 		ret = setup_frame(ksig, oldset, regs);
4411da177e4SLinus Torvalds 
442cfd60c07SAl Viro 	signal_setup_done(ret, ksig, 0);
443b927b3e2SRichard Henderson }
444b927b3e2SRichard Henderson 
4451da177e4SLinus Torvalds static inline void
4461da177e4SLinus Torvalds syscall_restart(unsigned long r0, unsigned long r19,
4471da177e4SLinus Torvalds 		struct pt_regs *regs, struct k_sigaction *ka)
4481da177e4SLinus Torvalds {
4491da177e4SLinus Torvalds 	switch (regs->r0) {
4501da177e4SLinus Torvalds 	case ERESTARTSYS:
4511da177e4SLinus Torvalds 		if (!(ka->sa.sa_flags & SA_RESTART)) {
4521da177e4SLinus Torvalds 		case ERESTARTNOHAND:
4531da177e4SLinus Torvalds 			regs->r0 = EINTR;
4541da177e4SLinus Torvalds 			break;
4551da177e4SLinus Torvalds 		}
456df561f66SGustavo A. R. Silva 		fallthrough;
4571da177e4SLinus Torvalds 	case ERESTARTNOINTR:
4581da177e4SLinus Torvalds 		regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
4591da177e4SLinus Torvalds 		regs->r19 = r19;
4601da177e4SLinus Torvalds 		regs->pc -= 4;
4611da177e4SLinus Torvalds 		break;
4621da177e4SLinus Torvalds 	case ERESTART_RESTARTBLOCK:
4631da177e4SLinus Torvalds 		regs->r0 = EINTR;
4641da177e4SLinus Torvalds 		break;
4651da177e4SLinus Torvalds 	}
4661da177e4SLinus Torvalds }
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds /*
4701da177e4SLinus Torvalds  * Note that 'init' is a special process: it doesn't get signals it doesn't
4711da177e4SLinus Torvalds  * want to handle. Thus you cannot kill init even with a SIGKILL even by
4721da177e4SLinus Torvalds  * mistake.
4731da177e4SLinus Torvalds  *
4741da177e4SLinus Torvalds  * Note that we go through the signals twice: once to check the signals that
4751da177e4SLinus Torvalds  * the kernel can handle, and then we build all the user-level signal handling
4761da177e4SLinus Torvalds  * stack-frames in one go after that.
4771da177e4SLinus Torvalds  *
4781da177e4SLinus Torvalds  * "r0" and "r19" are the registers we need to restore for system call
4791da177e4SLinus Torvalds  * restart. "r0" is also used as an indicator whether we can restart at
4801da177e4SLinus Torvalds  * all (if we get here from anything but a syscall return, it will be 0)
4811da177e4SLinus Torvalds  */
482b927b3e2SRichard Henderson static void
483d9d0738aSAl Viro do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
4841da177e4SLinus Torvalds {
4851da177e4SLinus Torvalds 	unsigned long single_stepping = ptrace_cancel_bpt(current);
486cfd60c07SAl Viro 	struct ksignal ksig;
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds 	/* This lets the debugger run, ... */
489cfd60c07SAl Viro 	if (get_signal(&ksig)) {
4901da177e4SLinus Torvalds 		/* ... so re-check the single stepping. */
4911da177e4SLinus Torvalds 		single_stepping |= ptrace_cancel_bpt(current);
4921da177e4SLinus Torvalds 		/* Whee!  Actually deliver the signal.  */
493b927b3e2SRichard Henderson 		if (r0)
494cfd60c07SAl Viro 			syscall_restart(r0, r19, regs, &ksig.ka);
495cfd60c07SAl Viro 		handle_signal(&ksig, regs);
496cfd60c07SAl Viro 	} else {
497cfd60c07SAl Viro 		single_stepping |= ptrace_cancel_bpt(current);
4981da177e4SLinus Torvalds 		if (r0) {
4991da177e4SLinus Torvalds 			switch (regs->r0) {
5001da177e4SLinus Torvalds 			case ERESTARTNOHAND:
5011da177e4SLinus Torvalds 			case ERESTARTSYS:
5021da177e4SLinus Torvalds 			case ERESTARTNOINTR:
5031da177e4SLinus Torvalds 				/* Reset v0 and a3 and replay syscall.  */
5041da177e4SLinus Torvalds 				regs->r0 = r0;
5051da177e4SLinus Torvalds 				regs->r19 = r19;
5061da177e4SLinus Torvalds 				regs->pc -= 4;
5071da177e4SLinus Torvalds 				break;
5081da177e4SLinus Torvalds 			case ERESTART_RESTARTBLOCK:
509cfd60c07SAl Viro 				/* Set v0 to the restart_syscall and replay */
5101da177e4SLinus Torvalds 				regs->r0 = __NR_restart_syscall;
5111da177e4SLinus Torvalds 				regs->pc -= 4;
5121da177e4SLinus Torvalds 				break;
5131da177e4SLinus Torvalds 			}
5141da177e4SLinus Torvalds 		}
51551a7b448SAl Viro 		restore_saved_sigmask();
516cfd60c07SAl Viro 	}
5171da177e4SLinus Torvalds 	if (single_stepping)
5181da177e4SLinus Torvalds 		ptrace_set_bpt(current);	/* re-set breakpoint */
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds void
522cb450766SAl Viro do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
523b927b3e2SRichard Henderson 		 unsigned long r0, unsigned long r19)
5241da177e4SLinus Torvalds {
5256972d6f2SAl Viro 	do {
5266972d6f2SAl Viro 		if (thread_flags & _TIF_NEED_RESCHED) {
5276972d6f2SAl Viro 			schedule();
5286972d6f2SAl Viro 		} else {
5296972d6f2SAl Viro 			local_irq_enable();
5305a9a8897SJens Axboe 			if (thread_flags & (_TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL)) {
531d9d0738aSAl Viro 				do_signal(regs, r0, r19);
5326972d6f2SAl Viro 				r0 = 0;
5336972d6f2SAl Viro 			} else {
534d0420c83SDavid Howells 				tracehook_notify_resume(regs);
535d0420c83SDavid Howells 			}
5361da177e4SLinus Torvalds 		}
5376972d6f2SAl Viro 		local_irq_disable();
5386972d6f2SAl Viro 		thread_flags = current_thread_info()->flags;
5396972d6f2SAl Viro 	} while (thread_flags & _TIF_WORK_MASK);
5406972d6f2SAl Viro }
541