xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision 5050e91fa650ecd6260ef62bbed9dfc5b4d05dfa)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds  * for more details.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 1991, 1992  Linus Torvalds
7dda73d0bSMartin Michlmayr  * Copyright (C) 1994 - 2000, 2006  Ralf Baechle
81da177e4SLinus Torvalds  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
91da177e4SLinus Torvalds  */
1002416dcfSRalf Baechle #include <linux/cache.h>
11431dc804SRalf Baechle #include <linux/compat.h>
121da177e4SLinus Torvalds #include <linux/sched.h>
131da177e4SLinus Torvalds #include <linux/mm.h>
141da177e4SLinus Torvalds #include <linux/smp.h>
151da177e4SLinus Torvalds #include <linux/kernel.h>
161da177e4SLinus Torvalds #include <linux/signal.h>
171da177e4SLinus Torvalds #include <linux/syscalls.h>
181da177e4SLinus Torvalds #include <linux/errno.h>
191da177e4SLinus Torvalds #include <linux/wait.h>
201da177e4SLinus Torvalds #include <linux/ptrace.h>
211da177e4SLinus Torvalds #include <linux/suspend.h>
221da177e4SLinus Torvalds #include <linux/compiler.h>
23faea6234SAtsushi Nemoto #include <linux/uaccess.h>
241da177e4SLinus Torvalds 
25e50c0a8fSRalf Baechle #include <asm/abi.h>
261da177e4SLinus Torvalds #include <asm/asm.h>
27431dc804SRalf Baechle #include <asm/compat-signal.h>
281da177e4SLinus Torvalds #include <linux/bitops.h>
291da177e4SLinus Torvalds #include <asm/cacheflush.h>
301da177e4SLinus Torvalds #include <asm/sim.h>
311da177e4SLinus Torvalds #include <asm/ucontext.h>
321da177e4SLinus Torvalds #include <asm/fpu.h>
3302416dcfSRalf Baechle #include <asm/war.h>
34b81947c6SDavid Howells #include <asm/dsp.h>
351da177e4SLinus Torvalds 
3636a1f2c2SFranck Bui-Huu #include "signal-common.h"
3736a1f2c2SFranck Bui-Huu 
381da177e4SLinus Torvalds /*
391da177e4SLinus Torvalds  * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
401da177e4SLinus Torvalds  */
411da177e4SLinus Torvalds #define __NR_O32_restart_syscall	4253
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds /* 32-bit compatibility types */
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds typedef unsigned int __sighandler32_t;
461da177e4SLinus Torvalds typedef void (*vfptr_t)(void);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds struct ucontext32 {
491da177e4SLinus Torvalds 	u32		    uc_flags;
501da177e4SLinus Torvalds 	s32		    uc_link;
51ea536ad4SAl Viro 	compat_stack_t      uc_stack;
521da177e4SLinus Torvalds 	struct sigcontext32 uc_mcontext;
5301ee6037SRalf Baechle 	compat_sigset_t	    uc_sigmask;	  /* mask last for extensibility */
541da177e4SLinus Torvalds };
551da177e4SLinus Torvalds 
56dd02f06aSRalf Baechle struct sigframe32 {
57dd02f06aSRalf Baechle 	u32 sf_ass[4];		/* argument save space for o32 */
58d814c28cSDavid Daney 	u32 sf_pad[2];		/* Was: signal trampoline */
59dd02f06aSRalf Baechle 	struct sigcontext32 sf_sc;
60755f21bbSAtsushi Nemoto 	compat_sigset_t sf_mask;
61dd02f06aSRalf Baechle };
62dd02f06aSRalf Baechle 
63c0b9bae9SFranck Bui-Huu struct rt_sigframe32 {
64c0b9bae9SFranck Bui-Huu 	u32 rs_ass[4];			/* argument save space for o32 */
65d814c28cSDavid Daney 	u32 rs_pad[2];			/* Was: signal trampoline */
66c0b9bae9SFranck Bui-Huu 	compat_siginfo_t rs_info;
67c0b9bae9SFranck Bui-Huu 	struct ucontext32 rs_uc;
68c0b9bae9SFranck Bui-Huu };
69c0b9bae9SFranck Bui-Huu 
709432a9baSFranck Bui-Huu static int setup_sigcontext32(struct pt_regs *regs,
719432a9baSFranck Bui-Huu 			      struct sigcontext32 __user *sc)
729432a9baSFranck Bui-Huu {
739432a9baSFranck Bui-Huu 	int err = 0;
749432a9baSFranck Bui-Huu 	int i;
759432a9baSFranck Bui-Huu 
769432a9baSFranck Bui-Huu 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
779432a9baSFranck Bui-Huu 
789432a9baSFranck Bui-Huu 	err |= __put_user(0, &sc->sc_regs[0]);
799432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
809432a9baSFranck Bui-Huu 		err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
819432a9baSFranck Bui-Huu 
829432a9baSFranck Bui-Huu 	err |= __put_user(regs->hi, &sc->sc_mdhi);
839432a9baSFranck Bui-Huu 	err |= __put_user(regs->lo, &sc->sc_mdlo);
849432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
859432a9baSFranck Bui-Huu 		err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
869432a9baSFranck Bui-Huu 		err |= __put_user(mfhi1(), &sc->sc_hi1);
879432a9baSFranck Bui-Huu 		err |= __put_user(mflo1(), &sc->sc_lo1);
889432a9baSFranck Bui-Huu 		err |= __put_user(mfhi2(), &sc->sc_hi2);
899432a9baSFranck Bui-Huu 		err |= __put_user(mflo2(), &sc->sc_lo2);
909432a9baSFranck Bui-Huu 		err |= __put_user(mfhi3(), &sc->sc_hi3);
919432a9baSFranck Bui-Huu 		err |= __put_user(mflo3(), &sc->sc_lo3);
929432a9baSFranck Bui-Huu 	}
939432a9baSFranck Bui-Huu 
949432a9baSFranck Bui-Huu 	/*
959432a9baSFranck Bui-Huu 	 * Save FPU state to signal context.  Signal handler
969432a9baSFranck Bui-Huu 	 * will "inherit" current FPU state.
979432a9baSFranck Bui-Huu 	 */
98d02a40afSPaul Burton 	err |= protected_save_fp_context(sc);
99d02a40afSPaul Burton 
1009432a9baSFranck Bui-Huu 	return err;
1019432a9baSFranck Bui-Huu }
1029432a9baSFranck Bui-Huu 
1039432a9baSFranck Bui-Huu static int restore_sigcontext32(struct pt_regs *regs,
1049432a9baSFranck Bui-Huu 				struct sigcontext32 __user *sc)
1059432a9baSFranck Bui-Huu {
1069432a9baSFranck Bui-Huu 	int err = 0;
1079432a9baSFranck Bui-Huu 	s32 treg;
1089432a9baSFranck Bui-Huu 	int i;
1099432a9baSFranck Bui-Huu 
1109432a9baSFranck Bui-Huu 	/* Always make any pending restarted system calls return -EINTR */
111f56141e3SAndy Lutomirski 	current->restart_block.fn = do_no_restart_syscall;
1129432a9baSFranck Bui-Huu 
1139432a9baSFranck Bui-Huu 	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
1149432a9baSFranck Bui-Huu 	err |= __get_user(regs->hi, &sc->sc_mdhi);
1159432a9baSFranck Bui-Huu 	err |= __get_user(regs->lo, &sc->sc_mdlo);
1169432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
1179432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
1189432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
1199432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
1209432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
1219432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
1229432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
1239432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
1249432a9baSFranck Bui-Huu 	}
1259432a9baSFranck Bui-Huu 
1269432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
1279432a9baSFranck Bui-Huu 		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
1289432a9baSFranck Bui-Huu 
129d02a40afSPaul Burton 	return err ?: protected_restore_fp_context(sc);
1309432a9baSFranck Bui-Huu }
1319432a9baSFranck Bui-Huu 
1329432a9baSFranck Bui-Huu /*
1331da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
1341da177e4SLinus Torvalds  */
1351da177e4SLinus Torvalds 
1361910f4abSAl Viro asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
1371da177e4SLinus Torvalds {
1381910f4abSAl Viro 	return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds 
141aa584802SAl Viro SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
142aa584802SAl Viro 	struct compat_sigaction __user *, oact)
1431da177e4SLinus Torvalds {
1441da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
1451da177e4SLinus Torvalds 	int ret;
1461da177e4SLinus Torvalds 	int err = 0;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	if (act) {
1491da177e4SLinus Torvalds 		old_sigset_t mask;
15077c728c2SRalf Baechle 		s32 handler;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
1531da177e4SLinus Torvalds 			return -EFAULT;
15477c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
1559bbf28a3SAtsushi Nemoto 		new_ka.sa.sa_handler = (void __user *)(s64)handler;
1561da177e4SLinus Torvalds 		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
1571da177e4SLinus Torvalds 		err |= __get_user(mask, &act->sa_mask.sig[0]);
1581da177e4SLinus Torvalds 		if (err)
1591da177e4SLinus Torvalds 			return -EFAULT;
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
1621da177e4SLinus Torvalds 	}
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	if (!ret && oact) {
1671da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
1681da177e4SLinus Torvalds 			return -EFAULT;
1691da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
1701da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
1711da177e4SLinus Torvalds 				  &oact->sa_handler);
1721da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
1731da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[1]);
1741da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[2]);
1751da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[3]);
1761da177e4SLinus Torvalds 		if (err)
1771da177e4SLinus Torvalds 			return -EFAULT;
1781da177e4SLinus Torvalds 	}
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	return ret;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
183ce395960SAl Viro int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
1841da177e4SLinus Torvalds {
1851da177e4SLinus Torvalds 	int err;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
1881da177e4SLinus Torvalds 		return -EFAULT;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	/* If you change siginfo_t structure, please be sure
1911da177e4SLinus Torvalds 	   this code is fixed accordingly.
1921da177e4SLinus Torvalds 	   It should never copy any pad contained in the structure
1931da177e4SLinus Torvalds 	   to avoid security leaks, but must copy the generic
1941da177e4SLinus Torvalds 	   3 ints plus the relevant union member.
1951da177e4SLinus Torvalds 	   This routine must convert siginfo from 64bit to 32bit as well
1961da177e4SLinus Torvalds 	   at the same time.  */
1971da177e4SLinus Torvalds 	err = __put_user(from->si_signo, &to->si_signo);
1981da177e4SLinus Torvalds 	err |= __put_user(from->si_errno, &to->si_errno);
1991da177e4SLinus Torvalds 	err |= __put_user((short)from->si_code, &to->si_code);
2001da177e4SLinus Torvalds 	if (from->si_code < 0)
2011da177e4SLinus Torvalds 		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
2021da177e4SLinus Torvalds 	else {
2031da177e4SLinus Torvalds 		switch (from->si_code >> 16) {
204a982099cSRalf Baechle 		case __SI_TIMER >> 16:
205a982099cSRalf Baechle 			err |= __put_user(from->si_tid, &to->si_tid);
206a982099cSRalf Baechle 			err |= __put_user(from->si_overrun, &to->si_overrun);
207a982099cSRalf Baechle 			err |= __put_user(from->si_int, &to->si_int);
208a982099cSRalf Baechle 			break;
2091da177e4SLinus Torvalds 		case __SI_CHLD >> 16:
2101da177e4SLinus Torvalds 			err |= __put_user(from->si_utime, &to->si_utime);
2111da177e4SLinus Torvalds 			err |= __put_user(from->si_stime, &to->si_stime);
2121da177e4SLinus Torvalds 			err |= __put_user(from->si_status, &to->si_status);
2131da177e4SLinus Torvalds 		default:
2141da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
2151da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
2161da177e4SLinus Torvalds 			break;
2171da177e4SLinus Torvalds 		case __SI_FAULT >> 16:
2185665a0acSAtsushi Nemoto 			err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
2191da177e4SLinus Torvalds 			break;
2201da177e4SLinus Torvalds 		case __SI_POLL >> 16:
2211da177e4SLinus Torvalds 			err |= __put_user(from->si_band, &to->si_band);
2221da177e4SLinus Torvalds 			err |= __put_user(from->si_fd, &to->si_fd);
2231da177e4SLinus Torvalds 			break;
2241da177e4SLinus Torvalds 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
2251da177e4SLinus Torvalds 		case __SI_MESGQ >> 16:
2261da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
2271da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
2281da177e4SLinus Torvalds 			err |= __put_user(from->si_int, &to->si_int);
2291da177e4SLinus Torvalds 			break;
230*5050e91fSMatt Redfearn 		case __SI_SYS >> 16:
231*5050e91fSMatt Redfearn 			err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
232*5050e91fSMatt Redfearn 					      sizeof(compat_uptr_t));
233*5050e91fSMatt Redfearn 			err |= __put_user(from->si_syscall, &to->si_syscall);
234*5050e91fSMatt Redfearn 			err |= __put_user(from->si_arch, &to->si_arch);
235*5050e91fSMatt Redfearn 			break;
2361da177e4SLinus Torvalds 		}
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 	return err;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
2415d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
2425d9a76cdSThomas Bogendoerfer {
2435d9a76cdSThomas Bogendoerfer 	if (copy_from_user(to, from, 3*sizeof(int)) ||
2445d9a76cdSThomas Bogendoerfer 	    copy_from_user(to->_sifields._pad,
2455d9a76cdSThomas Bogendoerfer 			   from->_sifields._pad, SI_PAD_SIZE32))
2465d9a76cdSThomas Bogendoerfer 		return -EFAULT;
2475d9a76cdSThomas Bogendoerfer 
2485d9a76cdSThomas Bogendoerfer 	return 0;
2495d9a76cdSThomas Bogendoerfer }
2505d9a76cdSThomas Bogendoerfer 
251f90080a0SFranck Bui-Huu asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
2521da177e4SLinus Torvalds {
253dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
2541da177e4SLinus Torvalds 	sigset_t blocked;
255c6a2f467SAtsushi Nemoto 	int sig;
2561da177e4SLinus Torvalds 
257dd02f06aSRalf Baechle 	frame = (struct sigframe32 __user *) regs.regs[29];
2581da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
2591da177e4SLinus Torvalds 		goto badframe;
260431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
2611da177e4SLinus Torvalds 		goto badframe;
2621da177e4SLinus Torvalds 
2638598f3cdSMatt Fleming 	set_current_blocked(&blocked);
2641da177e4SLinus Torvalds 
265c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->sf_sc);
266c6a2f467SAtsushi Nemoto 	if (sig < 0)
2671da177e4SLinus Torvalds 		goto badframe;
268c6a2f467SAtsushi Nemoto 	else if (sig)
269c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	/*
2721da177e4SLinus Torvalds 	 * Don't let your children do this ...
2731da177e4SLinus Torvalds 	 */
2741da177e4SLinus Torvalds 	__asm__ __volatile__(
2751da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
2761da177e4SLinus Torvalds 		"j\tsyscall_exit"
2771da177e4SLinus Torvalds 		:/* no outputs */
2781da177e4SLinus Torvalds 		:"r" (&regs));
2791da177e4SLinus Torvalds 	/* Unreached */
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds badframe:
2821da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds 
285f90080a0SFranck Bui-Huu asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
2861da177e4SLinus Torvalds {
2879bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
2881da177e4SLinus Torvalds 	sigset_t set;
289c6a2f467SAtsushi Nemoto 	int sig;
2901da177e4SLinus Torvalds 
2919bbf28a3SAtsushi Nemoto 	frame = (struct rt_sigframe32 __user *) regs.regs[29];
2921da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
2931da177e4SLinus Torvalds 		goto badframe;
294431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
2951da177e4SLinus Torvalds 		goto badframe;
2961da177e4SLinus Torvalds 
2978598f3cdSMatt Fleming 	set_current_blocked(&set);
2981da177e4SLinus Torvalds 
299c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
300c6a2f467SAtsushi Nemoto 	if (sig < 0)
3011da177e4SLinus Torvalds 		goto badframe;
302c6a2f467SAtsushi Nemoto 	else if (sig)
303c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
3041da177e4SLinus Torvalds 
305ea536ad4SAl Viro 	if (compat_restore_altstack(&frame->rs_uc.uc_stack))
3061da177e4SLinus Torvalds 		goto badframe;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	/*
3091da177e4SLinus Torvalds 	 * Don't let your children do this ...
3101da177e4SLinus Torvalds 	 */
3111da177e4SLinus Torvalds 	__asm__ __volatile__(
3121da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
3131da177e4SLinus Torvalds 		"j\tsyscall_exit"
3141da177e4SLinus Torvalds 		:/* no outputs */
3151da177e4SLinus Torvalds 		:"r" (&regs));
3161da177e4SLinus Torvalds 	/* Unreached */
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds badframe:
3191da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds 
32281d103bfSRichard Weinberger static int setup_frame_32(void *sig_return, struct ksignal *ksig,
32381d103bfSRichard Weinberger 			  struct pt_regs *regs, sigset_t *set)
3241da177e4SLinus Torvalds {
325dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
3261da177e4SLinus Torvalds 	int err = 0;
3271da177e4SLinus Torvalds 
3287c4f5635SRichard Weinberger 	frame = get_sigframe(ksig, regs, sizeof(*frame));
3291da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
33081d103bfSRichard Weinberger 		return -EFAULT;
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->sf_sc);
333431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
334431dc804SRalf Baechle 
3351da177e4SLinus Torvalds 	if (err)
33681d103bfSRichard Weinberger 		return -EFAULT;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	/*
3391da177e4SLinus Torvalds 	 * Arguments to signal handler:
3401da177e4SLinus Torvalds 	 *
3411da177e4SLinus Torvalds 	 *   a0 = signal number
3421da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
3431da177e4SLinus Torvalds 	 *   a2 = pointer to struct sigcontext
3441da177e4SLinus Torvalds 	 *
3451da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to the
3461da177e4SLinus Torvalds 	 * struct sigframe.
3471da177e4SLinus Torvalds 	 */
34881d103bfSRichard Weinberger 	regs->regs[ 4] = ksig->sig;
3491da177e4SLinus Torvalds 	regs->regs[ 5] = 0;
3501da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
3511da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
352d814c28cSDavid Daney 	regs->regs[31] = (unsigned long) sig_return;
35381d103bfSRichard Weinberger 	regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
3541da177e4SLinus Torvalds 
355722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
3561da177e4SLinus Torvalds 	       current->comm, current->pid,
357722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
358722bb63dSFranck Bui-Huu 
3597b3e2fc8SRalf Baechle 	return 0;
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds 
36281d103bfSRichard Weinberger static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
36381d103bfSRichard Weinberger 			     struct pt_regs *regs, sigset_t *set)
3641da177e4SLinus Torvalds {
3659bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
3661da177e4SLinus Torvalds 	int err = 0;
3671da177e4SLinus Torvalds 
3687c4f5635SRichard Weinberger 	frame = get_sigframe(ksig, regs, sizeof(*frame));
3691da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
37081d103bfSRichard Weinberger 		return -EFAULT;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
37381d103bfSRichard Weinberger 	err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info);
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	/* Create the ucontext.	 */
3761da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_flags);
3771da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_link);
378ea536ad4SAl Viro 	err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
3791da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
380431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	if (err)
38381d103bfSRichard Weinberger 		return -EFAULT;
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	/*
3861da177e4SLinus Torvalds 	 * Arguments to signal handler:
3871da177e4SLinus Torvalds 	 *
3881da177e4SLinus Torvalds 	 *   a0 = signal number
3891da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
3901da177e4SLinus Torvalds 	 *   a2 = pointer to ucontext
3911da177e4SLinus Torvalds 	 *
3921da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to
3931da177e4SLinus Torvalds 	 * the struct rt_sigframe32.
3941da177e4SLinus Torvalds 	 */
39581d103bfSRichard Weinberger 	regs->regs[ 4] = ksig->sig;
3961da177e4SLinus Torvalds 	regs->regs[ 5] = (unsigned long) &frame->rs_info;
3971da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
3981da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
399d814c28cSDavid Daney 	regs->regs[31] = (unsigned long) sig_return;
40081d103bfSRichard Weinberger 	regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
4011da177e4SLinus Torvalds 
402722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
4031da177e4SLinus Torvalds 	       current->comm, current->pid,
404722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
405722bb63dSFranck Bui-Huu 
4067b3e2fc8SRalf Baechle 	return 0;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds /*
410151fd6acSRalf Baechle  * o32 compatibility on 64-bit kernels, without DSP ASE
4111da177e4SLinus Torvalds  */
412151fd6acSRalf Baechle struct mips_abi mips_abi_32 = {
413151fd6acSRalf Baechle 	.setup_frame	= setup_frame_32,
414151fd6acSRalf Baechle 	.setup_rt_frame = setup_rt_frame_32,
41577856100SPaul Burton 	.restart	= __NR_O32_restart_syscall,
41677856100SPaul Burton 
41777856100SPaul Burton 	.off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
41877856100SPaul Burton 	.off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
41977856100SPaul Burton 	.off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
420ebb5e78cSAlex Smith 
421ebb5e78cSAlex Smith 	.vdso		= &vdso_image_o32,
422151fd6acSRalf Baechle };
423