xref: /openbmc/linux/arch/alpha/kernel/signal.c (revision 05096666)
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>
2503248addSEric W. Biederman #include <linux/resume_user_mode.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  */
SYSCALL_DEFINE2(osf_sigprocmask,int,how,unsigned long,newmask)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 
SYSCALL_DEFINE3(osf_sigaction,int,sig,const struct osf_sigaction __user *,act,struct osf_sigaction __user *,oact)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 
SYSCALL_DEFINE5(rt_sigaction,int,sig,const struct sigaction __user *,act,struct sigaction __user *,oact,size_t,sigsetsize,void __user *,restorer)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
restore_sigcontext(struct sigcontext __user * sc,struct pt_regs * regs)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;
153*05096666SAl Viro 	long err = __get_user(regs->pc, &sc->sc_pc);
1541da177e4SLinus Torvalds 
155f56141e3SAndy Lutomirski 	current->restart_block.fn = do_no_restart_syscall;
156*05096666SAl Viro 	current_thread_info()->status |= TS_SAVED_FP | TS_RESTORE_FP;
1572deba1bdSAl Viro 
1581da177e4SLinus Torvalds 	sw->r26 = (unsigned long) ret_from_sys_call;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	err |= __get_user(regs->r0, sc->sc_regs+0);
1611da177e4SLinus Torvalds 	err |= __get_user(regs->r1, sc->sc_regs+1);
1621da177e4SLinus Torvalds 	err |= __get_user(regs->r2, sc->sc_regs+2);
1631da177e4SLinus Torvalds 	err |= __get_user(regs->r3, sc->sc_regs+3);
1641da177e4SLinus Torvalds 	err |= __get_user(regs->r4, sc->sc_regs+4);
1651da177e4SLinus Torvalds 	err |= __get_user(regs->r5, sc->sc_regs+5);
1661da177e4SLinus Torvalds 	err |= __get_user(regs->r6, sc->sc_regs+6);
1671da177e4SLinus Torvalds 	err |= __get_user(regs->r7, sc->sc_regs+7);
1681da177e4SLinus Torvalds 	err |= __get_user(regs->r8, sc->sc_regs+8);
1691da177e4SLinus Torvalds 	err |= __get_user(sw->r9, sc->sc_regs+9);
1701da177e4SLinus Torvalds 	err |= __get_user(sw->r10, sc->sc_regs+10);
1711da177e4SLinus Torvalds 	err |= __get_user(sw->r11, sc->sc_regs+11);
1721da177e4SLinus Torvalds 	err |= __get_user(sw->r12, sc->sc_regs+12);
1731da177e4SLinus Torvalds 	err |= __get_user(sw->r13, sc->sc_regs+13);
1741da177e4SLinus Torvalds 	err |= __get_user(sw->r14, sc->sc_regs+14);
1751da177e4SLinus Torvalds 	err |= __get_user(sw->r15, sc->sc_regs+15);
1761da177e4SLinus Torvalds 	err |= __get_user(regs->r16, sc->sc_regs+16);
1771da177e4SLinus Torvalds 	err |= __get_user(regs->r17, sc->sc_regs+17);
1781da177e4SLinus Torvalds 	err |= __get_user(regs->r18, sc->sc_regs+18);
1791da177e4SLinus Torvalds 	err |= __get_user(regs->r19, sc->sc_regs+19);
1801da177e4SLinus Torvalds 	err |= __get_user(regs->r20, sc->sc_regs+20);
1811da177e4SLinus Torvalds 	err |= __get_user(regs->r21, sc->sc_regs+21);
1821da177e4SLinus Torvalds 	err |= __get_user(regs->r22, sc->sc_regs+22);
1831da177e4SLinus Torvalds 	err |= __get_user(regs->r23, sc->sc_regs+23);
1841da177e4SLinus Torvalds 	err |= __get_user(regs->r24, sc->sc_regs+24);
1851da177e4SLinus Torvalds 	err |= __get_user(regs->r25, sc->sc_regs+25);
1861da177e4SLinus Torvalds 	err |= __get_user(regs->r26, sc->sc_regs+26);
1871da177e4SLinus Torvalds 	err |= __get_user(regs->r27, sc->sc_regs+27);
1881da177e4SLinus Torvalds 	err |= __get_user(regs->r28, sc->sc_regs+28);
1891da177e4SLinus Torvalds 	err |= __get_user(regs->gp, sc->sc_regs+29);
1901da177e4SLinus Torvalds 	err |= __get_user(usp, sc->sc_regs+30);
1911da177e4SLinus Torvalds 	wrusp(usp);
1921da177e4SLinus Torvalds 
193*05096666SAl Viro 	err |= __copy_from_user(current_thread_info()->fp,
194*05096666SAl Viro 				sc->sc_fpregs, 31 * 8);
195*05096666SAl Viro 	err |= __get_user(current_thread_info()->fp[31], &sc->sc_fpcr);
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	return err;
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds /* Note that this syscall is also used by setcontext(3) to install
2011da177e4SLinus Torvalds    a given sigcontext.  This because it's impossible to set *all*
2021da177e4SLinus Torvalds    registers and transfer control from userland.  */
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds asmlinkage void
do_sigreturn(struct sigcontext __user * sc)205b960f303SAl Viro do_sigreturn(struct sigcontext __user *sc)
2061da177e4SLinus Torvalds {
207b960f303SAl Viro 	struct pt_regs *regs = current_pt_regs();
2081da177e4SLinus Torvalds 	sigset_t set;
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	/* Verify that it's a good sigcontext before using it */
21196d4f267SLinus Torvalds 	if (!access_ok(sc, sizeof(*sc)))
2121da177e4SLinus Torvalds 		goto give_sigsegv;
2131da177e4SLinus Torvalds 	if (__get_user(set.sig[0], &sc->sc_mask))
2141da177e4SLinus Torvalds 		goto give_sigsegv;
2151da177e4SLinus Torvalds 
2162561b069SMatt Fleming 	set_current_blocked(&set);
2171da177e4SLinus Torvalds 
218b960f303SAl Viro 	if (restore_sigcontext(sc, regs))
2191da177e4SLinus Torvalds 		goto give_sigsegv;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	/* Send SIGTRAP if we're single-stepping: */
2221da177e4SLinus Torvalds 	if (ptrace_cancel_bpt (current)) {
2237de5f68dSEric W. Biederman 		send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *) regs->pc,
2245f50245bSEric W. Biederman 			       current);
2251da177e4SLinus Torvalds 	}
2261da177e4SLinus Torvalds 	return;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds give_sigsegv:
2293cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds asmlinkage void
do_rt_sigreturn(struct rt_sigframe __user * frame)233b960f303SAl Viro do_rt_sigreturn(struct rt_sigframe __user *frame)
2341da177e4SLinus Torvalds {
235b960f303SAl Viro 	struct pt_regs *regs = current_pt_regs();
2361da177e4SLinus Torvalds 	sigset_t set;
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 	/* Verify that it's a good ucontext_t before using it */
23996d4f267SLinus Torvalds 	if (!access_ok(&frame->uc, sizeof(frame->uc)))
2401da177e4SLinus Torvalds 		goto give_sigsegv;
2411da177e4SLinus Torvalds 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
2421da177e4SLinus Torvalds 		goto give_sigsegv;
2431da177e4SLinus Torvalds 
2442561b069SMatt Fleming 	set_current_blocked(&set);
2451da177e4SLinus Torvalds 
246b960f303SAl Viro 	if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
2471da177e4SLinus Torvalds 		goto give_sigsegv;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	/* Send SIGTRAP if we're single-stepping: */
2501da177e4SLinus Torvalds 	if (ptrace_cancel_bpt (current)) {
2517de5f68dSEric W. Biederman 		send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *) regs->pc,
2525f50245bSEric W. Biederman 			       current);
2531da177e4SLinus Torvalds 	}
2541da177e4SLinus Torvalds 	return;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds give_sigsegv:
2573cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds /*
2621da177e4SLinus Torvalds  * Set up a signal frame.
2631da177e4SLinus Torvalds  */
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds static inline void __user *
get_sigframe(struct ksignal * ksig,unsigned long sp,size_t frame_size)266cfd60c07SAl Viro get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size)
2671da177e4SLinus Torvalds {
268cfd60c07SAl Viro 	return (void __user *)((sigsp(sp, ksig) - frame_size) & -32ul);
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds static long
setup_sigcontext(struct sigcontext __user * sc,struct pt_regs * regs,unsigned long mask,unsigned long sp)2721da177e4SLinus Torvalds setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
273d9d0738aSAl Viro 		 unsigned long mask, unsigned long sp)
2741da177e4SLinus Torvalds {
275d9d0738aSAl Viro 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
276*05096666SAl Viro 	long err = 0;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
2791da177e4SLinus Torvalds 	err |= __put_user(mask, &sc->sc_mask);
2801da177e4SLinus Torvalds 	err |= __put_user(regs->pc, &sc->sc_pc);
2811da177e4SLinus Torvalds 	err |= __put_user(8, &sc->sc_ps);
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	err |= __put_user(regs->r0 , sc->sc_regs+0);
2841da177e4SLinus Torvalds 	err |= __put_user(regs->r1 , sc->sc_regs+1);
2851da177e4SLinus Torvalds 	err |= __put_user(regs->r2 , sc->sc_regs+2);
2861da177e4SLinus Torvalds 	err |= __put_user(regs->r3 , sc->sc_regs+3);
2871da177e4SLinus Torvalds 	err |= __put_user(regs->r4 , sc->sc_regs+4);
2881da177e4SLinus Torvalds 	err |= __put_user(regs->r5 , sc->sc_regs+5);
2891da177e4SLinus Torvalds 	err |= __put_user(regs->r6 , sc->sc_regs+6);
2901da177e4SLinus Torvalds 	err |= __put_user(regs->r7 , sc->sc_regs+7);
2911da177e4SLinus Torvalds 	err |= __put_user(regs->r8 , sc->sc_regs+8);
2921da177e4SLinus Torvalds 	err |= __put_user(sw->r9   , sc->sc_regs+9);
2931da177e4SLinus Torvalds 	err |= __put_user(sw->r10  , sc->sc_regs+10);
2941da177e4SLinus Torvalds 	err |= __put_user(sw->r11  , sc->sc_regs+11);
2951da177e4SLinus Torvalds 	err |= __put_user(sw->r12  , sc->sc_regs+12);
2961da177e4SLinus Torvalds 	err |= __put_user(sw->r13  , sc->sc_regs+13);
2971da177e4SLinus Torvalds 	err |= __put_user(sw->r14  , sc->sc_regs+14);
2981da177e4SLinus Torvalds 	err |= __put_user(sw->r15  , sc->sc_regs+15);
2991da177e4SLinus Torvalds 	err |= __put_user(regs->r16, sc->sc_regs+16);
3001da177e4SLinus Torvalds 	err |= __put_user(regs->r17, sc->sc_regs+17);
3011da177e4SLinus Torvalds 	err |= __put_user(regs->r18, sc->sc_regs+18);
3021da177e4SLinus Torvalds 	err |= __put_user(regs->r19, sc->sc_regs+19);
3031da177e4SLinus Torvalds 	err |= __put_user(regs->r20, sc->sc_regs+20);
3041da177e4SLinus Torvalds 	err |= __put_user(regs->r21, sc->sc_regs+21);
3051da177e4SLinus Torvalds 	err |= __put_user(regs->r22, sc->sc_regs+22);
3061da177e4SLinus Torvalds 	err |= __put_user(regs->r23, sc->sc_regs+23);
3071da177e4SLinus Torvalds 	err |= __put_user(regs->r24, sc->sc_regs+24);
3081da177e4SLinus Torvalds 	err |= __put_user(regs->r25, sc->sc_regs+25);
3091da177e4SLinus Torvalds 	err |= __put_user(regs->r26, sc->sc_regs+26);
3101da177e4SLinus Torvalds 	err |= __put_user(regs->r27, sc->sc_regs+27);
3111da177e4SLinus Torvalds 	err |= __put_user(regs->r28, sc->sc_regs+28);
3121da177e4SLinus Torvalds 	err |= __put_user(regs->gp , sc->sc_regs+29);
3131da177e4SLinus Torvalds 	err |= __put_user(sp, sc->sc_regs+30);
3141da177e4SLinus Torvalds 	err |= __put_user(0, sc->sc_regs+31);
3151da177e4SLinus Torvalds 
316*05096666SAl Viro 	err |= __copy_to_user(sc->sc_fpregs,
317*05096666SAl Viro 			      current_thread_info()->fp, 31 * 8);
3181da177e4SLinus Torvalds 	err |= __put_user(0, sc->sc_fpregs+31);
319*05096666SAl Viro 	err |= __put_user(current_thread_info()->fp[31], &sc->sc_fpcr);
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0);
3221da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1);
3231da177e4SLinus Torvalds 	err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2);
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	return err;
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds 
328b927b3e2SRichard Henderson static int
setup_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)329cfd60c07SAl Viro setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
3301da177e4SLinus Torvalds {
3311da177e4SLinus Torvalds 	unsigned long oldsp, r26, err = 0;
3321da177e4SLinus Torvalds 	struct sigframe __user *frame;
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	oldsp = rdusp();
335cfd60c07SAl Viro 	frame = get_sigframe(ksig, oldsp, sizeof(*frame));
33696d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
337cbdfb9ffSAl Viro 		return -EFAULT;
3381da177e4SLinus Torvalds 
339d9d0738aSAl Viro 	err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp);
3401da177e4SLinus Torvalds 	if (err)
341cbdfb9ffSAl Viro 		return -EFAULT;
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub
3441da177e4SLinus Torvalds 	   already in userspace.  */
345cfd60c07SAl Viro 	r26 = (unsigned long) ksig->ka.ka_restorer;
346cfd60c07SAl Viro 	if (!r26) {
3471da177e4SLinus Torvalds 		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
3481da177e4SLinus Torvalds 		err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
3491da177e4SLinus Torvalds 		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
3501da177e4SLinus Torvalds 		imb();
3511da177e4SLinus Torvalds 		r26 = (unsigned long) frame->retcode;
3521da177e4SLinus Torvalds 	}
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	/* Check that everything was written properly.  */
3551da177e4SLinus Torvalds 	if (err)
356cbdfb9ffSAl Viro 		return err;
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	/* "Return" to the handler */
3591da177e4SLinus Torvalds 	regs->r26 = r26;
360cfd60c07SAl Viro 	regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
361cfd60c07SAl Viro 	regs->r16 = ksig->sig;			/* a0: signal number */
3621da177e4SLinus Torvalds 	regs->r17 = 0;				/* a1: exception code */
3631da177e4SLinus Torvalds 	regs->r18 = (unsigned long) &frame->sc;	/* a2: sigcontext pointer */
3641da177e4SLinus Torvalds 	wrusp((unsigned long) frame);
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds #if DEBUG_SIG
3671da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
3681da177e4SLinus Torvalds 		current->comm, current->pid, frame, regs->pc, regs->r26);
3691da177e4SLinus Torvalds #endif
370b927b3e2SRichard Henderson 	return 0;
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds 
373b927b3e2SRichard Henderson static int
setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)374cfd60c07SAl Viro setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
3751da177e4SLinus Torvalds {
3761da177e4SLinus Torvalds 	unsigned long oldsp, r26, err = 0;
3771da177e4SLinus Torvalds 	struct rt_sigframe __user *frame;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	oldsp = rdusp();
380cfd60c07SAl Viro 	frame = get_sigframe(ksig, oldsp, sizeof(*frame));
38196d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
382cbdfb9ffSAl Viro 		return -EFAULT;
3831da177e4SLinus Torvalds 
384cfd60c07SAl Viro 	err |= copy_siginfo_to_user(&frame->info, &ksig->info);
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	/* Create the ucontext.  */
3871da177e4SLinus Torvalds 	err |= __put_user(0, &frame->uc.uc_flags);
3881da177e4SLinus Torvalds 	err |= __put_user(0, &frame->uc.uc_link);
3891da177e4SLinus Torvalds 	err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
39050ececcfSAl Viro 	err |= __save_altstack(&frame->uc.uc_stack, oldsp);
391d9d0738aSAl Viro 	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs,
3921da177e4SLinus Torvalds 				set->sig[0], oldsp);
3931da177e4SLinus Torvalds 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
3941da177e4SLinus Torvalds 	if (err)
395cbdfb9ffSAl Viro 		return -EFAULT;
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub
3981da177e4SLinus Torvalds 	   already in userspace.  */
399cfd60c07SAl Viro 	r26 = (unsigned long) ksig->ka.ka_restorer;
400cfd60c07SAl Viro 	if (!r26) {
4011da177e4SLinus Torvalds 		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
4021da177e4SLinus Torvalds 		err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
4031da177e4SLinus Torvalds 				  frame->retcode+1);
4041da177e4SLinus Torvalds 		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
4051da177e4SLinus Torvalds 		imb();
4061da177e4SLinus Torvalds 		r26 = (unsigned long) frame->retcode;
4071da177e4SLinus Torvalds 	}
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 	if (err)
410cbdfb9ffSAl Viro 		return -EFAULT;
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 	/* "Return" to the handler */
4131da177e4SLinus Torvalds 	regs->r26 = r26;
414cfd60c07SAl Viro 	regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
415cfd60c07SAl Viro 	regs->r16 = ksig->sig;			  /* a0: signal number */
4161da177e4SLinus Torvalds 	regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
4171da177e4SLinus Torvalds 	regs->r18 = (unsigned long) &frame->uc;	  /* a2: ucontext pointer */
4181da177e4SLinus Torvalds 	wrusp((unsigned long) frame);
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds #if DEBUG_SIG
4211da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
4221da177e4SLinus Torvalds 		current->comm, current->pid, frame, regs->pc, regs->r26);
4231da177e4SLinus Torvalds #endif
4241da177e4SLinus Torvalds 
425b927b3e2SRichard Henderson 	return 0;
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds /*
4301da177e4SLinus Torvalds  * OK, we're invoking a handler.
4311da177e4SLinus Torvalds  */
432cbdfb9ffSAl Viro static inline void
handle_signal(struct ksignal * ksig,struct pt_regs * regs)433cfd60c07SAl Viro handle_signal(struct ksignal *ksig, struct pt_regs *regs)
4341da177e4SLinus Torvalds {
435b7f9a11aSAl Viro 	sigset_t *oldset = sigmask_to_save();
436b927b3e2SRichard Henderson 	int ret;
437b927b3e2SRichard Henderson 
438cfd60c07SAl Viro 	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
439cfd60c07SAl Viro 		ret = setup_rt_frame(ksig, oldset, regs);
4401da177e4SLinus Torvalds 	else
441cfd60c07SAl Viro 		ret = setup_frame(ksig, oldset, regs);
4421da177e4SLinus Torvalds 
443cfd60c07SAl Viro 	signal_setup_done(ret, ksig, 0);
444b927b3e2SRichard Henderson }
445b927b3e2SRichard Henderson 
4461da177e4SLinus Torvalds static inline void
syscall_restart(unsigned long r0,unsigned long r19,struct pt_regs * regs,struct k_sigaction * ka)4471da177e4SLinus Torvalds syscall_restart(unsigned long r0, unsigned long r19,
4481da177e4SLinus Torvalds 		struct pt_regs *regs, struct k_sigaction *ka)
4491da177e4SLinus Torvalds {
4501da177e4SLinus Torvalds 	switch (regs->r0) {
4511da177e4SLinus Torvalds 	case ERESTARTSYS:
4521da177e4SLinus Torvalds 		if (!(ka->sa.sa_flags & SA_RESTART)) {
4531da177e4SLinus Torvalds 		case ERESTARTNOHAND:
4541da177e4SLinus Torvalds 			regs->r0 = EINTR;
4551da177e4SLinus Torvalds 			break;
4561da177e4SLinus Torvalds 		}
457df561f66SGustavo A. R. Silva 		fallthrough;
4581da177e4SLinus Torvalds 	case ERESTARTNOINTR:
4591da177e4SLinus Torvalds 		regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
4601da177e4SLinus Torvalds 		regs->r19 = r19;
4611da177e4SLinus Torvalds 		regs->pc -= 4;
4621da177e4SLinus Torvalds 		break;
4631da177e4SLinus Torvalds 	case ERESTART_RESTARTBLOCK:
4641da177e4SLinus Torvalds 		regs->r0 = EINTR;
4651da177e4SLinus Torvalds 		break;
4661da177e4SLinus Torvalds 	}
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds /*
4711da177e4SLinus Torvalds  * Note that 'init' is a special process: it doesn't get signals it doesn't
4721da177e4SLinus Torvalds  * want to handle. Thus you cannot kill init even with a SIGKILL even by
4731da177e4SLinus Torvalds  * mistake.
4741da177e4SLinus Torvalds  *
4751da177e4SLinus Torvalds  * Note that we go through the signals twice: once to check the signals that
4761da177e4SLinus Torvalds  * the kernel can handle, and then we build all the user-level signal handling
4771da177e4SLinus Torvalds  * stack-frames in one go after that.
4781da177e4SLinus Torvalds  *
4791da177e4SLinus Torvalds  * "r0" and "r19" are the registers we need to restore for system call
4801da177e4SLinus Torvalds  * restart. "r0" is also used as an indicator whether we can restart at
4811da177e4SLinus Torvalds  * all (if we get here from anything but a syscall return, it will be 0)
4821da177e4SLinus Torvalds  */
483b927b3e2SRichard Henderson static void
do_signal(struct pt_regs * regs,unsigned long r0,unsigned long r19)484d9d0738aSAl Viro do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
4851da177e4SLinus Torvalds {
4861da177e4SLinus Torvalds 	unsigned long single_stepping = ptrace_cancel_bpt(current);
487cfd60c07SAl Viro 	struct ksignal ksig;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	/* This lets the debugger run, ... */
490cfd60c07SAl Viro 	if (get_signal(&ksig)) {
4911da177e4SLinus Torvalds 		/* ... so re-check the single stepping. */
4921da177e4SLinus Torvalds 		single_stepping |= ptrace_cancel_bpt(current);
4931da177e4SLinus Torvalds 		/* Whee!  Actually deliver the signal.  */
494b927b3e2SRichard Henderson 		if (r0)
495cfd60c07SAl Viro 			syscall_restart(r0, r19, regs, &ksig.ka);
496cfd60c07SAl Viro 		handle_signal(&ksig, regs);
497cfd60c07SAl Viro 	} else {
498cfd60c07SAl Viro 		single_stepping |= ptrace_cancel_bpt(current);
4991da177e4SLinus Torvalds 		if (r0) {
5001da177e4SLinus Torvalds 			switch (regs->r0) {
5011da177e4SLinus Torvalds 			case ERESTARTNOHAND:
5021da177e4SLinus Torvalds 			case ERESTARTSYS:
5031da177e4SLinus Torvalds 			case ERESTARTNOINTR:
5041da177e4SLinus Torvalds 				/* Reset v0 and a3 and replay syscall.  */
5051da177e4SLinus Torvalds 				regs->r0 = r0;
5061da177e4SLinus Torvalds 				regs->r19 = r19;
5071da177e4SLinus Torvalds 				regs->pc -= 4;
5081da177e4SLinus Torvalds 				break;
5091da177e4SLinus Torvalds 			case ERESTART_RESTARTBLOCK:
510cfd60c07SAl Viro 				/* Set v0 to the restart_syscall and replay */
5111da177e4SLinus Torvalds 				regs->r0 = __NR_restart_syscall;
5121da177e4SLinus Torvalds 				regs->pc -= 4;
5131da177e4SLinus Torvalds 				break;
5141da177e4SLinus Torvalds 			}
5151da177e4SLinus Torvalds 		}
51651a7b448SAl Viro 		restore_saved_sigmask();
517cfd60c07SAl Viro 	}
5181da177e4SLinus Torvalds 	if (single_stepping)
5191da177e4SLinus Torvalds 		ptrace_set_bpt(current);	/* re-set breakpoint */
5201da177e4SLinus Torvalds }
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds void
do_work_pending(struct pt_regs * regs,unsigned long thread_flags,unsigned long r0,unsigned long r19)523cb450766SAl Viro do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
524b927b3e2SRichard Henderson 		 unsigned long r0, unsigned long r19)
5251da177e4SLinus Torvalds {
5266972d6f2SAl Viro 	do {
5276972d6f2SAl Viro 		if (thread_flags & _TIF_NEED_RESCHED) {
5286972d6f2SAl Viro 			schedule();
5296972d6f2SAl Viro 		} else {
5306972d6f2SAl Viro 			local_irq_enable();
5315a9a8897SJens Axboe 			if (thread_flags & (_TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL)) {
532*05096666SAl Viro 				preempt_disable();
533*05096666SAl Viro 				save_fpu();
534*05096666SAl Viro 				preempt_enable();
535d9d0738aSAl Viro 				do_signal(regs, r0, r19);
5366972d6f2SAl Viro 				r0 = 0;
5376972d6f2SAl Viro 			} else {
53803248addSEric W. Biederman 				resume_user_mode_work(regs);
539d0420c83SDavid Howells 			}
5401da177e4SLinus Torvalds 		}
5416972d6f2SAl Viro 		local_irq_disable();
5427fb2b24bSMark Rutland 		thread_flags = read_thread_flags();
5436972d6f2SAl Viro 	} while (thread_flags & _TIF_WORK_MASK);
5446972d6f2SAl Viro }
545