xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision ce3959604878c1c693979ec552069dc8bdb5ccde)
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 ucontext32 {
591da177e4SLinus Torvalds 	u32		    uc_flags;
601da177e4SLinus Torvalds 	s32		    uc_link;
61ea536ad4SAl Viro 	compat_stack_t      uc_stack;
621da177e4SLinus Torvalds 	struct sigcontext32 uc_mcontext;
6301ee6037SRalf Baechle 	compat_sigset_t	    uc_sigmask;	  /* mask last for extensibility */
641da177e4SLinus Torvalds };
651da177e4SLinus Torvalds 
66dd02f06aSRalf Baechle struct sigframe32 {
67dd02f06aSRalf Baechle 	u32 sf_ass[4];		/* argument save space for o32 */
68d814c28cSDavid Daney 	u32 sf_pad[2];		/* Was: signal trampoline */
69dd02f06aSRalf Baechle 	struct sigcontext32 sf_sc;
70755f21bbSAtsushi Nemoto 	compat_sigset_t sf_mask;
71dd02f06aSRalf Baechle };
72dd02f06aSRalf Baechle 
73c0b9bae9SFranck Bui-Huu struct rt_sigframe32 {
74c0b9bae9SFranck Bui-Huu 	u32 rs_ass[4];			/* argument save space for o32 */
75d814c28cSDavid Daney 	u32 rs_pad[2];			/* Was: signal trampoline */
76c0b9bae9SFranck Bui-Huu 	compat_siginfo_t rs_info;
77c0b9bae9SFranck Bui-Huu 	struct ucontext32 rs_uc;
78c0b9bae9SFranck Bui-Huu };
79c0b9bae9SFranck Bui-Huu 
809432a9baSFranck Bui-Huu /*
819432a9baSFranck Bui-Huu  * sigcontext handlers
829432a9baSFranck Bui-Huu  */
83faea6234SAtsushi Nemoto static int protected_save_fp_context32(struct sigcontext32 __user *sc)
84faea6234SAtsushi Nemoto {
85faea6234SAtsushi Nemoto 	int err;
86faea6234SAtsushi Nemoto 	while (1) {
87faea6234SAtsushi Nemoto 		lock_fpu_owner();
88faea6234SAtsushi Nemoto 		own_fpu_inatomic(1);
89faea6234SAtsushi Nemoto 		err = save_fp_context32(sc); /* this might fail */
90faea6234SAtsushi Nemoto 		unlock_fpu_owner();
91faea6234SAtsushi Nemoto 		if (likely(!err))
92faea6234SAtsushi Nemoto 			break;
93faea6234SAtsushi Nemoto 		/* touch the sigcontext and try again */
94faea6234SAtsushi Nemoto 		err = __put_user(0, &sc->sc_fpregs[0]) |
95faea6234SAtsushi Nemoto 			__put_user(0, &sc->sc_fpregs[31]) |
96faea6234SAtsushi Nemoto 			__put_user(0, &sc->sc_fpc_csr);
97faea6234SAtsushi Nemoto 		if (err)
98faea6234SAtsushi Nemoto 			break;	/* really bad sigcontext */
99faea6234SAtsushi Nemoto 	}
100faea6234SAtsushi Nemoto 	return err;
101faea6234SAtsushi Nemoto }
102faea6234SAtsushi Nemoto 
103faea6234SAtsushi Nemoto static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
104faea6234SAtsushi Nemoto {
105c726b822SDavid Daney 	int err, tmp __maybe_unused;
106faea6234SAtsushi Nemoto 	while (1) {
107faea6234SAtsushi Nemoto 		lock_fpu_owner();
108faea6234SAtsushi Nemoto 		own_fpu_inatomic(0);
109faea6234SAtsushi Nemoto 		err = restore_fp_context32(sc); /* this might fail */
110faea6234SAtsushi Nemoto 		unlock_fpu_owner();
111faea6234SAtsushi Nemoto 		if (likely(!err))
112faea6234SAtsushi Nemoto 			break;
113faea6234SAtsushi Nemoto 		/* touch the sigcontext and try again */
114faea6234SAtsushi Nemoto 		err = __get_user(tmp, &sc->sc_fpregs[0]) |
115faea6234SAtsushi Nemoto 			__get_user(tmp, &sc->sc_fpregs[31]) |
116faea6234SAtsushi Nemoto 			__get_user(tmp, &sc->sc_fpc_csr);
117faea6234SAtsushi Nemoto 		if (err)
118faea6234SAtsushi Nemoto 			break;	/* really bad sigcontext */
119faea6234SAtsushi Nemoto 	}
120faea6234SAtsushi Nemoto 	return err;
121faea6234SAtsushi Nemoto }
122faea6234SAtsushi Nemoto 
1239432a9baSFranck Bui-Huu static int setup_sigcontext32(struct pt_regs *regs,
1249432a9baSFranck Bui-Huu 			      struct sigcontext32 __user *sc)
1259432a9baSFranck Bui-Huu {
1269432a9baSFranck Bui-Huu 	int err = 0;
1279432a9baSFranck Bui-Huu 	int i;
12853dc8028SAtsushi Nemoto 	u32 used_math;
1299432a9baSFranck Bui-Huu 
1309432a9baSFranck Bui-Huu 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
1319432a9baSFranck Bui-Huu 
1329432a9baSFranck Bui-Huu 	err |= __put_user(0, &sc->sc_regs[0]);
1339432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
1349432a9baSFranck Bui-Huu 		err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
1359432a9baSFranck Bui-Huu 
1369432a9baSFranck Bui-Huu 	err |= __put_user(regs->hi, &sc->sc_mdhi);
1379432a9baSFranck Bui-Huu 	err |= __put_user(regs->lo, &sc->sc_mdlo);
1389432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
1399432a9baSFranck Bui-Huu 		err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
1409432a9baSFranck Bui-Huu 		err |= __put_user(mfhi1(), &sc->sc_hi1);
1419432a9baSFranck Bui-Huu 		err |= __put_user(mflo1(), &sc->sc_lo1);
1429432a9baSFranck Bui-Huu 		err |= __put_user(mfhi2(), &sc->sc_hi2);
1439432a9baSFranck Bui-Huu 		err |= __put_user(mflo2(), &sc->sc_lo2);
1449432a9baSFranck Bui-Huu 		err |= __put_user(mfhi3(), &sc->sc_hi3);
1459432a9baSFranck Bui-Huu 		err |= __put_user(mflo3(), &sc->sc_lo3);
1469432a9baSFranck Bui-Huu 	}
1479432a9baSFranck Bui-Huu 
14853dc8028SAtsushi Nemoto 	used_math = !!used_math();
14953dc8028SAtsushi Nemoto 	err |= __put_user(used_math, &sc->sc_used_math);
1509432a9baSFranck Bui-Huu 
15153dc8028SAtsushi Nemoto 	if (used_math) {
1529432a9baSFranck Bui-Huu 		/*
1539432a9baSFranck Bui-Huu 		 * Save FPU state to signal context.  Signal handler
1549432a9baSFranck Bui-Huu 		 * will "inherit" current FPU state.
1559432a9baSFranck Bui-Huu 		 */
156faea6234SAtsushi Nemoto 		err |= protected_save_fp_context32(sc);
1579432a9baSFranck Bui-Huu 	}
1589432a9baSFranck Bui-Huu 	return err;
1599432a9baSFranck Bui-Huu }
1609432a9baSFranck Bui-Huu 
161c6a2f467SAtsushi Nemoto static int
162c6a2f467SAtsushi Nemoto check_and_restore_fp_context32(struct sigcontext32 __user *sc)
163c6a2f467SAtsushi Nemoto {
164c6a2f467SAtsushi Nemoto 	int err, sig;
165c6a2f467SAtsushi Nemoto 
166c6a2f467SAtsushi Nemoto 	err = sig = fpcsr_pending(&sc->sc_fpc_csr);
167c6a2f467SAtsushi Nemoto 	if (err > 0)
168c6a2f467SAtsushi Nemoto 		err = 0;
169faea6234SAtsushi Nemoto 	err |= protected_restore_fp_context32(sc);
170c6a2f467SAtsushi Nemoto 	return err ?: sig;
171c6a2f467SAtsushi Nemoto }
172c6a2f467SAtsushi Nemoto 
1739432a9baSFranck Bui-Huu static int restore_sigcontext32(struct pt_regs *regs,
1749432a9baSFranck Bui-Huu 				struct sigcontext32 __user *sc)
1759432a9baSFranck Bui-Huu {
1769432a9baSFranck Bui-Huu 	u32 used_math;
1779432a9baSFranck Bui-Huu 	int err = 0;
1789432a9baSFranck Bui-Huu 	s32 treg;
1799432a9baSFranck Bui-Huu 	int i;
1809432a9baSFranck Bui-Huu 
1819432a9baSFranck Bui-Huu 	/* Always make any pending restarted system calls return -EINTR */
1829432a9baSFranck Bui-Huu 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
1839432a9baSFranck Bui-Huu 
1849432a9baSFranck Bui-Huu 	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
1859432a9baSFranck Bui-Huu 	err |= __get_user(regs->hi, &sc->sc_mdhi);
1869432a9baSFranck Bui-Huu 	err |= __get_user(regs->lo, &sc->sc_mdlo);
1879432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
1889432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
1899432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
1909432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
1919432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
1929432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
1939432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
1949432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
1959432a9baSFranck Bui-Huu 	}
1969432a9baSFranck Bui-Huu 
1979432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
1989432a9baSFranck Bui-Huu 		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
1999432a9baSFranck Bui-Huu 
2009432a9baSFranck Bui-Huu 	err |= __get_user(used_math, &sc->sc_used_math);
2019432a9baSFranck Bui-Huu 	conditional_used_math(used_math);
2029432a9baSFranck Bui-Huu 
20353dc8028SAtsushi Nemoto 	if (used_math) {
2049432a9baSFranck Bui-Huu 		/* restore fpu context if we have used it before */
205c6a2f467SAtsushi Nemoto 		if (!err)
206c6a2f467SAtsushi Nemoto 			err = check_and_restore_fp_context32(sc);
2079432a9baSFranck Bui-Huu 	} else {
2089432a9baSFranck Bui-Huu 		/* signal handler may have used FPU.  Give it up. */
20953dc8028SAtsushi Nemoto 		lose_fpu(0);
2109432a9baSFranck Bui-Huu 	}
2119432a9baSFranck Bui-Huu 
2129432a9baSFranck Bui-Huu 	return err;
2139432a9baSFranck Bui-Huu }
2149432a9baSFranck Bui-Huu 
2159432a9baSFranck Bui-Huu /*
2169432a9baSFranck Bui-Huu  *
2179432a9baSFranck Bui-Huu  */
2181da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void);
2191da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void);
2201da177e4SLinus Torvalds 
2219bbf28a3SAtsushi Nemoto static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds 	int err = 0;
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
2261da177e4SLinus Torvalds 		return -EFAULT;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
2291da177e4SLinus Torvalds 	default:
2301da177e4SLinus Torvalds 		__put_sigset_unknown_nsig();
2311da177e4SLinus Torvalds 	case 2:
2321da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
2331da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
2341da177e4SLinus Torvalds 	case 1:
2351da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
2361da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	return err;
2401da177e4SLinus Torvalds }
2411da177e4SLinus Torvalds 
2429c6031ccSAtsushi Nemoto static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
2431da177e4SLinus Torvalds {
2441da177e4SLinus Torvalds 	int err = 0;
2451da177e4SLinus Torvalds 	unsigned long sig[4];
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
2481da177e4SLinus Torvalds 		return -EFAULT;
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
2511da177e4SLinus Torvalds 	default:
2521da177e4SLinus Torvalds 		__get_sigset_unknown_nsig();
2531da177e4SLinus Torvalds 	case 2:
2541da177e4SLinus Torvalds 		err |= __get_user(sig[3], &ubuf->sig[3]);
2551da177e4SLinus Torvalds 		err |= __get_user(sig[2], &ubuf->sig[2]);
2561da177e4SLinus Torvalds 		kbuf->sig[1] = sig[2] | (sig[3] << 32);
2571da177e4SLinus Torvalds 	case 1:
2581da177e4SLinus Torvalds 		err |= __get_user(sig[1], &ubuf->sig[1]);
2591da177e4SLinus Torvalds 		err |= __get_user(sig[0], &ubuf->sig[0]);
2601da177e4SLinus Torvalds 		kbuf->sig[0] = sig[0] | (sig[1] << 32);
2611da177e4SLinus Torvalds 	}
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	return err;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds /*
2671da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
2681da177e4SLinus Torvalds  */
2691da177e4SLinus Torvalds 
2701910f4abSAl Viro asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
2711da177e4SLinus Torvalds {
2721910f4abSAl Viro 	return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds 
275aa584802SAl Viro SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
276aa584802SAl Viro 	struct compat_sigaction __user *, oact)
2771da177e4SLinus Torvalds {
2781da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
2791da177e4SLinus Torvalds 	int ret;
2801da177e4SLinus Torvalds 	int err = 0;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	if (act) {
2831da177e4SLinus Torvalds 		old_sigset_t mask;
28477c728c2SRalf Baechle 		s32 handler;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
2871da177e4SLinus Torvalds 			return -EFAULT;
28877c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
2899bbf28a3SAtsushi Nemoto 		new_ka.sa.sa_handler = (void __user *)(s64)handler;
2901da177e4SLinus Torvalds 		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
2911da177e4SLinus Torvalds 		err |= __get_user(mask, &act->sa_mask.sig[0]);
2921da177e4SLinus Torvalds 		if (err)
2931da177e4SLinus Torvalds 			return -EFAULT;
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
2961da177e4SLinus Torvalds 	}
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	if (!ret && oact) {
3011da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
3021da177e4SLinus Torvalds 			return -EFAULT;
3031da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
3041da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
3051da177e4SLinus Torvalds 				  &oact->sa_handler);
3061da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
3071da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[1]);
3081da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[2]);
3091da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[3]);
3101da177e4SLinus Torvalds 		if (err)
3111da177e4SLinus Torvalds 			return -EFAULT;
3121da177e4SLinus Torvalds 	}
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	return ret;
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds 
317*ce395960SAl Viro int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
3181da177e4SLinus Torvalds {
3191da177e4SLinus Torvalds 	int err;
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
3221da177e4SLinus Torvalds 		return -EFAULT;
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	/* If you change siginfo_t structure, please be sure
3251da177e4SLinus Torvalds 	   this code is fixed accordingly.
3261da177e4SLinus Torvalds 	   It should never copy any pad contained in the structure
3271da177e4SLinus Torvalds 	   to avoid security leaks, but must copy the generic
3281da177e4SLinus Torvalds 	   3 ints plus the relevant union member.
3291da177e4SLinus Torvalds 	   This routine must convert siginfo from 64bit to 32bit as well
3301da177e4SLinus Torvalds 	   at the same time.  */
3311da177e4SLinus Torvalds 	err = __put_user(from->si_signo, &to->si_signo);
3321da177e4SLinus Torvalds 	err |= __put_user(from->si_errno, &to->si_errno);
3331da177e4SLinus Torvalds 	err |= __put_user((short)from->si_code, &to->si_code);
3341da177e4SLinus Torvalds 	if (from->si_code < 0)
3351da177e4SLinus Torvalds 		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
3361da177e4SLinus Torvalds 	else {
3371da177e4SLinus Torvalds 		switch (from->si_code >> 16) {
338a982099cSRalf Baechle 		case __SI_TIMER >> 16:
339a982099cSRalf Baechle 			err |= __put_user(from->si_tid, &to->si_tid);
340a982099cSRalf Baechle 			err |= __put_user(from->si_overrun, &to->si_overrun);
341a982099cSRalf Baechle 			err |= __put_user(from->si_int, &to->si_int);
342a982099cSRalf Baechle 			break;
3431da177e4SLinus Torvalds 		case __SI_CHLD >> 16:
3441da177e4SLinus Torvalds 			err |= __put_user(from->si_utime, &to->si_utime);
3451da177e4SLinus Torvalds 			err |= __put_user(from->si_stime, &to->si_stime);
3461da177e4SLinus Torvalds 			err |= __put_user(from->si_status, &to->si_status);
3471da177e4SLinus Torvalds 		default:
3481da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
3491da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
3501da177e4SLinus Torvalds 			break;
3511da177e4SLinus Torvalds 		case __SI_FAULT >> 16:
3525665a0acSAtsushi Nemoto 			err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
3531da177e4SLinus Torvalds 			break;
3541da177e4SLinus Torvalds 		case __SI_POLL >> 16:
3551da177e4SLinus Torvalds 			err |= __put_user(from->si_band, &to->si_band);
3561da177e4SLinus Torvalds 			err |= __put_user(from->si_fd, &to->si_fd);
3571da177e4SLinus Torvalds 			break;
3581da177e4SLinus Torvalds 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
3591da177e4SLinus Torvalds 		case __SI_MESGQ >> 16:
3601da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
3611da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
3621da177e4SLinus Torvalds 			err |= __put_user(from->si_int, &to->si_int);
3631da177e4SLinus Torvalds 			break;
3641da177e4SLinus Torvalds 		}
3651da177e4SLinus Torvalds 	}
3661da177e4SLinus Torvalds 	return err;
3671da177e4SLinus Torvalds }
3681da177e4SLinus Torvalds 
3695d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
3705d9a76cdSThomas Bogendoerfer {
3715d9a76cdSThomas Bogendoerfer 	memset(to, 0, sizeof *to);
3725d9a76cdSThomas Bogendoerfer 
3735d9a76cdSThomas Bogendoerfer 	if (copy_from_user(to, from, 3*sizeof(int)) ||
3745d9a76cdSThomas Bogendoerfer 	    copy_from_user(to->_sifields._pad,
3755d9a76cdSThomas Bogendoerfer 			   from->_sifields._pad, SI_PAD_SIZE32))
3765d9a76cdSThomas Bogendoerfer 		return -EFAULT;
3775d9a76cdSThomas Bogendoerfer 
3785d9a76cdSThomas Bogendoerfer 	return 0;
3795d9a76cdSThomas Bogendoerfer }
3805d9a76cdSThomas Bogendoerfer 
381f90080a0SFranck Bui-Huu asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
3821da177e4SLinus Torvalds {
383dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
3841da177e4SLinus Torvalds 	sigset_t blocked;
385c6a2f467SAtsushi Nemoto 	int sig;
3861da177e4SLinus Torvalds 
387dd02f06aSRalf Baechle 	frame = (struct sigframe32 __user *) regs.regs[29];
3881da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
3891da177e4SLinus Torvalds 		goto badframe;
390431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
3911da177e4SLinus Torvalds 		goto badframe;
3921da177e4SLinus Torvalds 
3938598f3cdSMatt Fleming 	set_current_blocked(&blocked);
3941da177e4SLinus Torvalds 
395c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->sf_sc);
396c6a2f467SAtsushi Nemoto 	if (sig < 0)
3971da177e4SLinus Torvalds 		goto badframe;
398c6a2f467SAtsushi Nemoto 	else if (sig)
399c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds 	/*
4021da177e4SLinus Torvalds 	 * Don't let your children do this ...
4031da177e4SLinus Torvalds 	 */
4041da177e4SLinus Torvalds 	__asm__ __volatile__(
4051da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
4061da177e4SLinus Torvalds 		"j\tsyscall_exit"
4071da177e4SLinus Torvalds 		:/* no outputs */
4081da177e4SLinus Torvalds 		:"r" (&regs));
4091da177e4SLinus Torvalds 	/* Unreached */
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds badframe:
4121da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds 
415f90080a0SFranck Bui-Huu asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
4161da177e4SLinus Torvalds {
4179bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
4181da177e4SLinus Torvalds 	sigset_t set;
419c6a2f467SAtsushi Nemoto 	int sig;
4201da177e4SLinus Torvalds 
4219bbf28a3SAtsushi Nemoto 	frame = (struct rt_sigframe32 __user *) regs.regs[29];
4221da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
4231da177e4SLinus Torvalds 		goto badframe;
424431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
4251da177e4SLinus Torvalds 		goto badframe;
4261da177e4SLinus Torvalds 
4278598f3cdSMatt Fleming 	set_current_blocked(&set);
4281da177e4SLinus Torvalds 
429c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
430c6a2f467SAtsushi Nemoto 	if (sig < 0)
4311da177e4SLinus Torvalds 		goto badframe;
432c6a2f467SAtsushi Nemoto 	else if (sig)
433c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
4341da177e4SLinus Torvalds 
435ea536ad4SAl Viro 	if (compat_restore_altstack(&frame->rs_uc.uc_stack))
4361da177e4SLinus Torvalds 		goto badframe;
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	/*
4391da177e4SLinus Torvalds 	 * Don't let your children do this ...
4401da177e4SLinus Torvalds 	 */
4411da177e4SLinus Torvalds 	__asm__ __volatile__(
4421da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
4431da177e4SLinus Torvalds 		"j\tsyscall_exit"
4441da177e4SLinus Torvalds 		:/* no outputs */
4451da177e4SLinus Torvalds 		:"r" (&regs));
4461da177e4SLinus Torvalds 	/* Unreached */
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds badframe:
4491da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
4501da177e4SLinus Torvalds }
4511da177e4SLinus Torvalds 
452d814c28cSDavid Daney static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
453d814c28cSDavid Daney 			  struct pt_regs *regs, int signr, sigset_t *set)
4541da177e4SLinus Torvalds {
455dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
4561da177e4SLinus Torvalds 	int err = 0;
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
4591da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
4601da177e4SLinus Torvalds 		goto give_sigsegv;
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->sf_sc);
463431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
464431dc804SRalf Baechle 
4651da177e4SLinus Torvalds 	if (err)
4661da177e4SLinus Torvalds 		goto give_sigsegv;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	/*
4691da177e4SLinus Torvalds 	 * Arguments to signal handler:
4701da177e4SLinus Torvalds 	 *
4711da177e4SLinus Torvalds 	 *   a0 = signal number
4721da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
4731da177e4SLinus Torvalds 	 *   a2 = pointer to struct sigcontext
4741da177e4SLinus Torvalds 	 *
4751da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to the
4761da177e4SLinus Torvalds 	 * struct sigframe.
4771da177e4SLinus Torvalds 	 */
4781da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
4791da177e4SLinus Torvalds 	regs->regs[ 5] = 0;
4801da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
4811da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
482d814c28cSDavid Daney 	regs->regs[31] = (unsigned long) sig_return;
4831da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
4841da177e4SLinus Torvalds 
485722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
4861da177e4SLinus Torvalds 	       current->comm, current->pid,
487722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
488722bb63dSFranck Bui-Huu 
4897b3e2fc8SRalf Baechle 	return 0;
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds give_sigsegv:
4921da177e4SLinus Torvalds 	force_sigsegv(signr, current);
4937b3e2fc8SRalf Baechle 	return -EFAULT;
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds 
496d814c28cSDavid Daney static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
497d814c28cSDavid Daney 			     struct pt_regs *regs, int signr, sigset_t *set,
498d814c28cSDavid Daney 			     siginfo_t *info)
4991da177e4SLinus Torvalds {
5009bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
5011da177e4SLinus Torvalds 	int err = 0;
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
5041da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
5051da177e4SLinus Torvalds 		goto give_sigsegv;
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
5081da177e4SLinus Torvalds 	err |= copy_siginfo_to_user32(&frame->rs_info, info);
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	/* Create the ucontext.	 */
5111da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_flags);
5121da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_link);
513ea536ad4SAl Viro 	err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
5141da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
515431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	if (err)
5181da177e4SLinus Torvalds 		goto give_sigsegv;
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 	/*
5211da177e4SLinus Torvalds 	 * Arguments to signal handler:
5221da177e4SLinus Torvalds 	 *
5231da177e4SLinus Torvalds 	 *   a0 = signal number
5241da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
5251da177e4SLinus Torvalds 	 *   a2 = pointer to ucontext
5261da177e4SLinus Torvalds 	 *
5271da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to
5281da177e4SLinus Torvalds 	 * the struct rt_sigframe32.
5291da177e4SLinus Torvalds 	 */
5301da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
5311da177e4SLinus Torvalds 	regs->regs[ 5] = (unsigned long) &frame->rs_info;
5321da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
5331da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
534d814c28cSDavid Daney 	regs->regs[31] = (unsigned long) sig_return;
5351da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
5361da177e4SLinus Torvalds 
537722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
5381da177e4SLinus Torvalds 	       current->comm, current->pid,
539722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
540722bb63dSFranck Bui-Huu 
5417b3e2fc8SRalf Baechle 	return 0;
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds give_sigsegv:
5441da177e4SLinus Torvalds 	force_sigsegv(signr, current);
5457b3e2fc8SRalf Baechle 	return -EFAULT;
5461da177e4SLinus Torvalds }
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds /*
549151fd6acSRalf Baechle  * o32 compatibility on 64-bit kernels, without DSP ASE
5501da177e4SLinus Torvalds  */
551151fd6acSRalf Baechle struct mips_abi mips_abi_32 = {
552151fd6acSRalf Baechle 	.setup_frame	= setup_frame_32,
553d814c28cSDavid Daney 	.signal_return_offset =
554d814c28cSDavid Daney 		offsetof(struct mips_vdso, o32_signal_trampoline),
555151fd6acSRalf Baechle 	.setup_rt_frame = setup_rt_frame_32,
556d814c28cSDavid Daney 	.rt_signal_return_offset =
557d814c28cSDavid Daney 		offsetof(struct mips_vdso, o32_rt_signal_trampoline),
558151fd6acSRalf Baechle 	.restart	= __NR_O32_restart_syscall
559151fd6acSRalf Baechle };
5601da177e4SLinus Torvalds 
561137f6f3eSRalf Baechle static int signal32_init(void)
562137f6f3eSRalf Baechle {
563137f6f3eSRalf Baechle 	if (cpu_has_fpu) {
564137f6f3eSRalf Baechle 		save_fp_context32 = _save_fp_context32;
565137f6f3eSRalf Baechle 		restore_fp_context32 = _restore_fp_context32;
566137f6f3eSRalf Baechle 	} else {
567137f6f3eSRalf Baechle 		save_fp_context32 = fpu_emulator_save_context32;
568137f6f3eSRalf Baechle 		restore_fp_context32 = fpu_emulator_restore_context32;
569137f6f3eSRalf Baechle 	}
570137f6f3eSRalf Baechle 
571137f6f3eSRalf Baechle 	return 0;
572137f6f3eSRalf Baechle }
573137f6f3eSRalf Baechle 
574137f6f3eSRalf Baechle arch_initcall(signal32_init);
575