xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
3*1da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
4*1da177e4SLinus Torvalds  * for more details.
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  * Copyright (C) 1991, 1992  Linus Torvalds
7*1da177e4SLinus Torvalds  * Copyright (C) 1994 - 2000  Ralf Baechle
8*1da177e4SLinus Torvalds  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9*1da177e4SLinus Torvalds  */
10*1da177e4SLinus Torvalds #include <linux/sched.h>
11*1da177e4SLinus Torvalds #include <linux/mm.h>
12*1da177e4SLinus Torvalds #include <linux/smp.h>
13*1da177e4SLinus Torvalds #include <linux/smp_lock.h>
14*1da177e4SLinus Torvalds #include <linux/kernel.h>
15*1da177e4SLinus Torvalds #include <linux/signal.h>
16*1da177e4SLinus Torvalds #include <linux/syscalls.h>
17*1da177e4SLinus Torvalds #include <linux/errno.h>
18*1da177e4SLinus Torvalds #include <linux/wait.h>
19*1da177e4SLinus Torvalds #include <linux/ptrace.h>
20*1da177e4SLinus Torvalds #include <linux/compat.h>
21*1da177e4SLinus Torvalds #include <linux/suspend.h>
22*1da177e4SLinus Torvalds #include <linux/compiler.h>
23*1da177e4SLinus Torvalds 
24*1da177e4SLinus Torvalds #include <asm/asm.h>
25*1da177e4SLinus Torvalds #include <linux/bitops.h>
26*1da177e4SLinus Torvalds #include <asm/cacheflush.h>
27*1da177e4SLinus Torvalds #include <asm/sim.h>
28*1da177e4SLinus Torvalds #include <asm/uaccess.h>
29*1da177e4SLinus Torvalds #include <asm/ucontext.h>
30*1da177e4SLinus Torvalds #include <asm/system.h>
31*1da177e4SLinus Torvalds #include <asm/fpu.h>
32*1da177e4SLinus Torvalds 
33*1da177e4SLinus Torvalds #define SI_PAD_SIZE32   ((SI_MAX_SIZE/sizeof(int)) - 3)
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds typedef struct compat_siginfo {
36*1da177e4SLinus Torvalds 	int si_signo;
37*1da177e4SLinus Torvalds 	int si_code;
38*1da177e4SLinus Torvalds 	int si_errno;
39*1da177e4SLinus Torvalds 
40*1da177e4SLinus Torvalds 	union {
41*1da177e4SLinus Torvalds 		int _pad[SI_PAD_SIZE32];
42*1da177e4SLinus Torvalds 
43*1da177e4SLinus Torvalds 		/* kill() */
44*1da177e4SLinus Torvalds 		struct {
45*1da177e4SLinus Torvalds 			compat_pid_t _pid;	/* sender's pid */
46*1da177e4SLinus Torvalds 			compat_uid_t _uid;	/* sender's uid */
47*1da177e4SLinus Torvalds 		} _kill;
48*1da177e4SLinus Torvalds 
49*1da177e4SLinus Torvalds 		/* SIGCHLD */
50*1da177e4SLinus Torvalds 		struct {
51*1da177e4SLinus Torvalds 			compat_pid_t _pid;	/* which child */
52*1da177e4SLinus Torvalds 			compat_uid_t _uid;	/* sender's uid */
53*1da177e4SLinus Torvalds 			int _status;		/* exit code */
54*1da177e4SLinus Torvalds 			compat_clock_t _utime;
55*1da177e4SLinus Torvalds 			compat_clock_t _stime;
56*1da177e4SLinus Torvalds 		} _sigchld;
57*1da177e4SLinus Torvalds 
58*1da177e4SLinus Torvalds 		/* IRIX SIGCHLD */
59*1da177e4SLinus Torvalds 		struct {
60*1da177e4SLinus Torvalds 			compat_pid_t _pid;	/* which child */
61*1da177e4SLinus Torvalds 			compat_clock_t _utime;
62*1da177e4SLinus Torvalds 			int _status;		/* exit code */
63*1da177e4SLinus Torvalds 			compat_clock_t _stime;
64*1da177e4SLinus Torvalds 		} _irix_sigchld;
65*1da177e4SLinus Torvalds 
66*1da177e4SLinus Torvalds 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
67*1da177e4SLinus Torvalds 		struct {
68*1da177e4SLinus Torvalds 			s32 _addr; /* faulting insn/memory ref. */
69*1da177e4SLinus Torvalds 		} _sigfault;
70*1da177e4SLinus Torvalds 
71*1da177e4SLinus Torvalds 		/* SIGPOLL, SIGXFSZ (To do ...)  */
72*1da177e4SLinus Torvalds 		struct {
73*1da177e4SLinus Torvalds 			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
74*1da177e4SLinus Torvalds 			int _fd;
75*1da177e4SLinus Torvalds 		} _sigpoll;
76*1da177e4SLinus Torvalds 
77*1da177e4SLinus Torvalds 		/* POSIX.1b timers */
78*1da177e4SLinus Torvalds 		struct {
79*1da177e4SLinus Torvalds 			unsigned int _timer1;
80*1da177e4SLinus Torvalds 			unsigned int _timer2;
81*1da177e4SLinus Torvalds 		} _timer;
82*1da177e4SLinus Torvalds 
83*1da177e4SLinus Torvalds 		/* POSIX.1b signals */
84*1da177e4SLinus Torvalds 		struct {
85*1da177e4SLinus Torvalds 			compat_pid_t _pid;	/* sender's pid */
86*1da177e4SLinus Torvalds 			compat_uid_t _uid;	/* sender's uid */
87*1da177e4SLinus Torvalds 			compat_sigval_t _sigval;
88*1da177e4SLinus Torvalds 		} _rt;
89*1da177e4SLinus Torvalds 
90*1da177e4SLinus Torvalds 	} _sifields;
91*1da177e4SLinus Torvalds } compat_siginfo_t;
92*1da177e4SLinus Torvalds 
93*1da177e4SLinus Torvalds /*
94*1da177e4SLinus Torvalds  * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
95*1da177e4SLinus Torvalds  */
96*1da177e4SLinus Torvalds #define __NR_O32_sigreturn		4119
97*1da177e4SLinus Torvalds #define __NR_O32_rt_sigreturn		4193
98*1da177e4SLinus Torvalds #define __NR_O32_restart_syscall	4253
99*1da177e4SLinus Torvalds 
100*1da177e4SLinus Torvalds #define DEBUG_SIG 0
101*1da177e4SLinus Torvalds 
102*1da177e4SLinus Torvalds #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
103*1da177e4SLinus Torvalds 
104*1da177e4SLinus Torvalds extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
105*1da177e4SLinus Torvalds 
106*1da177e4SLinus Torvalds /* 32-bit compatibility types */
107*1da177e4SLinus Torvalds 
108*1da177e4SLinus Torvalds #define _NSIG_BPW32	32
109*1da177e4SLinus Torvalds #define _NSIG_WORDS32	(_NSIG / _NSIG_BPW32)
110*1da177e4SLinus Torvalds 
111*1da177e4SLinus Torvalds typedef struct {
112*1da177e4SLinus Torvalds 	unsigned int sig[_NSIG_WORDS32];
113*1da177e4SLinus Torvalds } sigset_t32;
114*1da177e4SLinus Torvalds 
115*1da177e4SLinus Torvalds typedef unsigned int __sighandler32_t;
116*1da177e4SLinus Torvalds typedef void (*vfptr_t)(void);
117*1da177e4SLinus Torvalds 
118*1da177e4SLinus Torvalds struct sigaction32 {
119*1da177e4SLinus Torvalds 	unsigned int		sa_flags;
120*1da177e4SLinus Torvalds 	__sighandler32_t	sa_handler;
121*1da177e4SLinus Torvalds 	compat_sigset_t		sa_mask;
122*1da177e4SLinus Torvalds };
123*1da177e4SLinus Torvalds 
124*1da177e4SLinus Torvalds /* IRIX compatible stack_t  */
125*1da177e4SLinus Torvalds typedef struct sigaltstack32 {
126*1da177e4SLinus Torvalds 	s32 ss_sp;
127*1da177e4SLinus Torvalds 	compat_size_t ss_size;
128*1da177e4SLinus Torvalds 	int ss_flags;
129*1da177e4SLinus Torvalds } stack32_t;
130*1da177e4SLinus Torvalds 
131*1da177e4SLinus Torvalds struct ucontext32 {
132*1da177e4SLinus Torvalds 	u32                 uc_flags;
133*1da177e4SLinus Torvalds 	s32                 uc_link;
134*1da177e4SLinus Torvalds 	stack32_t           uc_stack;
135*1da177e4SLinus Torvalds 	struct sigcontext32 uc_mcontext;
136*1da177e4SLinus Torvalds 	sigset_t32          uc_sigmask;   /* mask last for extensibility */
137*1da177e4SLinus Torvalds };
138*1da177e4SLinus Torvalds 
139*1da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void);
140*1da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void);
141*1da177e4SLinus Torvalds 
142*1da177e4SLinus Torvalds static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t *ubuf)
143*1da177e4SLinus Torvalds {
144*1da177e4SLinus Torvalds 	int err = 0;
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
147*1da177e4SLinus Torvalds 		return -EFAULT;
148*1da177e4SLinus Torvalds 
149*1da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
150*1da177e4SLinus Torvalds 	default:
151*1da177e4SLinus Torvalds 		__put_sigset_unknown_nsig();
152*1da177e4SLinus Torvalds 	case 2:
153*1da177e4SLinus Torvalds 		err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
154*1da177e4SLinus Torvalds 		err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
155*1da177e4SLinus Torvalds 	case 1:
156*1da177e4SLinus Torvalds 		err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
157*1da177e4SLinus Torvalds 		err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
158*1da177e4SLinus Torvalds 	}
159*1da177e4SLinus Torvalds 
160*1da177e4SLinus Torvalds 	return err;
161*1da177e4SLinus Torvalds }
162*1da177e4SLinus Torvalds 
163*1da177e4SLinus Torvalds static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf)
164*1da177e4SLinus Torvalds {
165*1da177e4SLinus Torvalds 	int err = 0;
166*1da177e4SLinus Torvalds 	unsigned long sig[4];
167*1da177e4SLinus Torvalds 
168*1da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
169*1da177e4SLinus Torvalds 		return -EFAULT;
170*1da177e4SLinus Torvalds 
171*1da177e4SLinus Torvalds 	switch (_NSIG_WORDS) {
172*1da177e4SLinus Torvalds 	default:
173*1da177e4SLinus Torvalds 		__get_sigset_unknown_nsig();
174*1da177e4SLinus Torvalds 	case 2:
175*1da177e4SLinus Torvalds 		err |= __get_user (sig[3], &ubuf->sig[3]);
176*1da177e4SLinus Torvalds 		err |= __get_user (sig[2], &ubuf->sig[2]);
177*1da177e4SLinus Torvalds 		kbuf->sig[1] = sig[2] | (sig[3] << 32);
178*1da177e4SLinus Torvalds 	case 1:
179*1da177e4SLinus Torvalds 		err |= __get_user (sig[1], &ubuf->sig[1]);
180*1da177e4SLinus Torvalds 		err |= __get_user (sig[0], &ubuf->sig[0]);
181*1da177e4SLinus Torvalds 		kbuf->sig[0] = sig[0] | (sig[1] << 32);
182*1da177e4SLinus Torvalds 	}
183*1da177e4SLinus Torvalds 
184*1da177e4SLinus Torvalds 	return err;
185*1da177e4SLinus Torvalds }
186*1da177e4SLinus Torvalds 
187*1da177e4SLinus Torvalds /*
188*1da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
189*1da177e4SLinus Torvalds  */
190*1da177e4SLinus Torvalds 
191*1da177e4SLinus Torvalds save_static_function(sys32_sigsuspend);
192*1da177e4SLinus Torvalds __attribute_used__ noinline static int
193*1da177e4SLinus Torvalds _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
194*1da177e4SLinus Torvalds {
195*1da177e4SLinus Torvalds 	compat_sigset_t *uset;
196*1da177e4SLinus Torvalds 	sigset_t newset, saveset;
197*1da177e4SLinus Torvalds 
198*1da177e4SLinus Torvalds 	uset = (compat_sigset_t *) regs.regs[4];
199*1da177e4SLinus Torvalds 	if (get_sigset(&newset, uset))
200*1da177e4SLinus Torvalds 		return -EFAULT;
201*1da177e4SLinus Torvalds 	sigdelsetmask(&newset, ~_BLOCKABLE);
202*1da177e4SLinus Torvalds 
203*1da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
204*1da177e4SLinus Torvalds 	saveset = current->blocked;
205*1da177e4SLinus Torvalds 	current->blocked = newset;
206*1da177e4SLinus Torvalds 	recalc_sigpending();
207*1da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
208*1da177e4SLinus Torvalds 
209*1da177e4SLinus Torvalds 	regs.regs[2] = EINTR;
210*1da177e4SLinus Torvalds 	regs.regs[7] = 1;
211*1da177e4SLinus Torvalds 	while (1) {
212*1da177e4SLinus Torvalds 		current->state = TASK_INTERRUPTIBLE;
213*1da177e4SLinus Torvalds 		schedule();
214*1da177e4SLinus Torvalds 		if (do_signal32(&saveset, &regs))
215*1da177e4SLinus Torvalds 			return -EINTR;
216*1da177e4SLinus Torvalds 	}
217*1da177e4SLinus Torvalds }
218*1da177e4SLinus Torvalds 
219*1da177e4SLinus Torvalds save_static_function(sys32_rt_sigsuspend);
220*1da177e4SLinus Torvalds __attribute_used__ noinline static int
221*1da177e4SLinus Torvalds _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
222*1da177e4SLinus Torvalds {
223*1da177e4SLinus Torvalds 	compat_sigset_t *uset;
224*1da177e4SLinus Torvalds 	sigset_t newset, saveset;
225*1da177e4SLinus Torvalds         size_t sigsetsize;
226*1da177e4SLinus Torvalds 
227*1da177e4SLinus Torvalds 	/* XXX Don't preclude handling different sized sigset_t's.  */
228*1da177e4SLinus Torvalds 	sigsetsize = regs.regs[5];
229*1da177e4SLinus Torvalds 	if (sigsetsize != sizeof(compat_sigset_t))
230*1da177e4SLinus Torvalds 		return -EINVAL;
231*1da177e4SLinus Torvalds 
232*1da177e4SLinus Torvalds 	uset = (compat_sigset_t *) regs.regs[4];
233*1da177e4SLinus Torvalds 	if (get_sigset(&newset, uset))
234*1da177e4SLinus Torvalds 		return -EFAULT;
235*1da177e4SLinus Torvalds 	sigdelsetmask(&newset, ~_BLOCKABLE);
236*1da177e4SLinus Torvalds 
237*1da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
238*1da177e4SLinus Torvalds 	saveset = current->blocked;
239*1da177e4SLinus Torvalds 	current->blocked = newset;
240*1da177e4SLinus Torvalds         recalc_sigpending();
241*1da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
242*1da177e4SLinus Torvalds 
243*1da177e4SLinus Torvalds 	regs.regs[2] = EINTR;
244*1da177e4SLinus Torvalds 	regs.regs[7] = 1;
245*1da177e4SLinus Torvalds 	while (1) {
246*1da177e4SLinus Torvalds 		current->state = TASK_INTERRUPTIBLE;
247*1da177e4SLinus Torvalds 		schedule();
248*1da177e4SLinus Torvalds 		if (do_signal32(&saveset, &regs))
249*1da177e4SLinus Torvalds 			return -EINTR;
250*1da177e4SLinus Torvalds 	}
251*1da177e4SLinus Torvalds }
252*1da177e4SLinus Torvalds 
253*1da177e4SLinus Torvalds asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act,
254*1da177e4SLinus Torvalds                                struct sigaction32 *oact)
255*1da177e4SLinus Torvalds {
256*1da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
257*1da177e4SLinus Torvalds 	int ret;
258*1da177e4SLinus Torvalds 	int err = 0;
259*1da177e4SLinus Torvalds 
260*1da177e4SLinus Torvalds 	if (act) {
261*1da177e4SLinus Torvalds 		old_sigset_t mask;
262*1da177e4SLinus Torvalds 
263*1da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
264*1da177e4SLinus Torvalds 			return -EFAULT;
265*1da177e4SLinus Torvalds 		err |= __get_user((u32)(u64)new_ka.sa.sa_handler,
266*1da177e4SLinus Torvalds 		                  &act->sa_handler);
267*1da177e4SLinus Torvalds 		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
268*1da177e4SLinus Torvalds 		err |= __get_user(mask, &act->sa_mask.sig[0]);
269*1da177e4SLinus Torvalds 		if (err)
270*1da177e4SLinus Torvalds 			return -EFAULT;
271*1da177e4SLinus Torvalds 
272*1da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
273*1da177e4SLinus Torvalds 	}
274*1da177e4SLinus Torvalds 
275*1da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
276*1da177e4SLinus Torvalds 
277*1da177e4SLinus Torvalds 	if (!ret && oact) {
278*1da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
279*1da177e4SLinus Torvalds                         return -EFAULT;
280*1da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
281*1da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
282*1da177e4SLinus Torvalds 		                  &oact->sa_handler);
283*1da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
284*1da177e4SLinus Torvalds                 err |= __put_user(0, &oact->sa_mask.sig[1]);
285*1da177e4SLinus Torvalds                 err |= __put_user(0, &oact->sa_mask.sig[2]);
286*1da177e4SLinus Torvalds                 err |= __put_user(0, &oact->sa_mask.sig[3]);
287*1da177e4SLinus Torvalds                 if (err)
288*1da177e4SLinus Torvalds 			return -EFAULT;
289*1da177e4SLinus Torvalds 	}
290*1da177e4SLinus Torvalds 
291*1da177e4SLinus Torvalds 	return ret;
292*1da177e4SLinus Torvalds }
293*1da177e4SLinus Torvalds 
294*1da177e4SLinus Torvalds asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
295*1da177e4SLinus Torvalds {
296*1da177e4SLinus Torvalds 	const stack32_t *uss = (const stack32_t *) regs.regs[4];
297*1da177e4SLinus Torvalds 	stack32_t *uoss = (stack32_t *) regs.regs[5];
298*1da177e4SLinus Torvalds 	unsigned long usp = regs.regs[29];
299*1da177e4SLinus Torvalds 	stack_t kss, koss;
300*1da177e4SLinus Torvalds 	int ret, err = 0;
301*1da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
302*1da177e4SLinus Torvalds 	s32 sp;
303*1da177e4SLinus Torvalds 
304*1da177e4SLinus Torvalds 	if (uss) {
305*1da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
306*1da177e4SLinus Torvalds 			return -EFAULT;
307*1da177e4SLinus Torvalds 		err |= __get_user(sp, &uss->ss_sp);
308*1da177e4SLinus Torvalds 		kss.ss_sp = (void *) (long) sp;
309*1da177e4SLinus Torvalds 		err |= __get_user(kss.ss_size, &uss->ss_size);
310*1da177e4SLinus Torvalds 		err |= __get_user(kss.ss_flags, &uss->ss_flags);
311*1da177e4SLinus Torvalds 		if (err)
312*1da177e4SLinus Torvalds 			return -EFAULT;
313*1da177e4SLinus Torvalds 	}
314*1da177e4SLinus Torvalds 
315*1da177e4SLinus Torvalds 	set_fs (KERNEL_DS);
316*1da177e4SLinus Torvalds 	ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, usp);
317*1da177e4SLinus Torvalds 	set_fs (old_fs);
318*1da177e4SLinus Torvalds 
319*1da177e4SLinus Torvalds 	if (!ret && uoss) {
320*1da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
321*1da177e4SLinus Torvalds 			return -EFAULT;
322*1da177e4SLinus Torvalds 		sp = (int) (long) koss.ss_sp;
323*1da177e4SLinus Torvalds 		err |= __put_user(sp, &uoss->ss_sp);
324*1da177e4SLinus Torvalds 		err |= __put_user(koss.ss_size, &uoss->ss_size);
325*1da177e4SLinus Torvalds 		err |= __put_user(koss.ss_flags, &uoss->ss_flags);
326*1da177e4SLinus Torvalds 		if (err)
327*1da177e4SLinus Torvalds 			return -EFAULT;
328*1da177e4SLinus Torvalds 	}
329*1da177e4SLinus Torvalds 	return ret;
330*1da177e4SLinus Torvalds }
331*1da177e4SLinus Torvalds 
332*1da177e4SLinus Torvalds static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc)
333*1da177e4SLinus Torvalds {
334*1da177e4SLinus Torvalds 	int err = 0;
335*1da177e4SLinus Torvalds 	__u32 used_math;
336*1da177e4SLinus Torvalds 
337*1da177e4SLinus Torvalds 	/* Always make any pending restarted system calls return -EINTR */
338*1da177e4SLinus Torvalds 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
339*1da177e4SLinus Torvalds 
340*1da177e4SLinus Torvalds 	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
341*1da177e4SLinus Torvalds 	err |= __get_user(regs->hi, &sc->sc_mdhi);
342*1da177e4SLinus Torvalds 	err |= __get_user(regs->lo, &sc->sc_mdlo);
343*1da177e4SLinus Torvalds 
344*1da177e4SLinus Torvalds #define restore_gp_reg(i) do {						\
345*1da177e4SLinus Torvalds 	err |= __get_user(regs->regs[i], &sc->sc_regs[i]);		\
346*1da177e4SLinus Torvalds } while(0)
347*1da177e4SLinus Torvalds 	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
348*1da177e4SLinus Torvalds 	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
349*1da177e4SLinus Torvalds 	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
350*1da177e4SLinus Torvalds 	restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
351*1da177e4SLinus Torvalds 	restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
352*1da177e4SLinus Torvalds 	restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
353*1da177e4SLinus Torvalds 	restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
354*1da177e4SLinus Torvalds 	restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
355*1da177e4SLinus Torvalds 	restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
356*1da177e4SLinus Torvalds 	restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
357*1da177e4SLinus Torvalds 	restore_gp_reg(31);
358*1da177e4SLinus Torvalds #undef restore_gp_reg
359*1da177e4SLinus Torvalds 
360*1da177e4SLinus Torvalds 	err |= __get_user(used_math, &sc->sc_used_math);
361*1da177e4SLinus Torvalds 	conditional_used_math(used_math);
362*1da177e4SLinus Torvalds 
363*1da177e4SLinus Torvalds 	preempt_disable();
364*1da177e4SLinus Torvalds 
365*1da177e4SLinus Torvalds 	if (used_math()) {
366*1da177e4SLinus Torvalds 		/* restore fpu context if we have used it before */
367*1da177e4SLinus Torvalds 		own_fpu();
368*1da177e4SLinus Torvalds 		err |= restore_fp_context32(sc);
369*1da177e4SLinus Torvalds 	} else {
370*1da177e4SLinus Torvalds 		/* signal handler may have used FPU.  Give it up. */
371*1da177e4SLinus Torvalds 		lose_fpu();
372*1da177e4SLinus Torvalds 	}
373*1da177e4SLinus Torvalds 
374*1da177e4SLinus Torvalds 	preempt_enable();
375*1da177e4SLinus Torvalds 
376*1da177e4SLinus Torvalds 	return err;
377*1da177e4SLinus Torvalds }
378*1da177e4SLinus Torvalds 
379*1da177e4SLinus Torvalds struct sigframe {
380*1da177e4SLinus Torvalds 	u32 sf_ass[4];			/* argument save space for o32 */
381*1da177e4SLinus Torvalds 	u32 sf_code[2];			/* signal trampoline */
382*1da177e4SLinus Torvalds 	struct sigcontext32 sf_sc;
383*1da177e4SLinus Torvalds 	sigset_t sf_mask;
384*1da177e4SLinus Torvalds };
385*1da177e4SLinus Torvalds 
386*1da177e4SLinus Torvalds struct rt_sigframe32 {
387*1da177e4SLinus Torvalds 	u32 rs_ass[4];			/* argument save space for o32 */
388*1da177e4SLinus Torvalds 	u32 rs_code[2];			/* signal trampoline */
389*1da177e4SLinus Torvalds 	compat_siginfo_t rs_info;
390*1da177e4SLinus Torvalds 	struct ucontext32 rs_uc;
391*1da177e4SLinus Torvalds };
392*1da177e4SLinus Torvalds 
393*1da177e4SLinus Torvalds int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from)
394*1da177e4SLinus Torvalds {
395*1da177e4SLinus Torvalds 	int err;
396*1da177e4SLinus Torvalds 
397*1da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
398*1da177e4SLinus Torvalds 		return -EFAULT;
399*1da177e4SLinus Torvalds 
400*1da177e4SLinus Torvalds 	/* If you change siginfo_t structure, please be sure
401*1da177e4SLinus Torvalds 	   this code is fixed accordingly.
402*1da177e4SLinus Torvalds 	   It should never copy any pad contained in the structure
403*1da177e4SLinus Torvalds 	   to avoid security leaks, but must copy the generic
404*1da177e4SLinus Torvalds 	   3 ints plus the relevant union member.
405*1da177e4SLinus Torvalds 	   This routine must convert siginfo from 64bit to 32bit as well
406*1da177e4SLinus Torvalds 	   at the same time.  */
407*1da177e4SLinus Torvalds 	err = __put_user(from->si_signo, &to->si_signo);
408*1da177e4SLinus Torvalds 	err |= __put_user(from->si_errno, &to->si_errno);
409*1da177e4SLinus Torvalds 	err |= __put_user((short)from->si_code, &to->si_code);
410*1da177e4SLinus Torvalds 	if (from->si_code < 0)
411*1da177e4SLinus Torvalds 		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
412*1da177e4SLinus Torvalds 	else {
413*1da177e4SLinus Torvalds 		switch (from->si_code >> 16) {
414*1da177e4SLinus Torvalds 		case __SI_CHLD >> 16:
415*1da177e4SLinus Torvalds 			err |= __put_user(from->si_utime, &to->si_utime);
416*1da177e4SLinus Torvalds 			err |= __put_user(from->si_stime, &to->si_stime);
417*1da177e4SLinus Torvalds 			err |= __put_user(from->si_status, &to->si_status);
418*1da177e4SLinus Torvalds 		default:
419*1da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
420*1da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
421*1da177e4SLinus Torvalds 			break;
422*1da177e4SLinus Torvalds 		case __SI_FAULT >> 16:
423*1da177e4SLinus Torvalds 			err |= __put_user((long)from->si_addr, &to->si_addr);
424*1da177e4SLinus Torvalds 			break;
425*1da177e4SLinus Torvalds 		case __SI_POLL >> 16:
426*1da177e4SLinus Torvalds 			err |= __put_user(from->si_band, &to->si_band);
427*1da177e4SLinus Torvalds 			err |= __put_user(from->si_fd, &to->si_fd);
428*1da177e4SLinus Torvalds 			break;
429*1da177e4SLinus Torvalds 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
430*1da177e4SLinus Torvalds 		case __SI_MESGQ >> 16:
431*1da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
432*1da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
433*1da177e4SLinus Torvalds 			err |= __put_user(from->si_int, &to->si_int);
434*1da177e4SLinus Torvalds 			break;
435*1da177e4SLinus Torvalds 		}
436*1da177e4SLinus Torvalds 	}
437*1da177e4SLinus Torvalds 	return err;
438*1da177e4SLinus Torvalds }
439*1da177e4SLinus Torvalds 
440*1da177e4SLinus Torvalds save_static_function(sys32_sigreturn);
441*1da177e4SLinus Torvalds __attribute_used__ noinline static void
442*1da177e4SLinus Torvalds _sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
443*1da177e4SLinus Torvalds {
444*1da177e4SLinus Torvalds 	struct sigframe *frame;
445*1da177e4SLinus Torvalds 	sigset_t blocked;
446*1da177e4SLinus Torvalds 
447*1da177e4SLinus Torvalds 	frame = (struct sigframe *) regs.regs[29];
448*1da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
449*1da177e4SLinus Torvalds 		goto badframe;
450*1da177e4SLinus Torvalds 	if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
451*1da177e4SLinus Torvalds 		goto badframe;
452*1da177e4SLinus Torvalds 
453*1da177e4SLinus Torvalds 	sigdelsetmask(&blocked, ~_BLOCKABLE);
454*1da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
455*1da177e4SLinus Torvalds 	current->blocked = blocked;
456*1da177e4SLinus Torvalds 	recalc_sigpending();
457*1da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
458*1da177e4SLinus Torvalds 
459*1da177e4SLinus Torvalds 	if (restore_sigcontext32(&regs, &frame->sf_sc))
460*1da177e4SLinus Torvalds 		goto badframe;
461*1da177e4SLinus Torvalds 
462*1da177e4SLinus Torvalds 	/*
463*1da177e4SLinus Torvalds 	 * Don't let your children do this ...
464*1da177e4SLinus Torvalds 	 */
465*1da177e4SLinus Torvalds 	if (current_thread_info()->flags & TIF_SYSCALL_TRACE)
466*1da177e4SLinus Torvalds 		do_syscall_trace(&regs, 1);
467*1da177e4SLinus Torvalds 	__asm__ __volatile__(
468*1da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
469*1da177e4SLinus Torvalds 		"j\tsyscall_exit"
470*1da177e4SLinus Torvalds 		:/* no outputs */
471*1da177e4SLinus Torvalds 		:"r" (&regs));
472*1da177e4SLinus Torvalds 	/* Unreached */
473*1da177e4SLinus Torvalds 
474*1da177e4SLinus Torvalds badframe:
475*1da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
476*1da177e4SLinus Torvalds }
477*1da177e4SLinus Torvalds 
478*1da177e4SLinus Torvalds save_static_function(sys32_rt_sigreturn);
479*1da177e4SLinus Torvalds __attribute_used__ noinline static void
480*1da177e4SLinus Torvalds _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
481*1da177e4SLinus Torvalds {
482*1da177e4SLinus Torvalds 	struct rt_sigframe32 *frame;
483*1da177e4SLinus Torvalds 	sigset_t set;
484*1da177e4SLinus Torvalds 	stack_t st;
485*1da177e4SLinus Torvalds 	s32 sp;
486*1da177e4SLinus Torvalds 
487*1da177e4SLinus Torvalds 	frame = (struct rt_sigframe32 *) regs.regs[29];
488*1da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
489*1da177e4SLinus Torvalds 		goto badframe;
490*1da177e4SLinus Torvalds 	if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
491*1da177e4SLinus Torvalds 		goto badframe;
492*1da177e4SLinus Torvalds 
493*1da177e4SLinus Torvalds 	sigdelsetmask(&set, ~_BLOCKABLE);
494*1da177e4SLinus Torvalds 	spin_lock_irq(&current->sighand->siglock);
495*1da177e4SLinus Torvalds 	current->blocked = set;
496*1da177e4SLinus Torvalds 	recalc_sigpending();
497*1da177e4SLinus Torvalds 	spin_unlock_irq(&current->sighand->siglock);
498*1da177e4SLinus Torvalds 
499*1da177e4SLinus Torvalds 	if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
500*1da177e4SLinus Torvalds 		goto badframe;
501*1da177e4SLinus Torvalds 
502*1da177e4SLinus Torvalds 	/* The ucontext contains a stack32_t, so we must convert!  */
503*1da177e4SLinus Torvalds 	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
504*1da177e4SLinus Torvalds 		goto badframe;
505*1da177e4SLinus Torvalds 	st.ss_size = (long) sp;
506*1da177e4SLinus Torvalds 	if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
507*1da177e4SLinus Torvalds 		goto badframe;
508*1da177e4SLinus Torvalds 	if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
509*1da177e4SLinus Torvalds 		goto badframe;
510*1da177e4SLinus Torvalds 
511*1da177e4SLinus Torvalds 	/* It is more difficult to avoid calling this function than to
512*1da177e4SLinus Torvalds 	   call it and ignore errors.  */
513*1da177e4SLinus Torvalds 	do_sigaltstack(&st, NULL, regs.regs[29]);
514*1da177e4SLinus Torvalds 
515*1da177e4SLinus Torvalds 	/*
516*1da177e4SLinus Torvalds 	 * Don't let your children do this ...
517*1da177e4SLinus Torvalds 	 */
518*1da177e4SLinus Torvalds 	__asm__ __volatile__(
519*1da177e4SLinus Torvalds 		"move\t$29, %0\n\t"
520*1da177e4SLinus Torvalds 		"j\tsyscall_exit"
521*1da177e4SLinus Torvalds 		:/* no outputs */
522*1da177e4SLinus Torvalds 		:"r" (&regs));
523*1da177e4SLinus Torvalds 	/* Unreached */
524*1da177e4SLinus Torvalds 
525*1da177e4SLinus Torvalds badframe:
526*1da177e4SLinus Torvalds 	force_sig(SIGSEGV, current);
527*1da177e4SLinus Torvalds }
528*1da177e4SLinus Torvalds 
529*1da177e4SLinus Torvalds static inline int setup_sigcontext32(struct pt_regs *regs,
530*1da177e4SLinus Torvalds 				     struct sigcontext32 *sc)
531*1da177e4SLinus Torvalds {
532*1da177e4SLinus Torvalds 	int err = 0;
533*1da177e4SLinus Torvalds 
534*1da177e4SLinus Torvalds 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
535*1da177e4SLinus Torvalds 	err |= __put_user(regs->cp0_status, &sc->sc_status);
536*1da177e4SLinus Torvalds 
537*1da177e4SLinus Torvalds #define save_gp_reg(i) {						\
538*1da177e4SLinus Torvalds 	err |= __put_user(regs->regs[i], &sc->sc_regs[i]);		\
539*1da177e4SLinus Torvalds } while(0)
540*1da177e4SLinus Torvalds 	__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
541*1da177e4SLinus Torvalds 	save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
542*1da177e4SLinus Torvalds 	save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
543*1da177e4SLinus Torvalds 	save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
544*1da177e4SLinus Torvalds 	save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
545*1da177e4SLinus Torvalds 	save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
546*1da177e4SLinus Torvalds 	save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
547*1da177e4SLinus Torvalds 	save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
548*1da177e4SLinus Torvalds 	save_gp_reg(31);
549*1da177e4SLinus Torvalds #undef save_gp_reg
550*1da177e4SLinus Torvalds 
551*1da177e4SLinus Torvalds 	err |= __put_user(regs->hi, &sc->sc_mdhi);
552*1da177e4SLinus Torvalds 	err |= __put_user(regs->lo, &sc->sc_mdlo);
553*1da177e4SLinus Torvalds 	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
554*1da177e4SLinus Torvalds 	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
555*1da177e4SLinus Torvalds 
556*1da177e4SLinus Torvalds 	err |= __put_user(!!used_math(), &sc->sc_used_math);
557*1da177e4SLinus Torvalds 
558*1da177e4SLinus Torvalds 	if (!used_math())
559*1da177e4SLinus Torvalds 		goto out;
560*1da177e4SLinus Torvalds 
561*1da177e4SLinus Torvalds 	/*
562*1da177e4SLinus Torvalds 	 * Save FPU state to signal context.  Signal handler will "inherit"
563*1da177e4SLinus Torvalds 	 * current FPU state.
564*1da177e4SLinus Torvalds 	 */
565*1da177e4SLinus Torvalds 	preempt_disable();
566*1da177e4SLinus Torvalds 
567*1da177e4SLinus Torvalds 	if (!is_fpu_owner()) {
568*1da177e4SLinus Torvalds 		own_fpu();
569*1da177e4SLinus Torvalds 		restore_fp(current);
570*1da177e4SLinus Torvalds 	}
571*1da177e4SLinus Torvalds 	err |= save_fp_context32(sc);
572*1da177e4SLinus Torvalds 
573*1da177e4SLinus Torvalds 	preempt_enable();
574*1da177e4SLinus Torvalds 
575*1da177e4SLinus Torvalds out:
576*1da177e4SLinus Torvalds 	return err;
577*1da177e4SLinus Torvalds }
578*1da177e4SLinus Torvalds 
579*1da177e4SLinus Torvalds /*
580*1da177e4SLinus Torvalds  * Determine which stack to use..
581*1da177e4SLinus Torvalds  */
582*1da177e4SLinus Torvalds static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
583*1da177e4SLinus Torvalds 				 size_t frame_size)
584*1da177e4SLinus Torvalds {
585*1da177e4SLinus Torvalds 	unsigned long sp;
586*1da177e4SLinus Torvalds 
587*1da177e4SLinus Torvalds 	/* Default to using normal stack */
588*1da177e4SLinus Torvalds 	sp = regs->regs[29];
589*1da177e4SLinus Torvalds 
590*1da177e4SLinus Torvalds 	/*
591*1da177e4SLinus Torvalds  	 * FPU emulator may have it's own trampoline active just
592*1da177e4SLinus Torvalds  	 * above the user stack, 16-bytes before the next lowest
593*1da177e4SLinus Torvalds  	 * 16 byte boundary.  Try to avoid trashing it.
594*1da177e4SLinus Torvalds  	 */
595*1da177e4SLinus Torvalds  	sp -= 32;
596*1da177e4SLinus Torvalds 
597*1da177e4SLinus Torvalds 	/* This is the X/Open sanctioned signal stack switching.  */
598*1da177e4SLinus Torvalds 	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
599*1da177e4SLinus Torvalds 		sp = current->sas_ss_sp + current->sas_ss_size;
600*1da177e4SLinus Torvalds 
601*1da177e4SLinus Torvalds 	return (void *)((sp - frame_size) & ALMASK);
602*1da177e4SLinus Torvalds }
603*1da177e4SLinus Torvalds 
604*1da177e4SLinus Torvalds static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
605*1da177e4SLinus Torvalds 			       int signr, sigset_t *set)
606*1da177e4SLinus Torvalds {
607*1da177e4SLinus Torvalds 	struct sigframe *frame;
608*1da177e4SLinus Torvalds 	int err = 0;
609*1da177e4SLinus Torvalds 
610*1da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
611*1da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
612*1da177e4SLinus Torvalds 		goto give_sigsegv;
613*1da177e4SLinus Torvalds 
614*1da177e4SLinus Torvalds 	/*
615*1da177e4SLinus Torvalds 	 * Set up the return code ...
616*1da177e4SLinus Torvalds 	 *
617*1da177e4SLinus Torvalds 	 *         li      v0, __NR_O32_sigreturn
618*1da177e4SLinus Torvalds 	 *         syscall
619*1da177e4SLinus Torvalds 	 */
620*1da177e4SLinus Torvalds 	err |= __put_user(0x24020000 + __NR_O32_sigreturn, frame->sf_code + 0);
621*1da177e4SLinus Torvalds 	err |= __put_user(0x0000000c                     , frame->sf_code + 1);
622*1da177e4SLinus Torvalds 	flush_cache_sigtramp((unsigned long) frame->sf_code);
623*1da177e4SLinus Torvalds 
624*1da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->sf_sc);
625*1da177e4SLinus Torvalds 	err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
626*1da177e4SLinus Torvalds 	if (err)
627*1da177e4SLinus Torvalds 		goto give_sigsegv;
628*1da177e4SLinus Torvalds 
629*1da177e4SLinus Torvalds 	/*
630*1da177e4SLinus Torvalds 	 * Arguments to signal handler:
631*1da177e4SLinus Torvalds 	 *
632*1da177e4SLinus Torvalds 	 *   a0 = signal number
633*1da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
634*1da177e4SLinus Torvalds 	 *   a2 = pointer to struct sigcontext
635*1da177e4SLinus Torvalds 	 *
636*1da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to the
637*1da177e4SLinus Torvalds 	 * struct sigframe.
638*1da177e4SLinus Torvalds 	 */
639*1da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
640*1da177e4SLinus Torvalds 	regs->regs[ 5] = 0;
641*1da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
642*1da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
643*1da177e4SLinus Torvalds 	regs->regs[31] = (unsigned long) frame->sf_code;
644*1da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
645*1da177e4SLinus Torvalds 
646*1da177e4SLinus Torvalds #if DEBUG_SIG
647*1da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
648*1da177e4SLinus Torvalds 	       current->comm, current->pid,
649*1da177e4SLinus Torvalds 	       frame, regs->cp0_epc, frame->sf_code);
650*1da177e4SLinus Torvalds #endif
651*1da177e4SLinus Torvalds         return;
652*1da177e4SLinus Torvalds 
653*1da177e4SLinus Torvalds give_sigsegv:
654*1da177e4SLinus Torvalds 	force_sigsegv(signr, current);
655*1da177e4SLinus Torvalds }
656*1da177e4SLinus Torvalds 
657*1da177e4SLinus Torvalds static inline void setup_rt_frame(struct k_sigaction * ka,
658*1da177e4SLinus Torvalds 				  struct pt_regs *regs, int signr,
659*1da177e4SLinus Torvalds 				  sigset_t *set, siginfo_t *info)
660*1da177e4SLinus Torvalds {
661*1da177e4SLinus Torvalds 	struct rt_sigframe32 *frame;
662*1da177e4SLinus Torvalds 	int err = 0;
663*1da177e4SLinus Torvalds 	s32 sp;
664*1da177e4SLinus Torvalds 
665*1da177e4SLinus Torvalds 	frame = get_sigframe(ka, regs, sizeof(*frame));
666*1da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
667*1da177e4SLinus Torvalds 		goto give_sigsegv;
668*1da177e4SLinus Torvalds 
669*1da177e4SLinus Torvalds 	/* Set up to return from userspace.  If provided, use a stub already
670*1da177e4SLinus Torvalds 	   in userspace.  */
671*1da177e4SLinus Torvalds 	/*
672*1da177e4SLinus Torvalds 	 * Set up the return code ...
673*1da177e4SLinus Torvalds 	 *
674*1da177e4SLinus Torvalds 	 *         li      v0, __NR_O32_rt_sigreturn
675*1da177e4SLinus Torvalds 	 *         syscall
676*1da177e4SLinus Torvalds 	 */
677*1da177e4SLinus Torvalds 	err |= __put_user(0x24020000 + __NR_O32_rt_sigreturn, frame->rs_code + 0);
678*1da177e4SLinus Torvalds 	err |= __put_user(0x0000000c                      , frame->rs_code + 1);
679*1da177e4SLinus Torvalds 	flush_cache_sigtramp((unsigned long) frame->rs_code);
680*1da177e4SLinus Torvalds 
681*1da177e4SLinus Torvalds 	/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
682*1da177e4SLinus Torvalds 	err |= copy_siginfo_to_user32(&frame->rs_info, info);
683*1da177e4SLinus Torvalds 
684*1da177e4SLinus Torvalds 	/* Create the ucontext.  */
685*1da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_flags);
686*1da177e4SLinus Torvalds 	err |= __put_user(0, &frame->rs_uc.uc_link);
687*1da177e4SLinus Torvalds 	sp = (int) (long) current->sas_ss_sp;
688*1da177e4SLinus Torvalds 	err |= __put_user(sp,
689*1da177e4SLinus Torvalds 	                  &frame->rs_uc.uc_stack.ss_sp);
690*1da177e4SLinus Torvalds 	err |= __put_user(sas_ss_flags(regs->regs[29]),
691*1da177e4SLinus Torvalds 	                  &frame->rs_uc.uc_stack.ss_flags);
692*1da177e4SLinus Torvalds 	err |= __put_user(current->sas_ss_size,
693*1da177e4SLinus Torvalds 	                  &frame->rs_uc.uc_stack.ss_size);
694*1da177e4SLinus Torvalds 	err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
695*1da177e4SLinus Torvalds 	err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
696*1da177e4SLinus Torvalds 
697*1da177e4SLinus Torvalds 	if (err)
698*1da177e4SLinus Torvalds 		goto give_sigsegv;
699*1da177e4SLinus Torvalds 
700*1da177e4SLinus Torvalds 	/*
701*1da177e4SLinus Torvalds 	 * Arguments to signal handler:
702*1da177e4SLinus Torvalds 	 *
703*1da177e4SLinus Torvalds 	 *   a0 = signal number
704*1da177e4SLinus Torvalds 	 *   a1 = 0 (should be cause)
705*1da177e4SLinus Torvalds 	 *   a2 = pointer to ucontext
706*1da177e4SLinus Torvalds 	 *
707*1da177e4SLinus Torvalds 	 * $25 and c0_epc point to the signal handler, $29 points to
708*1da177e4SLinus Torvalds 	 * the struct rt_sigframe32.
709*1da177e4SLinus Torvalds 	 */
710*1da177e4SLinus Torvalds 	regs->regs[ 4] = signr;
711*1da177e4SLinus Torvalds 	regs->regs[ 5] = (unsigned long) &frame->rs_info;
712*1da177e4SLinus Torvalds 	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
713*1da177e4SLinus Torvalds 	regs->regs[29] = (unsigned long) frame;
714*1da177e4SLinus Torvalds 	regs->regs[31] = (unsigned long) frame->rs_code;
715*1da177e4SLinus Torvalds 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
716*1da177e4SLinus Torvalds 
717*1da177e4SLinus Torvalds #if DEBUG_SIG
718*1da177e4SLinus Torvalds 	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
719*1da177e4SLinus Torvalds 	       current->comm, current->pid,
720*1da177e4SLinus Torvalds 	       frame, regs->cp0_epc, frame->rs_code);
721*1da177e4SLinus Torvalds #endif
722*1da177e4SLinus Torvalds 	return;
723*1da177e4SLinus Torvalds 
724*1da177e4SLinus Torvalds give_sigsegv:
725*1da177e4SLinus Torvalds 	force_sigsegv(signr, current);
726*1da177e4SLinus Torvalds }
727*1da177e4SLinus Torvalds 
728*1da177e4SLinus Torvalds static inline void handle_signal(unsigned long sig, siginfo_t *info,
729*1da177e4SLinus Torvalds 	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
730*1da177e4SLinus Torvalds {
731*1da177e4SLinus Torvalds 	switch (regs->regs[0]) {
732*1da177e4SLinus Torvalds 	case ERESTART_RESTARTBLOCK:
733*1da177e4SLinus Torvalds 	case ERESTARTNOHAND:
734*1da177e4SLinus Torvalds 		regs->regs[2] = EINTR;
735*1da177e4SLinus Torvalds 		break;
736*1da177e4SLinus Torvalds 	case ERESTARTSYS:
737*1da177e4SLinus Torvalds 		if(!(ka->sa.sa_flags & SA_RESTART)) {
738*1da177e4SLinus Torvalds 			regs->regs[2] = EINTR;
739*1da177e4SLinus Torvalds 			break;
740*1da177e4SLinus Torvalds 		}
741*1da177e4SLinus Torvalds 	/* fallthrough */
742*1da177e4SLinus Torvalds 	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
743*1da177e4SLinus Torvalds 		regs->regs[7] = regs->regs[26];
744*1da177e4SLinus Torvalds 		regs->cp0_epc -= 8;
745*1da177e4SLinus Torvalds 	}
746*1da177e4SLinus Torvalds 
747*1da177e4SLinus Torvalds 	regs->regs[0] = 0;		/* Don't deal with this again.  */
748*1da177e4SLinus Torvalds 
749*1da177e4SLinus Torvalds 	if (ka->sa.sa_flags & SA_SIGINFO)
750*1da177e4SLinus Torvalds 		setup_rt_frame(ka, regs, sig, oldset, info);
751*1da177e4SLinus Torvalds 	else
752*1da177e4SLinus Torvalds 		setup_frame(ka, regs, sig, oldset);
753*1da177e4SLinus Torvalds 
754*1da177e4SLinus Torvalds 	if (!(ka->sa.sa_flags & SA_NODEFER)) {
755*1da177e4SLinus Torvalds 		spin_lock_irq(&current->sighand->siglock);
756*1da177e4SLinus Torvalds 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
757*1da177e4SLinus Torvalds 		sigaddset(&current->blocked,sig);
758*1da177e4SLinus Torvalds 		recalc_sigpending();
759*1da177e4SLinus Torvalds 		spin_unlock_irq(&current->sighand->siglock);
760*1da177e4SLinus Torvalds 	}
761*1da177e4SLinus Torvalds }
762*1da177e4SLinus Torvalds 
763*1da177e4SLinus Torvalds int do_signal32(sigset_t *oldset, struct pt_regs *regs)
764*1da177e4SLinus Torvalds {
765*1da177e4SLinus Torvalds 	struct k_sigaction ka;
766*1da177e4SLinus Torvalds 	siginfo_t info;
767*1da177e4SLinus Torvalds 	int signr;
768*1da177e4SLinus Torvalds 
769*1da177e4SLinus Torvalds 	/*
770*1da177e4SLinus Torvalds 	 * We want the common case to go fast, which is why we may in certain
771*1da177e4SLinus Torvalds 	 * cases get here from kernel mode. Just return without doing anything
772*1da177e4SLinus Torvalds 	 * if so.
773*1da177e4SLinus Torvalds 	 */
774*1da177e4SLinus Torvalds 	if (!user_mode(regs))
775*1da177e4SLinus Torvalds 		return 1;
776*1da177e4SLinus Torvalds 
777*1da177e4SLinus Torvalds 	if (try_to_freeze(0))
778*1da177e4SLinus Torvalds 		goto no_signal;
779*1da177e4SLinus Torvalds 
780*1da177e4SLinus Torvalds 	if (!oldset)
781*1da177e4SLinus Torvalds 		oldset = &current->blocked;
782*1da177e4SLinus Torvalds 
783*1da177e4SLinus Torvalds 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
784*1da177e4SLinus Torvalds 	if (signr > 0) {
785*1da177e4SLinus Torvalds 		handle_signal(signr, &info, &ka, oldset, regs);
786*1da177e4SLinus Torvalds 		return 1;
787*1da177e4SLinus Torvalds 	}
788*1da177e4SLinus Torvalds 
789*1da177e4SLinus Torvalds no_signal:
790*1da177e4SLinus Torvalds 	/*
791*1da177e4SLinus Torvalds 	 * Who's code doesn't conform to the restartable syscall convention
792*1da177e4SLinus Torvalds 	 * dies here!!!  The li instruction, a single machine instruction,
793*1da177e4SLinus Torvalds 	 * must directly be followed by the syscall instruction.
794*1da177e4SLinus Torvalds 	 */
795*1da177e4SLinus Torvalds 	if (regs->regs[0]) {
796*1da177e4SLinus Torvalds 		if (regs->regs[2] == ERESTARTNOHAND ||
797*1da177e4SLinus Torvalds 		    regs->regs[2] == ERESTARTSYS ||
798*1da177e4SLinus Torvalds 		    regs->regs[2] == ERESTARTNOINTR) {
799*1da177e4SLinus Torvalds 			regs->regs[7] = regs->regs[26];
800*1da177e4SLinus Torvalds 			regs->cp0_epc -= 8;
801*1da177e4SLinus Torvalds 		}
802*1da177e4SLinus Torvalds 		if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
803*1da177e4SLinus Torvalds 			regs->regs[2] = __NR_O32_restart_syscall;
804*1da177e4SLinus Torvalds 			regs->regs[7] = regs->regs[26];
805*1da177e4SLinus Torvalds 			regs->cp0_epc -= 4;
806*1da177e4SLinus Torvalds 		}
807*1da177e4SLinus Torvalds 	}
808*1da177e4SLinus Torvalds 	return 0;
809*1da177e4SLinus Torvalds }
810*1da177e4SLinus Torvalds 
811*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act,
812*1da177e4SLinus Torvalds 				  struct sigaction32 *oact,
813*1da177e4SLinus Torvalds 				  unsigned int sigsetsize)
814*1da177e4SLinus Torvalds {
815*1da177e4SLinus Torvalds 	struct k_sigaction new_sa, old_sa;
816*1da177e4SLinus Torvalds 	int ret = -EINVAL;
817*1da177e4SLinus Torvalds 
818*1da177e4SLinus Torvalds 	/* XXX: Don't preclude handling different sized sigset_t's.  */
819*1da177e4SLinus Torvalds 	if (sigsetsize != sizeof(sigset_t))
820*1da177e4SLinus Torvalds 		goto out;
821*1da177e4SLinus Torvalds 
822*1da177e4SLinus Torvalds 	if (act) {
823*1da177e4SLinus Torvalds 		int err = 0;
824*1da177e4SLinus Torvalds 
825*1da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
826*1da177e4SLinus Torvalds 			return -EFAULT;
827*1da177e4SLinus Torvalds 		err |= __get_user((u32)(u64)new_sa.sa.sa_handler,
828*1da177e4SLinus Torvalds 		                  &act->sa_handler);
829*1da177e4SLinus Torvalds 		err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
830*1da177e4SLinus Torvalds 		err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
831*1da177e4SLinus Torvalds 		if (err)
832*1da177e4SLinus Torvalds 			return -EFAULT;
833*1da177e4SLinus Torvalds 	}
834*1da177e4SLinus Torvalds 
835*1da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
836*1da177e4SLinus Torvalds 
837*1da177e4SLinus Torvalds 	if (!ret && oact) {
838*1da177e4SLinus Torvalds 		int err = 0;
839*1da177e4SLinus Torvalds 
840*1da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
841*1da177e4SLinus Torvalds 			return -EFAULT;
842*1da177e4SLinus Torvalds 
843*1da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
844*1da177e4SLinus Torvalds 		                   &oact->sa_handler);
845*1da177e4SLinus Torvalds 		err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
846*1da177e4SLinus Torvalds 		err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
847*1da177e4SLinus Torvalds 		if (err)
848*1da177e4SLinus Torvalds 			return -EFAULT;
849*1da177e4SLinus Torvalds 	}
850*1da177e4SLinus Torvalds out:
851*1da177e4SLinus Torvalds 	return ret;
852*1da177e4SLinus Torvalds }
853*1da177e4SLinus Torvalds 
854*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set,
855*1da177e4SLinus Torvalds 	compat_sigset_t *oset, unsigned int sigsetsize)
856*1da177e4SLinus Torvalds {
857*1da177e4SLinus Torvalds 	sigset_t old_set, new_set;
858*1da177e4SLinus Torvalds 	int ret;
859*1da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
860*1da177e4SLinus Torvalds 
861*1da177e4SLinus Torvalds 	if (set && get_sigset(&new_set, set))
862*1da177e4SLinus Torvalds 		return -EFAULT;
863*1da177e4SLinus Torvalds 
864*1da177e4SLinus Torvalds 	set_fs (KERNEL_DS);
865*1da177e4SLinus Torvalds 	ret = sys_rt_sigprocmask(how, set ? &new_set : NULL,
866*1da177e4SLinus Torvalds 				 oset ? &old_set : NULL, sigsetsize);
867*1da177e4SLinus Torvalds 	set_fs (old_fs);
868*1da177e4SLinus Torvalds 
869*1da177e4SLinus Torvalds 	if (!ret && oset && put_sigset(&old_set, oset))
870*1da177e4SLinus Torvalds 		return -EFAULT;
871*1da177e4SLinus Torvalds 
872*1da177e4SLinus Torvalds 	return ret;
873*1da177e4SLinus Torvalds }
874*1da177e4SLinus Torvalds 
875*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset,
876*1da177e4SLinus Torvalds 	unsigned int sigsetsize)
877*1da177e4SLinus Torvalds {
878*1da177e4SLinus Torvalds 	int ret;
879*1da177e4SLinus Torvalds 	sigset_t set;
880*1da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
881*1da177e4SLinus Torvalds 
882*1da177e4SLinus Torvalds 	set_fs (KERNEL_DS);
883*1da177e4SLinus Torvalds 	ret = sys_rt_sigpending(&set, sigsetsize);
884*1da177e4SLinus Torvalds 	set_fs (old_fs);
885*1da177e4SLinus Torvalds 
886*1da177e4SLinus Torvalds 	if (!ret && put_sigset(&set, uset))
887*1da177e4SLinus Torvalds 		return -EFAULT;
888*1da177e4SLinus Torvalds 
889*1da177e4SLinus Torvalds 	return ret;
890*1da177e4SLinus Torvalds }
891*1da177e4SLinus Torvalds 
892*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t *uinfo)
893*1da177e4SLinus Torvalds {
894*1da177e4SLinus Torvalds 	siginfo_t info;
895*1da177e4SLinus Torvalds 	int ret;
896*1da177e4SLinus Torvalds 	mm_segment_t old_fs = get_fs();
897*1da177e4SLinus Torvalds 
898*1da177e4SLinus Torvalds 	if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
899*1da177e4SLinus Torvalds 	    copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
900*1da177e4SLinus Torvalds 		return -EFAULT;
901*1da177e4SLinus Torvalds 	set_fs (KERNEL_DS);
902*1da177e4SLinus Torvalds 	ret = sys_rt_sigqueueinfo(pid, sig, &info);
903*1da177e4SLinus Torvalds 	set_fs (old_fs);
904*1da177e4SLinus Torvalds 	return ret;
905*1da177e4SLinus Torvalds }
906