xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision 1910f4ab777f17744aec3b39fa15d3d4340df6d4)
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>
34d814c28cSDavid Daney #include <asm/vdso.h>
35b81947c6SDavid Howells #include <asm/dsp.h>
361da177e4SLinus Torvalds 
3736a1f2c2SFranck Bui-Huu #include "signal-common.h"
3836a1f2c2SFranck Bui-Huu 
39137f6f3eSRalf Baechle static int (*save_fp_context32)(struct sigcontext32 __user *sc);
40137f6f3eSRalf Baechle static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
41137f6f3eSRalf Baechle 
42137f6f3eSRalf Baechle extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
43137f6f3eSRalf Baechle extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
44137f6f3eSRalf Baechle 
45137f6f3eSRalf Baechle extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
46137f6f3eSRalf Baechle extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
47137f6f3eSRalf Baechle 
481da177e4SLinus Torvalds /*
491da177e4SLinus Torvalds  * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
501da177e4SLinus Torvalds  */
511da177e4SLinus Torvalds #define __NR_O32_restart_syscall        4253
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds /* 32-bit compatibility types */
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds typedef unsigned int __sighandler32_t;
561da177e4SLinus Torvalds typedef void (*vfptr_t)(void);
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds struct sigaction32 {
591da177e4SLinus Torvalds 	unsigned int		sa_flags;
601da177e4SLinus Torvalds 	__sighandler32_t	sa_handler;
611da177e4SLinus Torvalds 	compat_sigset_t		sa_mask;
621da177e4SLinus Torvalds };
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds struct ucontext32 {
651da177e4SLinus Torvalds 	u32                 uc_flags;
661da177e4SLinus Torvalds 	s32                 uc_link;
67ea536ad4SAl Viro 	compat_stack_t      uc_stack;
681da177e4SLinus Torvalds 	struct sigcontext32 uc_mcontext;
6901ee6037SRalf Baechle 	compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
701da177e4SLinus Torvalds };
711da177e4SLinus Torvalds 
72dd02f06aSRalf Baechle struct sigframe32 {
73dd02f06aSRalf Baechle 	u32 sf_ass[4];		/* argument save space for o32 */
74d814c28cSDavid Daney 	u32 sf_pad[2];		/* Was: signal trampoline */
75dd02f06aSRalf Baechle 	struct sigcontext32 sf_sc;
76755f21bbSAtsushi Nemoto 	compat_sigset_t sf_mask;
77dd02f06aSRalf Baechle };
78dd02f06aSRalf Baechle 
79c0b9bae9SFranck Bui-Huu struct rt_sigframe32 {
80c0b9bae9SFranck Bui-Huu 	u32 rs_ass[4];			/* argument save space for o32 */
81d814c28cSDavid Daney 	u32 rs_pad[2];			/* Was: signal trampoline */
82c0b9bae9SFranck Bui-Huu 	compat_siginfo_t rs_info;
83c0b9bae9SFranck Bui-Huu 	struct ucontext32 rs_uc;
84c0b9bae9SFranck Bui-Huu };
85c0b9bae9SFranck Bui-Huu 
869432a9baSFranck Bui-Huu /*
879432a9baSFranck Bui-Huu  * sigcontext handlers
889432a9baSFranck Bui-Huu  */
89faea6234SAtsushi Nemoto static int protected_save_fp_context32(struct sigcontext32 __user *sc)
90faea6234SAtsushi Nemoto {
91faea6234SAtsushi Nemoto 	int err;
92faea6234SAtsushi Nemoto 	while (1) {
93faea6234SAtsushi Nemoto 		lock_fpu_owner();
94faea6234SAtsushi Nemoto 		own_fpu_inatomic(1);
95faea6234SAtsushi Nemoto 		err = save_fp_context32(sc); /* this might fail */
96faea6234SAtsushi Nemoto 		unlock_fpu_owner();
97faea6234SAtsushi Nemoto 		if (likely(!err))
98faea6234SAtsushi Nemoto 			break;
99faea6234SAtsushi Nemoto 		/* touch the sigcontext and try again */
100faea6234SAtsushi Nemoto 		err = __put_user(0, &sc->sc_fpregs[0]) |
101faea6234SAtsushi Nemoto 			__put_user(0, &sc->sc_fpregs[31]) |
102faea6234SAtsushi Nemoto 			__put_user(0, &sc->sc_fpc_csr);
103faea6234SAtsushi Nemoto 		if (err)
104faea6234SAtsushi Nemoto 			break;	/* really bad sigcontext */
105faea6234SAtsushi Nemoto 	}
106faea6234SAtsushi Nemoto 	return err;
107faea6234SAtsushi Nemoto }
108faea6234SAtsushi Nemoto 
109faea6234SAtsushi Nemoto static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
110faea6234SAtsushi Nemoto {
111c726b822SDavid Daney 	int err, tmp __maybe_unused;
112faea6234SAtsushi Nemoto 	while (1) {
113faea6234SAtsushi Nemoto 		lock_fpu_owner();
114faea6234SAtsushi Nemoto 		own_fpu_inatomic(0);
115faea6234SAtsushi Nemoto 		err = restore_fp_context32(sc); /* this might fail */
116faea6234SAtsushi Nemoto 		unlock_fpu_owner();
117faea6234SAtsushi Nemoto 		if (likely(!err))
118faea6234SAtsushi Nemoto 			break;
119faea6234SAtsushi Nemoto 		/* touch the sigcontext and try again */
120faea6234SAtsushi Nemoto 		err = __get_user(tmp, &sc->sc_fpregs[0]) |
121faea6234SAtsushi Nemoto 			__get_user(tmp, &sc->sc_fpregs[31]) |
122faea6234SAtsushi Nemoto 			__get_user(tmp, &sc->sc_fpc_csr);
123faea6234SAtsushi Nemoto 		if (err)
124faea6234SAtsushi Nemoto 			break;	/* really bad sigcontext */
125faea6234SAtsushi Nemoto 	}
126faea6234SAtsushi Nemoto 	return err;
127faea6234SAtsushi Nemoto }
128faea6234SAtsushi Nemoto 
1299432a9baSFranck Bui-Huu static int setup_sigcontext32(struct pt_regs *regs,
1309432a9baSFranck Bui-Huu 			      struct sigcontext32 __user *sc)
1319432a9baSFranck Bui-Huu {
1329432a9baSFranck Bui-Huu 	int err = 0;
1339432a9baSFranck Bui-Huu 	int i;
13453dc8028SAtsushi Nemoto 	u32 used_math;
1359432a9baSFranck Bui-Huu 
1369432a9baSFranck Bui-Huu 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
1379432a9baSFranck Bui-Huu 
1389432a9baSFranck Bui-Huu 	err |= __put_user(0, &sc->sc_regs[0]);
1399432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
1409432a9baSFranck Bui-Huu 		err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
1419432a9baSFranck Bui-Huu 
1429432a9baSFranck Bui-Huu 	err |= __put_user(regs->hi, &sc->sc_mdhi);
1439432a9baSFranck Bui-Huu 	err |= __put_user(regs->lo, &sc->sc_mdlo);
1449432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
1459432a9baSFranck Bui-Huu 		err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
1469432a9baSFranck Bui-Huu 		err |= __put_user(mfhi1(), &sc->sc_hi1);
1479432a9baSFranck Bui-Huu 		err |= __put_user(mflo1(), &sc->sc_lo1);
1489432a9baSFranck Bui-Huu 		err |= __put_user(mfhi2(), &sc->sc_hi2);
1499432a9baSFranck Bui-Huu 		err |= __put_user(mflo2(), &sc->sc_lo2);
1509432a9baSFranck Bui-Huu 		err |= __put_user(mfhi3(), &sc->sc_hi3);
1519432a9baSFranck Bui-Huu 		err |= __put_user(mflo3(), &sc->sc_lo3);
1529432a9baSFranck Bui-Huu 	}
1539432a9baSFranck Bui-Huu 
15453dc8028SAtsushi Nemoto 	used_math = !!used_math();
15553dc8028SAtsushi Nemoto 	err |= __put_user(used_math, &sc->sc_used_math);
1569432a9baSFranck Bui-Huu 
15753dc8028SAtsushi Nemoto 	if (used_math) {
1589432a9baSFranck Bui-Huu 		/*
1599432a9baSFranck Bui-Huu 		 * Save FPU state to signal context.  Signal handler
1609432a9baSFranck Bui-Huu 		 * will "inherit" current FPU state.
1619432a9baSFranck Bui-Huu 		 */
162faea6234SAtsushi Nemoto 		err |= protected_save_fp_context32(sc);
1639432a9baSFranck Bui-Huu 	}
1649432a9baSFranck Bui-Huu 	return err;
1659432a9baSFranck Bui-Huu }
1669432a9baSFranck Bui-Huu 
167c6a2f467SAtsushi Nemoto static int
168c6a2f467SAtsushi Nemoto check_and_restore_fp_context32(struct sigcontext32 __user *sc)
169c6a2f467SAtsushi Nemoto {
170c6a2f467SAtsushi Nemoto 	int err, sig;
171c6a2f467SAtsushi Nemoto 
172c6a2f467SAtsushi Nemoto 	err = sig = fpcsr_pending(&sc->sc_fpc_csr);
173c6a2f467SAtsushi Nemoto 	if (err > 0)
174c6a2f467SAtsushi Nemoto 		err = 0;
175faea6234SAtsushi Nemoto 	err |= protected_restore_fp_context32(sc);
176c6a2f467SAtsushi Nemoto 	return err ?: sig;
177c6a2f467SAtsushi Nemoto }
178c6a2f467SAtsushi Nemoto 
1799432a9baSFranck Bui-Huu static int restore_sigcontext32(struct pt_regs *regs,
1809432a9baSFranck Bui-Huu 				struct sigcontext32 __user *sc)
1819432a9baSFranck Bui-Huu {
1829432a9baSFranck Bui-Huu 	u32 used_math;
1839432a9baSFranck Bui-Huu 	int err = 0;
1849432a9baSFranck Bui-Huu 	s32 treg;
1859432a9baSFranck Bui-Huu 	int i;
1869432a9baSFranck Bui-Huu 
1879432a9baSFranck Bui-Huu 	/* Always make any pending restarted system calls return -EINTR */
1889432a9baSFranck Bui-Huu 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
1899432a9baSFranck Bui-Huu 
1909432a9baSFranck Bui-Huu 	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
1919432a9baSFranck Bui-Huu 	err |= __get_user(regs->hi, &sc->sc_mdhi);
1929432a9baSFranck Bui-Huu 	err |= __get_user(regs->lo, &sc->sc_mdlo);
1939432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
1949432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
1959432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
1969432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
1979432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
1989432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
1999432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2009432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2019432a9baSFranck Bui-Huu 	}
2029432a9baSFranck Bui-Huu 
2039432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
2049432a9baSFranck Bui-Huu 		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
2059432a9baSFranck Bui-Huu 
2069432a9baSFranck Bui-Huu 	err |= __get_user(used_math, &sc->sc_used_math);
2079432a9baSFranck Bui-Huu 	conditional_used_math(used_math);
2089432a9baSFranck Bui-Huu 
20953dc8028SAtsushi Nemoto 	if (used_math) {
2109432a9baSFranck Bui-Huu 		/* restore fpu context if we have used it before */
211c6a2f467SAtsushi Nemoto 		if (!err)
212c6a2f467SAtsushi Nemoto 			err = check_and_restore_fp_context32(sc);
2139432a9baSFranck Bui-Huu 	} else {
2149432a9baSFranck Bui-Huu 		/* signal handler may have used FPU.  Give it up. */
21553dc8028SAtsushi Nemoto 		lose_fpu(0);
2169432a9baSFranck Bui-Huu 	}
2179432a9baSFranck Bui-Huu 
2189432a9baSFranck Bui-Huu 	return err;
2199432a9baSFranck Bui-Huu }
2209432a9baSFranck Bui-Huu 
2219432a9baSFranck Bui-Huu /*
2229432a9baSFranck Bui-Huu  *
2239432a9baSFranck Bui-Huu  */
2241da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void);
2251da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void);
2261da177e4SLinus Torvalds 
2279bbf28a3SAtsushi Nemoto static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	int err = 0;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
2321da177e4SLinus Torvalds 		return -EFAULT;
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
2351da177e4SLinus Torvalds 	default:
2361da177e4SLinus Torvalds 		__put_sigset_unknown_nsig();
2371da177e4SLinus Torvalds 	case 2:
2381da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
2391da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
2401da177e4SLinus Torvalds 	case 1:
2411da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
2421da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 	return err;
2461da177e4SLinus Torvalds }
2471da177e4SLinus Torvalds 
2489c6031ccSAtsushi Nemoto static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
2491da177e4SLinus Torvalds {
2501da177e4SLinus Torvalds 	int err = 0;
2511da177e4SLinus Torvalds 	unsigned long sig[4];
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
2541da177e4SLinus Torvalds 		return -EFAULT;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
2571da177e4SLinus Torvalds 	default:
2581da177e4SLinus Torvalds 		__get_sigset_unknown_nsig();
2591da177e4SLinus Torvalds 	case 2:
2601da177e4SLinus Torvalds 		err |= __get_user(sig[3], &ubuf->sig[3]);
2611da177e4SLinus Torvalds 		err |= __get_user(sig[2], &ubuf->sig[2]);
2621da177e4SLinus Torvalds 		kbuf->sig[1] = sig[2] | (sig[3] << 32);
2631da177e4SLinus Torvalds 	case 1:
2641da177e4SLinus Torvalds 		err |= __get_user(sig[1], &ubuf->sig[1]);
2651da177e4SLinus Torvalds 		err |= __get_user(sig[0], &ubuf->sig[0]);
2661da177e4SLinus Torvalds 		kbuf->sig[0] = sig[0] | (sig[1] << 32);
2671da177e4SLinus Torvalds 	}
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	return err;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds /*
2731da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
2741da177e4SLinus Torvalds  */
2751da177e4SLinus Torvalds 
276*1910f4abSAl Viro asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
2771da177e4SLinus Torvalds {
278*1910f4abSAl Viro 	return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
281dbda6ac0SRalf Baechle SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
282dbda6ac0SRalf Baechle 	struct sigaction32 __user *, oact)
2831da177e4SLinus Torvalds {
2841da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
2851da177e4SLinus Torvalds 	int ret;
2861da177e4SLinus Torvalds 	int err = 0;
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	if (act) {
2891da177e4SLinus Torvalds 		old_sigset_t mask;
29077c728c2SRalf Baechle 		s32 handler;
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
2931da177e4SLinus Torvalds 			return -EFAULT;
29477c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
2959bbf28a3SAtsushi Nemoto 		new_ka.sa.sa_handler = (void __user *)(s64)handler;
2961da177e4SLinus Torvalds 		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
2971da177e4SLinus Torvalds 		err |= __get_user(mask, &act->sa_mask.sig[0]);
2981da177e4SLinus Torvalds 		if (err)
2991da177e4SLinus Torvalds 			return -EFAULT;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
3021da177e4SLinus Torvalds 	}
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 	if (!ret && oact) {
3071da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
3081da177e4SLinus Torvalds 			return -EFAULT;
3091da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
3101da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
3111da177e4SLinus Torvalds 		                  &oact->sa_handler);
3121da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
3131da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[1]);
3141da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[2]);
3151da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[3]);
3161da177e4SLinus Torvalds 		if (err)
3171da177e4SLinus Torvalds 			return -EFAULT;
3181da177e4SLinus Torvalds 	}
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	return ret;
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds 
3239bbf28a3SAtsushi Nemoto int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
3241da177e4SLinus Torvalds {
3251da177e4SLinus Torvalds 	int err;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
3281da177e4SLinus Torvalds 		return -EFAULT;
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	/* If you change siginfo_t structure, please be sure
3311da177e4SLinus Torvalds 	   this code is fixed accordingly.
3321da177e4SLinus Torvalds 	   It should never copy any pad contained in the structure
3331da177e4SLinus Torvalds 	   to avoid security leaks, but must copy the generic
3341da177e4SLinus Torvalds 	   3 ints plus the relevant union member.
3351da177e4SLinus Torvalds 	   This routine must convert siginfo from 64bit to 32bit as well
3361da177e4SLinus Torvalds 	   at the same time.  */
3371da177e4SLinus Torvalds 	err = __put_user(from->si_signo, &to->si_signo);
3381da177e4SLinus Torvalds 	err |= __put_user(from->si_errno, &to->si_errno);
3391da177e4SLinus Torvalds 	err |= __put_user((short)from->si_code, &to->si_code);
3401da177e4SLinus Torvalds 	if (from->si_code < 0)
3411da177e4SLinus Torvalds 		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
3421da177e4SLinus Torvalds 	else {
3431da177e4SLinus Torvalds 		switch (from->si_code >> 16) {
344a982099cSRalf Baechle 		case __SI_TIMER >> 16:
345a982099cSRalf Baechle 			err |= __put_user(from->si_tid, &to->si_tid);
346a982099cSRalf Baechle 			err |= __put_user(from->si_overrun, &to->si_overrun);
347a982099cSRalf Baechle 			err |= __put_user(from->si_int, &to->si_int);
348a982099cSRalf Baechle 			break;
3491da177e4SLinus Torvalds 		case __SI_CHLD >> 16:
3501da177e4SLinus Torvalds 			err |= __put_user(from->si_utime, &to->si_utime);
3511da177e4SLinus Torvalds 			err |= __put_user(from->si_stime, &to->si_stime);
3521da177e4SLinus Torvalds 			err |= __put_user(from->si_status, &to->si_status);
3531da177e4SLinus Torvalds 		default:
3541da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
3551da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
3561da177e4SLinus Torvalds 			break;
3571da177e4SLinus Torvalds 		case __SI_FAULT >> 16:
3585665a0acSAtsushi Nemoto 			err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
3591da177e4SLinus Torvalds 			break;
3601da177e4SLinus Torvalds 		case __SI_POLL >> 16:
3611da177e4SLinus Torvalds 			err |= __put_user(from->si_band, &to->si_band);
3621da177e4SLinus Torvalds 			err |= __put_user(from->si_fd, &to->si_fd);
3631da177e4SLinus Torvalds 			break;
3641da177e4SLinus Torvalds 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
3651da177e4SLinus Torvalds 		case __SI_MESGQ >> 16:
3661da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
3671da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
3681da177e4SLinus Torvalds 			err |= __put_user(from->si_int, &to->si_int);
3691da177e4SLinus Torvalds 			break;
3701da177e4SLinus Torvalds 		}
3711da177e4SLinus Torvalds 	}
3721da177e4SLinus Torvalds 	return err;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds 
3755d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
3765d9a76cdSThomas Bogendoerfer {
3775d9a76cdSThomas Bogendoerfer 	memset(to, 0, sizeof *to);
3785d9a76cdSThomas Bogendoerfer 
3795d9a76cdSThomas Bogendoerfer 	if (copy_from_user(to, from, 3*sizeof(int)) ||
3805d9a76cdSThomas Bogendoerfer 	    copy_from_user(to->_sifields._pad,
3815d9a76cdSThomas Bogendoerfer 			   from->_sifields._pad, SI_PAD_SIZE32))
3825d9a76cdSThomas Bogendoerfer 		return -EFAULT;
3835d9a76cdSThomas Bogendoerfer 
3845d9a76cdSThomas Bogendoerfer 	return 0;
3855d9a76cdSThomas Bogendoerfer }
3865d9a76cdSThomas Bogendoerfer 
387f90080a0SFranck Bui-Huu asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
3881da177e4SLinus Torvalds {
389dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
3901da177e4SLinus Torvalds 	sigset_t blocked;
391c6a2f467SAtsushi Nemoto 	int sig;
3921da177e4SLinus Torvalds 
393dd02f06aSRalf Baechle 	frame = (struct sigframe32 __user *) regs.regs[29];
3941da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
3951da177e4SLinus Torvalds 		goto badframe;
396431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
3971da177e4SLinus Torvalds 		goto badframe;
3981da177e4SLinus Torvalds 
3998598f3cdSMatt Fleming 	set_current_blocked(&blocked);
4001da177e4SLinus Torvalds 
401c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->sf_sc);
402c6a2f467SAtsushi Nemoto 	if (sig < 0)
4031da177e4SLinus Torvalds 		goto badframe;
404c6a2f467SAtsushi Nemoto 	else if (sig)
405c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	/*
4081da177e4SLinus Torvalds 	 * Don't let your children do this ...
4091da177e4SLinus Torvalds 	 */
4101da177e4SLinus Torvalds 	__asm__ __volatile__(
4111da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
4121da177e4SLinus Torvalds 		"j\tsyscall_exit"
4131da177e4SLinus Torvalds 		:/* no outputs */
4141da177e4SLinus Torvalds 		:"r" (&regs));
4151da177e4SLinus Torvalds 	/* Unreached */
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds badframe:
4181da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
421f90080a0SFranck Bui-Huu asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
4221da177e4SLinus Torvalds {
4239bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
4241da177e4SLinus Torvalds 	sigset_t set;
425c6a2f467SAtsushi Nemoto 	int sig;
4261da177e4SLinus Torvalds 
4279bbf28a3SAtsushi Nemoto 	frame = (struct rt_sigframe32 __user *) regs.regs[29];
4281da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
4291da177e4SLinus Torvalds 		goto badframe;
430431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
4311da177e4SLinus Torvalds 		goto badframe;
4321da177e4SLinus Torvalds 
4338598f3cdSMatt Fleming 	set_current_blocked(&set);
4341da177e4SLinus Torvalds 
435c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
436c6a2f467SAtsushi Nemoto 	if (sig < 0)
4371da177e4SLinus Torvalds 		goto badframe;
438c6a2f467SAtsushi Nemoto 	else if (sig)
439c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
4401da177e4SLinus Torvalds 
441ea536ad4SAl Viro 	if (compat_restore_altstack(&frame->rs_uc.uc_stack))
4421da177e4SLinus Torvalds 		goto badframe;
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	/*
4451da177e4SLinus Torvalds 	 * Don't let your children do this ...
4461da177e4SLinus Torvalds 	 */
4471da177e4SLinus Torvalds 	__asm__ __volatile__(
4481da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
4491da177e4SLinus Torvalds 		"j\tsyscall_exit"
4501da177e4SLinus Torvalds 		:/* no outputs */
4511da177e4SLinus Torvalds 		:"r" (&regs));
4521da177e4SLinus Torvalds 	/* Unreached */
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds badframe:
4551da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
458d814c28cSDavid Daney static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
459d814c28cSDavid Daney 			  struct pt_regs *regs, int signr, sigset_t *set)
4601da177e4SLinus Torvalds {
461dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
4621da177e4SLinus Torvalds 	int err = 0;
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
4651da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
4661da177e4SLinus Torvalds 		goto give_sigsegv;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->sf_sc);
469431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
470431dc804SRalf Baechle 
4711da177e4SLinus Torvalds 	if (err)
4721da177e4SLinus Torvalds 		goto give_sigsegv;
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	/*
4751da177e4SLinus Torvalds 	 * Arguments to signal handler:
4761da177e4SLinus Torvalds 	 *
4771da177e4SLinus Torvalds 	 *   a0 = signal number
4781da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
4791da177e4SLinus Torvalds 	 *   a2 = pointer to struct sigcontext
4801da177e4SLinus Torvalds 	 *
4811da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to the
4821da177e4SLinus Torvalds 	 * struct sigframe.
4831da177e4SLinus Torvalds 	 */
4841da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
4851da177e4SLinus Torvalds 	regs->regs[ 5] = 0;
4861da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
4871da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
488d814c28cSDavid Daney 	regs->regs[31] = (unsigned long) sig_return;
4891da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
4901da177e4SLinus Torvalds 
491722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
4921da177e4SLinus Torvalds 	       current->comm, current->pid,
493722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
494722bb63dSFranck Bui-Huu 
4957b3e2fc8SRalf Baechle 	return 0;
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds give_sigsegv:
4981da177e4SLinus Torvalds 	force_sigsegv(signr, current);
4997b3e2fc8SRalf Baechle 	return -EFAULT;
5001da177e4SLinus Torvalds }
5011da177e4SLinus Torvalds 
502d814c28cSDavid Daney static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
503d814c28cSDavid Daney 			     struct pt_regs *regs, int signr, sigset_t *set,
504d814c28cSDavid Daney 			     siginfo_t *info)
5051da177e4SLinus Torvalds {
5069bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
5071da177e4SLinus Torvalds 	int err = 0;
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
5101da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
5111da177e4SLinus Torvalds 		goto give_sigsegv;
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
5141da177e4SLinus Torvalds 	err |= copy_siginfo_to_user32(&frame->rs_info, info);
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 	/* Create the ucontext.  */
5171da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_flags);
5181da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_link);
519ea536ad4SAl Viro 	err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
5201da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
521431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	if (err)
5241da177e4SLinus Torvalds 		goto give_sigsegv;
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	/*
5271da177e4SLinus Torvalds 	 * Arguments to signal handler:
5281da177e4SLinus Torvalds 	 *
5291da177e4SLinus Torvalds 	 *   a0 = signal number
5301da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
5311da177e4SLinus Torvalds 	 *   a2 = pointer to ucontext
5321da177e4SLinus Torvalds 	 *
5331da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to
5341da177e4SLinus Torvalds 	 * the struct rt_sigframe32.
5351da177e4SLinus Torvalds 	 */
5361da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
5371da177e4SLinus Torvalds 	regs->regs[ 5] = (unsigned long) &frame->rs_info;
5381da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
5391da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
540d814c28cSDavid Daney 	regs->regs[31] = (unsigned long) sig_return;
5411da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
5421da177e4SLinus Torvalds 
543722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
5441da177e4SLinus Torvalds 	       current->comm, current->pid,
545722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
546722bb63dSFranck Bui-Huu 
5477b3e2fc8SRalf Baechle 	return 0;
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds give_sigsegv:
5501da177e4SLinus Torvalds 	force_sigsegv(signr, current);
5517b3e2fc8SRalf Baechle 	return -EFAULT;
5521da177e4SLinus Torvalds }
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds /*
555151fd6acSRalf Baechle  * o32 compatibility on 64-bit kernels, without DSP ASE
5561da177e4SLinus Torvalds  */
557151fd6acSRalf Baechle struct mips_abi mips_abi_32 = {
558151fd6acSRalf Baechle 	.setup_frame	= setup_frame_32,
559d814c28cSDavid Daney 	.signal_return_offset =
560d814c28cSDavid Daney 		offsetof(struct mips_vdso, o32_signal_trampoline),
561151fd6acSRalf Baechle 	.setup_rt_frame	= setup_rt_frame_32,
562d814c28cSDavid Daney 	.rt_signal_return_offset =
563d814c28cSDavid Daney 		offsetof(struct mips_vdso, o32_rt_signal_trampoline),
564151fd6acSRalf Baechle 	.restart	= __NR_O32_restart_syscall
565151fd6acSRalf Baechle };
5661da177e4SLinus Torvalds 
567dbda6ac0SRalf Baechle SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
568dbda6ac0SRalf Baechle 	const struct sigaction32 __user *, act,
569dbda6ac0SRalf Baechle 	struct sigaction32 __user *, oact, unsigned int, sigsetsize)
5701da177e4SLinus Torvalds {
5711da177e4SLinus Torvalds 	struct k_sigaction new_sa, old_sa;
5721da177e4SLinus Torvalds 	int ret = -EINVAL;
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 	/* XXX: Don't preclude handling different sized sigset_t's.  */
5751da177e4SLinus Torvalds 	if (sigsetsize != sizeof(sigset_t))
5761da177e4SLinus Torvalds 		goto out;
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds 	if (act) {
57977c728c2SRalf Baechle 		s32 handler;
5801da177e4SLinus Torvalds 		int err = 0;
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
5831da177e4SLinus Torvalds 			return -EFAULT;
58477c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
5859bbf28a3SAtsushi Nemoto 		new_sa.sa.sa_handler = (void __user *)(s64)handler;
5861da177e4SLinus Torvalds 		err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
5871da177e4SLinus Torvalds 		err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
5881da177e4SLinus Torvalds 		if (err)
5891da177e4SLinus Torvalds 			return -EFAULT;
5901da177e4SLinus Torvalds 	}
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 	if (!ret && oact) {
5951da177e4SLinus Torvalds 		int err = 0;
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
5981da177e4SLinus Torvalds 			return -EFAULT;
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
6011da177e4SLinus Torvalds 		                   &oact->sa_handler);
6021da177e4SLinus Torvalds 		err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
6031da177e4SLinus Torvalds 		err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
6041da177e4SLinus Torvalds 		if (err)
6051da177e4SLinus Torvalds 			return -EFAULT;
6061da177e4SLinus Torvalds 	}
6071da177e4SLinus Torvalds out:
6081da177e4SLinus Torvalds 	return ret;
6091da177e4SLinus Torvalds }
6101da177e4SLinus Torvalds 
611137f6f3eSRalf Baechle static int signal32_init(void)
612137f6f3eSRalf Baechle {
613137f6f3eSRalf Baechle 	if (cpu_has_fpu) {
614137f6f3eSRalf Baechle 		save_fp_context32 = _save_fp_context32;
615137f6f3eSRalf Baechle 		restore_fp_context32 = _restore_fp_context32;
616137f6f3eSRalf Baechle 	} else {
617137f6f3eSRalf Baechle 		save_fp_context32 = fpu_emulator_save_context32;
618137f6f3eSRalf Baechle 		restore_fp_context32 = fpu_emulator_restore_context32;
619137f6f3eSRalf Baechle 	}
620137f6f3eSRalf Baechle 
621137f6f3eSRalf Baechle 	return 0;
622137f6f3eSRalf Baechle }
623137f6f3eSRalf Baechle 
624137f6f3eSRalf Baechle arch_initcall(signal32_init);
625