xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision 5d9a76cd0ed367d01b0b237253adb7607e86a277)
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/system.h>
331da177e4SLinus Torvalds #include <asm/fpu.h>
3402416dcfSRalf Baechle #include <asm/war.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_sigreturn		4119
421da177e4SLinus Torvalds #define __NR_O32_rt_sigreturn		4193
431da177e4SLinus Torvalds #define __NR_O32_restart_syscall        4253
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds /* 32-bit compatibility types */
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds typedef unsigned int __sighandler32_t;
481da177e4SLinus Torvalds typedef void (*vfptr_t)(void);
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds struct sigaction32 {
511da177e4SLinus Torvalds 	unsigned int		sa_flags;
521da177e4SLinus Torvalds 	__sighandler32_t	sa_handler;
531da177e4SLinus Torvalds 	compat_sigset_t		sa_mask;
541da177e4SLinus Torvalds };
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds /* IRIX compatible stack_t  */
571da177e4SLinus Torvalds typedef struct sigaltstack32 {
581da177e4SLinus Torvalds 	s32 ss_sp;
591da177e4SLinus Torvalds 	compat_size_t ss_size;
601da177e4SLinus Torvalds 	int ss_flags;
611da177e4SLinus Torvalds } stack32_t;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds struct ucontext32 {
641da177e4SLinus Torvalds 	u32                 uc_flags;
651da177e4SLinus Torvalds 	s32                 uc_link;
661da177e4SLinus Torvalds 	stack32_t           uc_stack;
671da177e4SLinus Torvalds 	struct sigcontext32 uc_mcontext;
6801ee6037SRalf Baechle 	compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
691da177e4SLinus Torvalds };
701da177e4SLinus Torvalds 
71dd02f06aSRalf Baechle /*
72dd02f06aSRalf Baechle  * Horribly complicated - with the bloody RM9000 workarounds enabled
73dd02f06aSRalf Baechle  * the signal trampolines is moving to the end of the structure so we can
74dd02f06aSRalf Baechle  * increase the alignment without breaking software compatibility.
75dd02f06aSRalf Baechle  */
76c0b9bae9SFranck Bui-Huu #if ICACHE_REFILLS_WORKAROUND_WAR == 0
77c0b9bae9SFranck Bui-Huu 
78dd02f06aSRalf Baechle struct sigframe32 {
79dd02f06aSRalf Baechle 	u32 sf_ass[4];		/* argument save space for o32 */
80dd02f06aSRalf Baechle 	u32 sf_code[2];		/* signal trampoline */
81dd02f06aSRalf Baechle 	struct sigcontext32 sf_sc;
82755f21bbSAtsushi Nemoto 	compat_sigset_t sf_mask;
83dd02f06aSRalf Baechle };
84dd02f06aSRalf Baechle 
85c0b9bae9SFranck Bui-Huu struct rt_sigframe32 {
86c0b9bae9SFranck Bui-Huu 	u32 rs_ass[4];			/* argument save space for o32 */
87c0b9bae9SFranck Bui-Huu 	u32 rs_code[2];			/* signal trampoline */
88c0b9bae9SFranck Bui-Huu 	compat_siginfo_t rs_info;
89c0b9bae9SFranck Bui-Huu 	struct ucontext32 rs_uc;
90c0b9bae9SFranck Bui-Huu };
91c0b9bae9SFranck Bui-Huu 
92c0b9bae9SFranck Bui-Huu #else  /* ICACHE_REFILLS_WORKAROUND_WAR */
93c0b9bae9SFranck Bui-Huu 
94dd02f06aSRalf Baechle struct sigframe32 {
95dd02f06aSRalf Baechle 	u32 sf_ass[4];			/* argument save space for o32 */
96dd02f06aSRalf Baechle 	u32 sf_pad[2];
97dd02f06aSRalf Baechle 	struct sigcontext32 sf_sc;	/* hw context */
98755f21bbSAtsushi Nemoto 	compat_sigset_t sf_mask;
99dd02f06aSRalf Baechle 	u32 sf_code[8] ____cacheline_aligned;	/* signal trampoline */
100dd02f06aSRalf Baechle };
101dd02f06aSRalf Baechle 
102c0b9bae9SFranck Bui-Huu struct rt_sigframe32 {
103c0b9bae9SFranck Bui-Huu 	u32 rs_ass[4];			/* argument save space for o32 */
104c0b9bae9SFranck Bui-Huu 	u32 rs_pad[2];
105c0b9bae9SFranck Bui-Huu 	compat_siginfo_t rs_info;
106c0b9bae9SFranck Bui-Huu 	struct ucontext32 rs_uc;
107c0b9bae9SFranck Bui-Huu 	u32 rs_code[8] __attribute__((aligned(32)));	/* signal trampoline */
108c0b9bae9SFranck Bui-Huu };
109c0b9bae9SFranck Bui-Huu 
110c0b9bae9SFranck Bui-Huu #endif	/* !ICACHE_REFILLS_WORKAROUND_WAR */
111c0b9bae9SFranck Bui-Huu 
1129432a9baSFranck Bui-Huu /*
1139432a9baSFranck Bui-Huu  * sigcontext handlers
1149432a9baSFranck Bui-Huu  */
115faea6234SAtsushi Nemoto static int protected_save_fp_context32(struct sigcontext32 __user *sc)
116faea6234SAtsushi Nemoto {
117faea6234SAtsushi Nemoto 	int err;
118faea6234SAtsushi Nemoto 	while (1) {
119faea6234SAtsushi Nemoto 		lock_fpu_owner();
120faea6234SAtsushi Nemoto 		own_fpu_inatomic(1);
121faea6234SAtsushi Nemoto 		err = save_fp_context32(sc); /* this might fail */
122faea6234SAtsushi Nemoto 		unlock_fpu_owner();
123faea6234SAtsushi Nemoto 		if (likely(!err))
124faea6234SAtsushi Nemoto 			break;
125faea6234SAtsushi Nemoto 		/* touch the sigcontext and try again */
126faea6234SAtsushi Nemoto 		err = __put_user(0, &sc->sc_fpregs[0]) |
127faea6234SAtsushi Nemoto 			__put_user(0, &sc->sc_fpregs[31]) |
128faea6234SAtsushi Nemoto 			__put_user(0, &sc->sc_fpc_csr);
129faea6234SAtsushi Nemoto 		if (err)
130faea6234SAtsushi Nemoto 			break;	/* really bad sigcontext */
131faea6234SAtsushi Nemoto 	}
132faea6234SAtsushi Nemoto 	return err;
133faea6234SAtsushi Nemoto }
134faea6234SAtsushi Nemoto 
135faea6234SAtsushi Nemoto static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
136faea6234SAtsushi Nemoto {
137faea6234SAtsushi Nemoto 	int err, tmp;
138faea6234SAtsushi Nemoto 	while (1) {
139faea6234SAtsushi Nemoto 		lock_fpu_owner();
140faea6234SAtsushi Nemoto 		own_fpu_inatomic(0);
141faea6234SAtsushi Nemoto 		err = restore_fp_context32(sc); /* this might fail */
142faea6234SAtsushi Nemoto 		unlock_fpu_owner();
143faea6234SAtsushi Nemoto 		if (likely(!err))
144faea6234SAtsushi Nemoto 			break;
145faea6234SAtsushi Nemoto 		/* touch the sigcontext and try again */
146faea6234SAtsushi Nemoto 		err = __get_user(tmp, &sc->sc_fpregs[0]) |
147faea6234SAtsushi Nemoto 			__get_user(tmp, &sc->sc_fpregs[31]) |
148faea6234SAtsushi Nemoto 			__get_user(tmp, &sc->sc_fpc_csr);
149faea6234SAtsushi Nemoto 		if (err)
150faea6234SAtsushi Nemoto 			break;	/* really bad sigcontext */
151faea6234SAtsushi Nemoto 	}
152faea6234SAtsushi Nemoto 	return err;
153faea6234SAtsushi Nemoto }
154faea6234SAtsushi Nemoto 
1559432a9baSFranck Bui-Huu static int setup_sigcontext32(struct pt_regs *regs,
1569432a9baSFranck Bui-Huu 			      struct sigcontext32 __user *sc)
1579432a9baSFranck Bui-Huu {
1589432a9baSFranck Bui-Huu 	int err = 0;
1599432a9baSFranck Bui-Huu 	int i;
16053dc8028SAtsushi Nemoto 	u32 used_math;
1619432a9baSFranck Bui-Huu 
1629432a9baSFranck Bui-Huu 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
1639432a9baSFranck Bui-Huu 
1649432a9baSFranck Bui-Huu 	err |= __put_user(0, &sc->sc_regs[0]);
1659432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
1669432a9baSFranck Bui-Huu 		err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
1679432a9baSFranck Bui-Huu 
1689432a9baSFranck Bui-Huu 	err |= __put_user(regs->hi, &sc->sc_mdhi);
1699432a9baSFranck Bui-Huu 	err |= __put_user(regs->lo, &sc->sc_mdlo);
1709432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
1719432a9baSFranck Bui-Huu 		err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
1729432a9baSFranck Bui-Huu 		err |= __put_user(mfhi1(), &sc->sc_hi1);
1739432a9baSFranck Bui-Huu 		err |= __put_user(mflo1(), &sc->sc_lo1);
1749432a9baSFranck Bui-Huu 		err |= __put_user(mfhi2(), &sc->sc_hi2);
1759432a9baSFranck Bui-Huu 		err |= __put_user(mflo2(), &sc->sc_lo2);
1769432a9baSFranck Bui-Huu 		err |= __put_user(mfhi3(), &sc->sc_hi3);
1779432a9baSFranck Bui-Huu 		err |= __put_user(mflo3(), &sc->sc_lo3);
1789432a9baSFranck Bui-Huu 	}
1799432a9baSFranck Bui-Huu 
18053dc8028SAtsushi Nemoto 	used_math = !!used_math();
18153dc8028SAtsushi Nemoto 	err |= __put_user(used_math, &sc->sc_used_math);
1829432a9baSFranck Bui-Huu 
18353dc8028SAtsushi Nemoto 	if (used_math) {
1849432a9baSFranck Bui-Huu 		/*
1859432a9baSFranck Bui-Huu 		 * Save FPU state to signal context.  Signal handler
1869432a9baSFranck Bui-Huu 		 * will "inherit" current FPU state.
1879432a9baSFranck Bui-Huu 		 */
188faea6234SAtsushi Nemoto 		err |= protected_save_fp_context32(sc);
1899432a9baSFranck Bui-Huu 	}
1909432a9baSFranck Bui-Huu 	return err;
1919432a9baSFranck Bui-Huu }
1929432a9baSFranck Bui-Huu 
193c6a2f467SAtsushi Nemoto static int
194c6a2f467SAtsushi Nemoto check_and_restore_fp_context32(struct sigcontext32 __user *sc)
195c6a2f467SAtsushi Nemoto {
196c6a2f467SAtsushi Nemoto 	int err, sig;
197c6a2f467SAtsushi Nemoto 
198c6a2f467SAtsushi Nemoto 	err = sig = fpcsr_pending(&sc->sc_fpc_csr);
199c6a2f467SAtsushi Nemoto 	if (err > 0)
200c6a2f467SAtsushi Nemoto 		err = 0;
201faea6234SAtsushi Nemoto 	err |= protected_restore_fp_context32(sc);
202c6a2f467SAtsushi Nemoto 	return err ?: sig;
203c6a2f467SAtsushi Nemoto }
204c6a2f467SAtsushi Nemoto 
2059432a9baSFranck Bui-Huu static int restore_sigcontext32(struct pt_regs *regs,
2069432a9baSFranck Bui-Huu 				struct sigcontext32 __user *sc)
2079432a9baSFranck Bui-Huu {
2089432a9baSFranck Bui-Huu 	u32 used_math;
2099432a9baSFranck Bui-Huu 	int err = 0;
2109432a9baSFranck Bui-Huu 	s32 treg;
2119432a9baSFranck Bui-Huu 	int i;
2129432a9baSFranck Bui-Huu 
2139432a9baSFranck Bui-Huu 	/* Always make any pending restarted system calls return -EINTR */
2149432a9baSFranck Bui-Huu 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
2159432a9baSFranck Bui-Huu 
2169432a9baSFranck Bui-Huu 	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
2179432a9baSFranck Bui-Huu 	err |= __get_user(regs->hi, &sc->sc_mdhi);
2189432a9baSFranck Bui-Huu 	err |= __get_user(regs->lo, &sc->sc_mdlo);
2199432a9baSFranck Bui-Huu 	if (cpu_has_dsp) {
2209432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2219432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2229432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2239432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2249432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2259432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2269432a9baSFranck Bui-Huu 		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2279432a9baSFranck Bui-Huu 	}
2289432a9baSFranck Bui-Huu 
2299432a9baSFranck Bui-Huu 	for (i = 1; i < 32; i++)
2309432a9baSFranck Bui-Huu 		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
2319432a9baSFranck Bui-Huu 
2329432a9baSFranck Bui-Huu 	err |= __get_user(used_math, &sc->sc_used_math);
2339432a9baSFranck Bui-Huu 	conditional_used_math(used_math);
2349432a9baSFranck Bui-Huu 
23553dc8028SAtsushi Nemoto 	if (used_math) {
2369432a9baSFranck Bui-Huu 		/* restore fpu context if we have used it before */
237c6a2f467SAtsushi Nemoto 		if (!err)
238c6a2f467SAtsushi Nemoto 			err = check_and_restore_fp_context32(sc);
2399432a9baSFranck Bui-Huu 	} else {
2409432a9baSFranck Bui-Huu 		/* signal handler may have used FPU.  Give it up. */
24153dc8028SAtsushi Nemoto 		lose_fpu(0);
2429432a9baSFranck Bui-Huu 	}
2439432a9baSFranck Bui-Huu 
2449432a9baSFranck Bui-Huu 	return err;
2459432a9baSFranck Bui-Huu }
2469432a9baSFranck Bui-Huu 
2479432a9baSFranck Bui-Huu /*
2489432a9baSFranck Bui-Huu  *
2499432a9baSFranck Bui-Huu  */
2501da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void);
2511da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void);
2521da177e4SLinus Torvalds 
2539bbf28a3SAtsushi Nemoto static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds 	int err = 0;
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
2581da177e4SLinus Torvalds 		return -EFAULT;
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
2611da177e4SLinus Torvalds 	default:
2621da177e4SLinus Torvalds 		__put_sigset_unknown_nsig();
2631da177e4SLinus Torvalds 	case 2:
2641da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
2651da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
2661da177e4SLinus Torvalds 	case 1:
2671da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
2681da177e4SLinus Torvalds 		err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
2691da177e4SLinus Torvalds 	}
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	return err;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
2749c6031ccSAtsushi Nemoto static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	int err = 0;
2771da177e4SLinus Torvalds 	unsigned long sig[4];
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
2801da177e4SLinus Torvalds 		return -EFAULT;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
2831da177e4SLinus Torvalds 	default:
2841da177e4SLinus Torvalds 		__get_sigset_unknown_nsig();
2851da177e4SLinus Torvalds 	case 2:
2861da177e4SLinus Torvalds 		err |= __get_user(sig[3], &ubuf->sig[3]);
2871da177e4SLinus Torvalds 		err |= __get_user(sig[2], &ubuf->sig[2]);
2881da177e4SLinus Torvalds 		kbuf->sig[1] = sig[2] | (sig[3] << 32);
2891da177e4SLinus Torvalds 	case 1:
2901da177e4SLinus Torvalds 		err |= __get_user(sig[1], &ubuf->sig[1]);
2911da177e4SLinus Torvalds 		err |= __get_user(sig[0], &ubuf->sig[0]);
2921da177e4SLinus Torvalds 		kbuf->sig[0] = sig[0] | (sig[1] << 32);
2931da177e4SLinus Torvalds 	}
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	return err;
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds /*
2991da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
3001da177e4SLinus Torvalds  */
3011da177e4SLinus Torvalds 
302f90080a0SFranck Bui-Huu asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
3031da177e4SLinus Torvalds {
3049c6031ccSAtsushi Nemoto 	compat_sigset_t __user *uset;
30568fa383fSMartin Michlmayr 	sigset_t newset;
3061da177e4SLinus Torvalds 
3079c6031ccSAtsushi Nemoto 	uset = (compat_sigset_t __user *) regs.regs[4];
3081da177e4SLinus Torvalds 	if (get_sigset(&newset, uset))
3091da177e4SLinus Torvalds 		return -EFAULT;
3101da177e4SLinus Torvalds 	sigdelsetmask(&newset, ~_BLOCKABLE);
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
31368fa383fSMartin Michlmayr 	current->saved_sigmask = current->blocked;
3141da177e4SLinus Torvalds 	current->blocked = newset;
3151da177e4SLinus Torvalds 	recalc_sigpending();
3161da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	current->state = TASK_INTERRUPTIBLE;
3191da177e4SLinus Torvalds 	schedule();
32068fa383fSMartin Michlmayr 	set_thread_flag(TIF_RESTORE_SIGMASK);
32168fa383fSMartin Michlmayr 	return -ERESTARTNOHAND;
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
324f90080a0SFranck Bui-Huu asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
3251da177e4SLinus Torvalds {
3269c6031ccSAtsushi Nemoto 	compat_sigset_t __user *uset;
32768fa383fSMartin Michlmayr 	sigset_t newset;
3281da177e4SLinus Torvalds 	size_t sigsetsize;
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	/* XXX Don't preclude handling different sized sigset_t's.  */
3311da177e4SLinus Torvalds 	sigsetsize = regs.regs[5];
3321da177e4SLinus Torvalds 	if (sigsetsize != sizeof(compat_sigset_t))
3331da177e4SLinus Torvalds 		return -EINVAL;
3341da177e4SLinus Torvalds 
3359c6031ccSAtsushi Nemoto 	uset = (compat_sigset_t __user *) regs.regs[4];
3361da177e4SLinus Torvalds 	if (get_sigset(&newset, uset))
3371da177e4SLinus Torvalds 		return -EFAULT;
3381da177e4SLinus Torvalds 	sigdelsetmask(&newset, ~_BLOCKABLE);
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
34168fa383fSMartin Michlmayr 	current->saved_sigmask = current->blocked;
3421da177e4SLinus Torvalds 	current->blocked = newset;
3431da177e4SLinus Torvalds 	recalc_sigpending();
3441da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	current->state = TASK_INTERRUPTIBLE;
3471da177e4SLinus Torvalds 	schedule();
34868fa383fSMartin Michlmayr 	set_thread_flag(TIF_RESTORE_SIGMASK);
34968fa383fSMartin Michlmayr 	return -ERESTARTNOHAND;
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds 
3529c6031ccSAtsushi Nemoto asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
3539c6031ccSAtsushi Nemoto                                struct sigaction32 __user *oact)
3541da177e4SLinus Torvalds {
3551da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
3561da177e4SLinus Torvalds 	int ret;
3571da177e4SLinus Torvalds 	int err = 0;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	if (act) {
3601da177e4SLinus Torvalds 		old_sigset_t mask;
36177c728c2SRalf Baechle 		s32 handler;
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
3641da177e4SLinus Torvalds 			return -EFAULT;
36577c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
3669bbf28a3SAtsushi Nemoto 		new_ka.sa.sa_handler = (void __user *)(s64)handler;
3671da177e4SLinus Torvalds 		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
3681da177e4SLinus Torvalds 		err |= __get_user(mask, &act->sa_mask.sig[0]);
3691da177e4SLinus Torvalds 		if (err)
3701da177e4SLinus Torvalds 			return -EFAULT;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
3731da177e4SLinus Torvalds 	}
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	if (!ret && oact) {
3781da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
3791da177e4SLinus Torvalds 			return -EFAULT;
3801da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
3811da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
3821da177e4SLinus Torvalds 		                  &oact->sa_handler);
3831da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
3841da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[1]);
3851da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[2]);
3861da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[3]);
3871da177e4SLinus Torvalds 		if (err)
3881da177e4SLinus Torvalds 			return -EFAULT;
3891da177e4SLinus Torvalds 	}
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	return ret;
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
3951da177e4SLinus Torvalds {
3969bbf28a3SAtsushi Nemoto 	const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
3979bbf28a3SAtsushi Nemoto 	stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
3981da177e4SLinus Torvalds 	unsigned long usp = regs.regs[29];
3991da177e4SLinus Torvalds 	stack_t kss, koss;
4001da177e4SLinus Torvalds 	int ret, err = 0;
4011da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
4021da177e4SLinus Torvalds 	s32 sp;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	if (uss) {
4051da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
4061da177e4SLinus Torvalds 			return -EFAULT;
4071da177e4SLinus Torvalds 		err |= __get_user(sp, &uss->ss_sp);
4089c6031ccSAtsushi Nemoto 		kss.ss_sp = (void __user *) (long) sp;
4091da177e4SLinus Torvalds 		err |= __get_user(kss.ss_size, &uss->ss_size);
4101da177e4SLinus Torvalds 		err |= __get_user(kss.ss_flags, &uss->ss_flags);
4111da177e4SLinus Torvalds 		if (err)
4121da177e4SLinus Torvalds 			return -EFAULT;
4131da177e4SLinus Torvalds 	}
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	set_fs(KERNEL_DS);
4169bbf28a3SAtsushi Nemoto 	ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
4179bbf28a3SAtsushi Nemoto 			     uoss ? (stack_t __user *)&koss : NULL, usp);
4181da177e4SLinus Torvalds 	set_fs(old_fs);
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	if (!ret && uoss) {
4211da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
4221da177e4SLinus Torvalds 			return -EFAULT;
4239c6031ccSAtsushi Nemoto 		sp = (int) (unsigned long) koss.ss_sp;
4241da177e4SLinus Torvalds 		err |= __put_user(sp, &uoss->ss_sp);
4251da177e4SLinus Torvalds 		err |= __put_user(koss.ss_size, &uoss->ss_size);
4261da177e4SLinus Torvalds 		err |= __put_user(koss.ss_flags, &uoss->ss_flags);
4271da177e4SLinus Torvalds 		if (err)
4281da177e4SLinus Torvalds 			return -EFAULT;
4291da177e4SLinus Torvalds 	}
4301da177e4SLinus Torvalds 	return ret;
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds 
4339bbf28a3SAtsushi Nemoto int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds 	int err;
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
4381da177e4SLinus Torvalds 		return -EFAULT;
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	/* If you change siginfo_t structure, please be sure
4411da177e4SLinus Torvalds 	   this code is fixed accordingly.
4421da177e4SLinus Torvalds 	   It should never copy any pad contained in the structure
4431da177e4SLinus Torvalds 	   to avoid security leaks, but must copy the generic
4441da177e4SLinus Torvalds 	   3 ints plus the relevant union member.
4451da177e4SLinus Torvalds 	   This routine must convert siginfo from 64bit to 32bit as well
4461da177e4SLinus Torvalds 	   at the same time.  */
4471da177e4SLinus Torvalds 	err = __put_user(from->si_signo, &to->si_signo);
4481da177e4SLinus Torvalds 	err |= __put_user(from->si_errno, &to->si_errno);
4491da177e4SLinus Torvalds 	err |= __put_user((short)from->si_code, &to->si_code);
4501da177e4SLinus Torvalds 	if (from->si_code < 0)
4511da177e4SLinus Torvalds 		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
4521da177e4SLinus Torvalds 	else {
4531da177e4SLinus Torvalds 		switch (from->si_code >> 16) {
454a982099cSRalf Baechle 		case __SI_TIMER >> 16:
455a982099cSRalf Baechle 			err |= __put_user(from->si_tid, &to->si_tid);
456a982099cSRalf Baechle 			err |= __put_user(from->si_overrun, &to->si_overrun);
457a982099cSRalf Baechle 			err |= __put_user(from->si_int, &to->si_int);
458a982099cSRalf Baechle 			break;
4591da177e4SLinus Torvalds 		case __SI_CHLD >> 16:
4601da177e4SLinus Torvalds 			err |= __put_user(from->si_utime, &to->si_utime);
4611da177e4SLinus Torvalds 			err |= __put_user(from->si_stime, &to->si_stime);
4621da177e4SLinus Torvalds 			err |= __put_user(from->si_status, &to->si_status);
4631da177e4SLinus Torvalds 		default:
4641da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
4651da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
4661da177e4SLinus Torvalds 			break;
4671da177e4SLinus Torvalds 		case __SI_FAULT >> 16:
4685665a0acSAtsushi Nemoto 			err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
4691da177e4SLinus Torvalds 			break;
4701da177e4SLinus Torvalds 		case __SI_POLL >> 16:
4711da177e4SLinus Torvalds 			err |= __put_user(from->si_band, &to->si_band);
4721da177e4SLinus Torvalds 			err |= __put_user(from->si_fd, &to->si_fd);
4731da177e4SLinus Torvalds 			break;
4741da177e4SLinus Torvalds 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
4751da177e4SLinus Torvalds 		case __SI_MESGQ >> 16:
4761da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
4771da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
4781da177e4SLinus Torvalds 			err |= __put_user(from->si_int, &to->si_int);
4791da177e4SLinus Torvalds 			break;
4801da177e4SLinus Torvalds 		}
4811da177e4SLinus Torvalds 	}
4821da177e4SLinus Torvalds 	return err;
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds 
485*5d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
486*5d9a76cdSThomas Bogendoerfer {
487*5d9a76cdSThomas Bogendoerfer 	memset(to, 0, sizeof *to);
488*5d9a76cdSThomas Bogendoerfer 
489*5d9a76cdSThomas Bogendoerfer 	if (copy_from_user(to, from, 3*sizeof(int)) ||
490*5d9a76cdSThomas Bogendoerfer 	    copy_from_user(to->_sifields._pad,
491*5d9a76cdSThomas Bogendoerfer 			   from->_sifields._pad, SI_PAD_SIZE32))
492*5d9a76cdSThomas Bogendoerfer 		return -EFAULT;
493*5d9a76cdSThomas Bogendoerfer 
494*5d9a76cdSThomas Bogendoerfer 	return 0;
495*5d9a76cdSThomas Bogendoerfer }
496*5d9a76cdSThomas Bogendoerfer 
497f90080a0SFranck Bui-Huu asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
4981da177e4SLinus Torvalds {
499dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
5001da177e4SLinus Torvalds 	sigset_t blocked;
501c6a2f467SAtsushi Nemoto 	int sig;
5021da177e4SLinus Torvalds 
503dd02f06aSRalf Baechle 	frame = (struct sigframe32 __user *) regs.regs[29];
5041da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
5051da177e4SLinus Torvalds 		goto badframe;
506431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
5071da177e4SLinus Torvalds 		goto badframe;
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds 	sigdelsetmask(&blocked, ~_BLOCKABLE);
5101da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
5111da177e4SLinus Torvalds 	current->blocked = blocked;
5121da177e4SLinus Torvalds 	recalc_sigpending();
5131da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
5141da177e4SLinus Torvalds 
515c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->sf_sc);
516c6a2f467SAtsushi Nemoto 	if (sig < 0)
5171da177e4SLinus Torvalds 		goto badframe;
518c6a2f467SAtsushi Nemoto 	else if (sig)
519c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	/*
5221da177e4SLinus Torvalds 	 * Don't let your children do this ...
5231da177e4SLinus Torvalds 	 */
5241da177e4SLinus Torvalds 	__asm__ __volatile__(
5251da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
5261da177e4SLinus Torvalds 		"j\tsyscall_exit"
5271da177e4SLinus Torvalds 		:/* no outputs */
5281da177e4SLinus Torvalds 		:"r" (&regs));
5291da177e4SLinus Torvalds 	/* Unreached */
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds badframe:
5321da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
5331da177e4SLinus Torvalds }
5341da177e4SLinus Torvalds 
535f90080a0SFranck Bui-Huu asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
5361da177e4SLinus Torvalds {
5379bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
5381fcf1cc7SRalf Baechle 	mm_segment_t old_fs;
5391da177e4SLinus Torvalds 	sigset_t set;
5401da177e4SLinus Torvalds 	stack_t st;
5411da177e4SLinus Torvalds 	s32 sp;
542c6a2f467SAtsushi Nemoto 	int sig;
5431da177e4SLinus Torvalds 
5449bbf28a3SAtsushi Nemoto 	frame = (struct rt_sigframe32 __user *) regs.regs[29];
5451da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
5461da177e4SLinus Torvalds 		goto badframe;
547431dc804SRalf Baechle 	if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
5481da177e4SLinus Torvalds 		goto badframe;
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	sigdelsetmask(&set, ~_BLOCKABLE);
5511da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
5521da177e4SLinus Torvalds 	current->blocked = set;
5531da177e4SLinus Torvalds 	recalc_sigpending();
5541da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
5551da177e4SLinus Torvalds 
556c6a2f467SAtsushi Nemoto 	sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
557c6a2f467SAtsushi Nemoto 	if (sig < 0)
5581da177e4SLinus Torvalds 		goto badframe;
559c6a2f467SAtsushi Nemoto 	else if (sig)
560c6a2f467SAtsushi Nemoto 		force_sig(sig, current);
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	/* The ucontext contains a stack32_t, so we must convert!  */
5631da177e4SLinus Torvalds 	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
5641da177e4SLinus Torvalds 		goto badframe;
5659c6031ccSAtsushi Nemoto 	st.ss_sp = (void __user *)(long) sp;
5661da177e4SLinus Torvalds 	if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
5671da177e4SLinus Torvalds 		goto badframe;
5681da177e4SLinus Torvalds 	if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
5691da177e4SLinus Torvalds 		goto badframe;
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 	/* It is more difficult to avoid calling this function than to
5721da177e4SLinus Torvalds 	   call it and ignore errors.  */
5731fcf1cc7SRalf Baechle 	old_fs = get_fs();
5741fcf1cc7SRalf Baechle 	set_fs(KERNEL_DS);
5759bbf28a3SAtsushi Nemoto 	do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
5761fcf1cc7SRalf Baechle 	set_fs(old_fs);
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds 	/*
5791da177e4SLinus Torvalds 	 * Don't let your children do this ...
5801da177e4SLinus Torvalds 	 */
5811da177e4SLinus Torvalds 	__asm__ __volatile__(
5821da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
5831da177e4SLinus Torvalds 		"j\tsyscall_exit"
5841da177e4SLinus Torvalds 		:/* no outputs */
5851da177e4SLinus Torvalds 		:"r" (&regs));
5861da177e4SLinus Torvalds 	/* Unreached */
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds badframe:
5891da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds 
592151fd6acSRalf Baechle static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
5931da177e4SLinus Torvalds 	int signr, sigset_t *set)
5941da177e4SLinus Torvalds {
595dd02f06aSRalf Baechle 	struct sigframe32 __user *frame;
5961da177e4SLinus Torvalds 	int err = 0;
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
5991da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
6001da177e4SLinus Torvalds 		goto give_sigsegv;
6011da177e4SLinus Torvalds 
60236a1f2c2SFranck Bui-Huu 	err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->sf_sc);
605431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
606431dc804SRalf Baechle 
6071da177e4SLinus Torvalds 	if (err)
6081da177e4SLinus Torvalds 		goto give_sigsegv;
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	/*
6111da177e4SLinus Torvalds 	 * Arguments to signal handler:
6121da177e4SLinus Torvalds 	 *
6131da177e4SLinus Torvalds 	 *   a0 = signal number
6141da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
6151da177e4SLinus Torvalds 	 *   a2 = pointer to struct sigcontext
6161da177e4SLinus Torvalds 	 *
6171da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to the
6181da177e4SLinus Torvalds 	 * struct sigframe.
6191da177e4SLinus Torvalds 	 */
6201da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
6211da177e4SLinus Torvalds 	regs->regs[ 5] = 0;
6221da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
6231da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
6241da177e4SLinus Torvalds 	regs->regs[31] = (unsigned long) frame->sf_code;
6251da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
6261da177e4SLinus Torvalds 
627722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
6281da177e4SLinus Torvalds 	       current->comm, current->pid,
629722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
630722bb63dSFranck Bui-Huu 
6317b3e2fc8SRalf Baechle 	return 0;
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds give_sigsegv:
6341da177e4SLinus Torvalds 	force_sigsegv(signr, current);
6357b3e2fc8SRalf Baechle 	return -EFAULT;
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds 
638151fd6acSRalf Baechle static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
63916cd3951SAtsushi Nemoto 	int signr, sigset_t *set, siginfo_t *info)
6401da177e4SLinus Torvalds {
6419bbf28a3SAtsushi Nemoto 	struct rt_sigframe32 __user *frame;
6421da177e4SLinus Torvalds 	int err = 0;
6431da177e4SLinus Torvalds 	s32 sp;
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
6461da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
6471da177e4SLinus Torvalds 		goto give_sigsegv;
6481da177e4SLinus Torvalds 
64936a1f2c2SFranck Bui-Huu 	err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
6521da177e4SLinus Torvalds 	err |= copy_siginfo_to_user32(&frame->rs_info, info);
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds 	/* Create the ucontext.  */
6551da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_flags);
6561da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_link);
6571da177e4SLinus Torvalds 	sp = (int) (long) current->sas_ss_sp;
6581da177e4SLinus Torvalds 	err |= __put_user(sp,
6591da177e4SLinus Torvalds 	                  &frame->rs_uc.uc_stack.ss_sp);
6601da177e4SLinus Torvalds 	err |= __put_user(sas_ss_flags(regs->regs[29]),
6611da177e4SLinus Torvalds 	                  &frame->rs_uc.uc_stack.ss_flags);
6621da177e4SLinus Torvalds 	err |= __put_user(current->sas_ss_size,
6631da177e4SLinus Torvalds 	                  &frame->rs_uc.uc_stack.ss_size);
6641da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
665431dc804SRalf Baechle 	err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds 	if (err)
6681da177e4SLinus Torvalds 		goto give_sigsegv;
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	/*
6711da177e4SLinus Torvalds 	 * Arguments to signal handler:
6721da177e4SLinus Torvalds 	 *
6731da177e4SLinus Torvalds 	 *   a0 = signal number
6741da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
6751da177e4SLinus Torvalds 	 *   a2 = pointer to ucontext
6761da177e4SLinus Torvalds 	 *
6771da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to
6781da177e4SLinus Torvalds 	 * the struct rt_sigframe32.
6791da177e4SLinus Torvalds 	 */
6801da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
6811da177e4SLinus Torvalds 	regs->regs[ 5] = (unsigned long) &frame->rs_info;
6821da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
6831da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
6841da177e4SLinus Torvalds 	regs->regs[31] = (unsigned long) frame->rs_code;
6851da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
6861da177e4SLinus Torvalds 
687722bb63dSFranck Bui-Huu 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
6881da177e4SLinus Torvalds 	       current->comm, current->pid,
689722bb63dSFranck Bui-Huu 	       frame, regs->cp0_epc, regs->regs[31]);
690722bb63dSFranck Bui-Huu 
6917b3e2fc8SRalf Baechle 	return 0;
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds give_sigsegv:
6941da177e4SLinus Torvalds 	force_sigsegv(signr, current);
6957b3e2fc8SRalf Baechle 	return -EFAULT;
6961da177e4SLinus Torvalds }
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds /*
699151fd6acSRalf Baechle  * o32 compatibility on 64-bit kernels, without DSP ASE
7001da177e4SLinus Torvalds  */
701151fd6acSRalf Baechle struct mips_abi mips_abi_32 = {
702151fd6acSRalf Baechle 	.setup_frame	= setup_frame_32,
703151fd6acSRalf Baechle 	.setup_rt_frame	= setup_rt_frame_32,
704151fd6acSRalf Baechle 	.restart	= __NR_O32_restart_syscall
705151fd6acSRalf Baechle };
7061da177e4SLinus Torvalds 
7079c6031ccSAtsushi Nemoto asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
7089bbf28a3SAtsushi Nemoto 				  struct sigaction32 __user *oact,
7091da177e4SLinus Torvalds 				  unsigned int sigsetsize)
7101da177e4SLinus Torvalds {
7111da177e4SLinus Torvalds 	struct k_sigaction new_sa, old_sa;
7121da177e4SLinus Torvalds 	int ret = -EINVAL;
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	/* XXX: Don't preclude handling different sized sigset_t's.  */
7151da177e4SLinus Torvalds 	if (sigsetsize != sizeof(sigset_t))
7161da177e4SLinus Torvalds 		goto out;
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	if (act) {
71977c728c2SRalf Baechle 		s32 handler;
7201da177e4SLinus Torvalds 		int err = 0;
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
7231da177e4SLinus Torvalds 			return -EFAULT;
72477c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
7259bbf28a3SAtsushi Nemoto 		new_sa.sa.sa_handler = (void __user *)(s64)handler;
7261da177e4SLinus Torvalds 		err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
7271da177e4SLinus Torvalds 		err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
7281da177e4SLinus Torvalds 		if (err)
7291da177e4SLinus Torvalds 			return -EFAULT;
7301da177e4SLinus Torvalds 	}
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	if (!ret && oact) {
7351da177e4SLinus Torvalds 		int err = 0;
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
7381da177e4SLinus Torvalds 			return -EFAULT;
7391da177e4SLinus Torvalds 
7401da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
7411da177e4SLinus Torvalds 		                   &oact->sa_handler);
7421da177e4SLinus Torvalds 		err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
7431da177e4SLinus Torvalds 		err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
7441da177e4SLinus Torvalds 		if (err)
7451da177e4SLinus Torvalds 			return -EFAULT;
7461da177e4SLinus Torvalds 	}
7471da177e4SLinus Torvalds out:
7481da177e4SLinus Torvalds 	return ret;
7491da177e4SLinus Torvalds }
7501da177e4SLinus Torvalds 
7519c6031ccSAtsushi Nemoto asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
7529bbf28a3SAtsushi Nemoto 	compat_sigset_t __user *oset, unsigned int sigsetsize)
7531da177e4SLinus Torvalds {
7541da177e4SLinus Torvalds 	sigset_t old_set, new_set;
7551da177e4SLinus Torvalds 	int ret;
7561da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 	if (set && get_sigset(&new_set, set))
7591da177e4SLinus Torvalds 		return -EFAULT;
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds 	set_fs(KERNEL_DS);
7629bbf28a3SAtsushi Nemoto 	ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
7639bbf28a3SAtsushi Nemoto 				 oset ? (sigset_t __user *)&old_set : NULL,
7649bbf28a3SAtsushi Nemoto 				 sigsetsize);
7651da177e4SLinus Torvalds 	set_fs(old_fs);
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 	if (!ret && oset && put_sigset(&old_set, oset))
7681da177e4SLinus Torvalds 		return -EFAULT;
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 	return ret;
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds 
7739bbf28a3SAtsushi Nemoto asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
7741da177e4SLinus Torvalds 	unsigned int sigsetsize)
7751da177e4SLinus Torvalds {
7761da177e4SLinus Torvalds 	int ret;
7771da177e4SLinus Torvalds 	sigset_t set;
7781da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 	set_fs(KERNEL_DS);
7819bbf28a3SAtsushi Nemoto 	ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
7821da177e4SLinus Torvalds 	set_fs(old_fs);
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds 	if (!ret && put_sigset(&set, uset))
7851da177e4SLinus Torvalds 		return -EFAULT;
7861da177e4SLinus Torvalds 
7871da177e4SLinus Torvalds 	return ret;
7881da177e4SLinus Torvalds }
7891da177e4SLinus Torvalds 
7909bbf28a3SAtsushi Nemoto asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
7911da177e4SLinus Torvalds {
7921da177e4SLinus Torvalds 	siginfo_t info;
7931da177e4SLinus Torvalds 	int ret;
7941da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 	if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
7971da177e4SLinus Torvalds 	    copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
7981da177e4SLinus Torvalds 		return -EFAULT;
7991da177e4SLinus Torvalds 	set_fs(KERNEL_DS);
8009bbf28a3SAtsushi Nemoto 	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
8011da177e4SLinus Torvalds 	set_fs(old_fs);
8021da177e4SLinus Torvalds 	return ret;
8031da177e4SLinus Torvalds }
80454f2da75SRalf Baechle 
80554f2da75SRalf Baechle asmlinkage long
80654f2da75SRalf Baechle sys32_waitid(int which, compat_pid_t pid,
80754f2da75SRalf Baechle 	     compat_siginfo_t __user *uinfo, int options,
80854f2da75SRalf Baechle 	     struct compat_rusage __user *uru)
80954f2da75SRalf Baechle {
81054f2da75SRalf Baechle 	siginfo_t info;
81154f2da75SRalf Baechle 	struct rusage ru;
81254f2da75SRalf Baechle 	long ret;
81354f2da75SRalf Baechle 	mm_segment_t old_fs = get_fs();
81454f2da75SRalf Baechle 
81554f2da75SRalf Baechle 	info.si_signo = 0;
81654f2da75SRalf Baechle 	set_fs(KERNEL_DS);
81754f2da75SRalf Baechle 	ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
81854f2da75SRalf Baechle 			 uru ? (struct rusage __user *) &ru : NULL);
81954f2da75SRalf Baechle 	set_fs(old_fs);
82054f2da75SRalf Baechle 
82154f2da75SRalf Baechle 	if (ret < 0 || info.si_signo == 0)
82254f2da75SRalf Baechle 		return ret;
82354f2da75SRalf Baechle 
82454f2da75SRalf Baechle 	if (uru && (ret = put_compat_rusage(&ru, uru)))
82554f2da75SRalf Baechle 		return ret;
82654f2da75SRalf Baechle 
82754f2da75SRalf Baechle 	BUG_ON(info.si_code & __SI_MASK);
82854f2da75SRalf Baechle 	info.si_code |= __SI_CHLD;
82954f2da75SRalf Baechle 	return copy_siginfo_to_user32(uinfo, &info);
83054f2da75SRalf Baechle }
831