blob: 5d102efbdbea55bec75614c02616319e62437190 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1991, 1992 Linus Torvalds
Martin Michlmayrdda73d02006-02-18 15:21:30 +00007 * Copyright (C) 1994 - 2000, 2006 Ralf Baechle
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9 */
Ralf Baechle02416dc2005-06-15 13:00:12 +000010#include <linux/cache.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/sched.h>
12#include <linux/mm.h>
13#include <linux/smp.h>
14#include <linux/smp_lock.h>
15#include <linux/kernel.h>
16#include <linux/signal.h>
17#include <linux/syscalls.h>
18#include <linux/errno.h>
19#include <linux/wait.h>
20#include <linux/ptrace.h>
21#include <linux/compat.h>
22#include <linux/suspend.h>
23#include <linux/compiler.h>
24
Ralf Baechlee50c0a82005-05-31 11:49:19 +000025#include <asm/abi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/asm.h>
27#include <linux/bitops.h>
28#include <asm/cacheflush.h>
29#include <asm/sim.h>
30#include <asm/uaccess.h>
31#include <asm/ucontext.h>
32#include <asm/system.h>
33#include <asm/fpu.h>
Ralf Baechle02416dc2005-06-15 13:00:12 +000034#include <asm/war.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +010036#include "signal-common.h"
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
39
40typedef struct compat_siginfo {
41 int si_signo;
42 int si_code;
43 int si_errno;
44
45 union {
46 int _pad[SI_PAD_SIZE32];
47
48 /* kill() */
49 struct {
50 compat_pid_t _pid; /* sender's pid */
51 compat_uid_t _uid; /* sender's uid */
52 } _kill;
53
54 /* SIGCHLD */
55 struct {
56 compat_pid_t _pid; /* which child */
57 compat_uid_t _uid; /* sender's uid */
58 int _status; /* exit code */
59 compat_clock_t _utime;
60 compat_clock_t _stime;
61 } _sigchld;
62
63 /* IRIX SIGCHLD */
64 struct {
65 compat_pid_t _pid; /* which child */
66 compat_clock_t _utime;
67 int _status; /* exit code */
68 compat_clock_t _stime;
69 } _irix_sigchld;
70
71 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
72 struct {
73 s32 _addr; /* faulting insn/memory ref. */
74 } _sigfault;
75
76 /* SIGPOLL, SIGXFSZ (To do ...) */
77 struct {
78 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
79 int _fd;
80 } _sigpoll;
81
82 /* POSIX.1b timers */
83 struct {
Ralf Baechlea9820992005-02-16 21:24:16 +000084 timer_t _tid; /* timer id */
85 int _overrun; /* overrun count */
Ralf Baechle209ac8d2005-03-18 17:36:42 +000086 compat_sigval_t _sigval;/* same as below */
Ralf Baechlea9820992005-02-16 21:24:16 +000087 int _sys_private; /* not to be passed to user */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 } _timer;
89
90 /* POSIX.1b signals */
91 struct {
92 compat_pid_t _pid; /* sender's pid */
93 compat_uid_t _uid; /* sender's uid */
94 compat_sigval_t _sigval;
95 } _rt;
96
97 } _sifields;
98} compat_siginfo_t;
99
100/*
101 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
102 */
103#define __NR_O32_sigreturn 4119
104#define __NR_O32_rt_sigreturn 4193
105#define __NR_O32_restart_syscall 4253
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/* 32-bit compatibility types */
110
111#define _NSIG_BPW32 32
112#define _NSIG_WORDS32 (_NSIG / _NSIG_BPW32)
113
114typedef struct {
115 unsigned int sig[_NSIG_WORDS32];
116} sigset_t32;
117
118typedef unsigned int __sighandler32_t;
119typedef void (*vfptr_t)(void);
120
121struct sigaction32 {
122 unsigned int sa_flags;
123 __sighandler32_t sa_handler;
124 compat_sigset_t sa_mask;
125};
126
127/* IRIX compatible stack_t */
128typedef struct sigaltstack32 {
129 s32 ss_sp;
130 compat_size_t ss_size;
131 int ss_flags;
132} stack32_t;
133
134struct ucontext32 {
135 u32 uc_flags;
136 s32 uc_link;
137 stack32_t uc_stack;
138 struct sigcontext32 uc_mcontext;
139 sigset_t32 uc_sigmask; /* mask last for extensibility */
140};
141
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100142#if ICACHE_REFILLS_WORKAROUND_WAR == 0
143
144struct rt_sigframe32 {
145 u32 rs_ass[4]; /* argument save space for o32 */
146 u32 rs_code[2]; /* signal trampoline */
147 compat_siginfo_t rs_info;
148 struct ucontext32 rs_uc;
149};
150
151#else /* ICACHE_REFILLS_WORKAROUND_WAR */
152
153struct rt_sigframe32 {
154 u32 rs_ass[4]; /* argument save space for o32 */
155 u32 rs_pad[2];
156 compat_siginfo_t rs_info;
157 struct ucontext32 rs_uc;
158 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
159};
160
161#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
162
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100163/*
164 * sigcontext handlers
165 */
166static int setup_sigcontext32(struct pt_regs *regs,
167 struct sigcontext32 __user *sc)
168{
169 int err = 0;
170 int i;
171
172 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
173 err |= __put_user(regs->cp0_status, &sc->sc_status);
174
175 err |= __put_user(0, &sc->sc_regs[0]);
176 for (i = 1; i < 32; i++)
177 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
178
179 err |= __put_user(regs->hi, &sc->sc_mdhi);
180 err |= __put_user(regs->lo, &sc->sc_mdlo);
181 if (cpu_has_dsp) {
182 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
183 err |= __put_user(mfhi1(), &sc->sc_hi1);
184 err |= __put_user(mflo1(), &sc->sc_lo1);
185 err |= __put_user(mfhi2(), &sc->sc_hi2);
186 err |= __put_user(mflo2(), &sc->sc_lo2);
187 err |= __put_user(mfhi3(), &sc->sc_hi3);
188 err |= __put_user(mflo3(), &sc->sc_lo3);
189 }
190
191 err |= __put_user(!!used_math(), &sc->sc_used_math);
192
193 if (used_math()) {
194 /*
195 * Save FPU state to signal context. Signal handler
196 * will "inherit" current FPU state.
197 */
198 preempt_disable();
199
200 if (!is_fpu_owner()) {
201 own_fpu();
202 restore_fp(current);
203 }
204 err |= save_fp_context32(sc);
205
206 preempt_enable();
207 }
208 return err;
209}
210
211static int restore_sigcontext32(struct pt_regs *regs,
212 struct sigcontext32 __user *sc)
213{
214 u32 used_math;
215 int err = 0;
216 s32 treg;
217 int i;
218
219 /* Always make any pending restarted system calls return -EINTR */
220 current_thread_info()->restart_block.fn = do_no_restart_syscall;
221
222 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
223 err |= __get_user(regs->hi, &sc->sc_mdhi);
224 err |= __get_user(regs->lo, &sc->sc_mdlo);
225 if (cpu_has_dsp) {
226 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
227 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
228 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
229 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
230 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
231 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
232 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
233 }
234
235 for (i = 1; i < 32; i++)
236 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
237
238 err |= __get_user(used_math, &sc->sc_used_math);
239 conditional_used_math(used_math);
240
241 preempt_disable();
242
243 if (used_math()) {
244 /* restore fpu context if we have used it before */
245 own_fpu();
246 err |= restore_fp_context32(sc);
247 } else {
248 /* signal handler may have used FPU. Give it up. */
249 lose_fpu();
250 }
251
252 preempt_enable();
253
254 return err;
255}
256
257/*
258 *
259 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260extern void __put_sigset_unknown_nsig(void);
261extern void __get_sigset_unknown_nsig(void);
262
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900263static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 int err = 0;
266
267 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
268 return -EFAULT;
269
270 switch (_NSIG_WORDS) {
271 default:
272 __put_sigset_unknown_nsig();
273 case 2:
274 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
275 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
276 case 1:
277 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
278 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
279 }
280
281 return err;
282}
283
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900284static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
286 int err = 0;
287 unsigned long sig[4];
288
289 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
290 return -EFAULT;
291
292 switch (_NSIG_WORDS) {
293 default:
294 __get_sigset_unknown_nsig();
295 case 2:
296 err |= __get_user (sig[3], &ubuf->sig[3]);
297 err |= __get_user (sig[2], &ubuf->sig[2]);
298 kbuf->sig[1] = sig[2] | (sig[3] << 32);
299 case 1:
300 err |= __get_user (sig[1], &ubuf->sig[1]);
301 err |= __get_user (sig[0], &ubuf->sig[0]);
302 kbuf->sig[0] = sig[0] | (sig[1] << 32);
303 }
304
305 return err;
306}
307
308/*
309 * Atomically swap in the new signal mask, and wait for a signal.
310 */
311
312save_static_function(sys32_sigsuspend);
313__attribute_used__ noinline static int
314_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
315{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900316 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000317 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900319 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 if (get_sigset(&newset, uset))
321 return -EFAULT;
322 sigdelsetmask(&newset, ~_BLOCKABLE);
323
324 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000325 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 current->blocked = newset;
327 recalc_sigpending();
328 spin_unlock_irq(&current->sighand->siglock);
329
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000330 current->state = TASK_INTERRUPTIBLE;
331 schedule();
332 set_thread_flag(TIF_RESTORE_SIGMASK);
333 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336save_static_function(sys32_rt_sigsuspend);
337__attribute_used__ noinline static int
338_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
339{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900340 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000341 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000342 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 /* XXX Don't preclude handling different sized sigset_t's. */
345 sigsetsize = regs.regs[5];
346 if (sigsetsize != sizeof(compat_sigset_t))
347 return -EINVAL;
348
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900349 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 if (get_sigset(&newset, uset))
351 return -EFAULT;
352 sigdelsetmask(&newset, ~_BLOCKABLE);
353
354 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000355 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000357 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 spin_unlock_irq(&current->sighand->siglock);
359
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000360 current->state = TASK_INTERRUPTIBLE;
361 schedule();
362 set_thread_flag(TIF_RESTORE_SIGMASK);
363 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
365
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900366asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
367 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 struct k_sigaction new_ka, old_ka;
370 int ret;
371 int err = 0;
372
373 if (act) {
374 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000375 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
378 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000379 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900380 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
382 err |= __get_user(mask, &act->sa_mask.sig[0]);
383 if (err)
384 return -EFAULT;
385
386 siginitset(&new_ka.sa.sa_mask, mask);
387 }
388
389 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
390
391 if (!ret && oact) {
392 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000393 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
395 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
396 &oact->sa_handler);
397 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000398 err |= __put_user(0, &oact->sa_mask.sig[1]);
399 err |= __put_user(0, &oact->sa_mask.sig[2]);
400 err |= __put_user(0, &oact->sa_mask.sig[3]);
401 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return -EFAULT;
403 }
404
405 return ret;
406}
407
408asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
409{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900410 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
411 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 unsigned long usp = regs.regs[29];
413 stack_t kss, koss;
414 int ret, err = 0;
415 mm_segment_t old_fs = get_fs();
416 s32 sp;
417
418 if (uss) {
419 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
420 return -EFAULT;
421 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900422 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 err |= __get_user(kss.ss_size, &uss->ss_size);
424 err |= __get_user(kss.ss_flags, &uss->ss_flags);
425 if (err)
426 return -EFAULT;
427 }
428
429 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900430 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
431 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 set_fs (old_fs);
433
434 if (!ret && uoss) {
435 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
436 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900437 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 err |= __put_user(sp, &uoss->ss_sp);
439 err |= __put_user(koss.ss_size, &uoss->ss_size);
440 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
441 if (err)
442 return -EFAULT;
443 }
444 return ret;
445}
446
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900447int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 int err;
450
451 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
452 return -EFAULT;
453
454 /* If you change siginfo_t structure, please be sure
455 this code is fixed accordingly.
456 It should never copy any pad contained in the structure
457 to avoid security leaks, but must copy the generic
458 3 ints plus the relevant union member.
459 This routine must convert siginfo from 64bit to 32bit as well
460 at the same time. */
461 err = __put_user(from->si_signo, &to->si_signo);
462 err |= __put_user(from->si_errno, &to->si_errno);
463 err |= __put_user((short)from->si_code, &to->si_code);
464 if (from->si_code < 0)
465 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
466 else {
467 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000468 case __SI_TIMER >> 16:
469 err |= __put_user(from->si_tid, &to->si_tid);
470 err |= __put_user(from->si_overrun, &to->si_overrun);
471 err |= __put_user(from->si_int, &to->si_int);
472 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 case __SI_CHLD >> 16:
474 err |= __put_user(from->si_utime, &to->si_utime);
475 err |= __put_user(from->si_stime, &to->si_stime);
476 err |= __put_user(from->si_status, &to->si_status);
477 default:
478 err |= __put_user(from->si_pid, &to->si_pid);
479 err |= __put_user(from->si_uid, &to->si_uid);
480 break;
481 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900482 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 break;
484 case __SI_POLL >> 16:
485 err |= __put_user(from->si_band, &to->si_band);
486 err |= __put_user(from->si_fd, &to->si_fd);
487 break;
488 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
489 case __SI_MESGQ >> 16:
490 err |= __put_user(from->si_pid, &to->si_pid);
491 err |= __put_user(from->si_uid, &to->si_uid);
492 err |= __put_user(from->si_int, &to->si_int);
493 break;
494 }
495 }
496 return err;
497}
498
499save_static_function(sys32_sigreturn);
500__attribute_used__ noinline static void
501_sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
502{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900503 struct sigframe __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 sigset_t blocked;
505
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900506 frame = (struct sigframe __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
508 goto badframe;
509 if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
510 goto badframe;
511
512 sigdelsetmask(&blocked, ~_BLOCKABLE);
513 spin_lock_irq(&current->sighand->siglock);
514 current->blocked = blocked;
515 recalc_sigpending();
516 spin_unlock_irq(&current->sighand->siglock);
517
518 if (restore_sigcontext32(&regs, &frame->sf_sc))
519 goto badframe;
520
521 /*
522 * Don't let your children do this ...
523 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 __asm__ __volatile__(
525 "move\t$29, %0\n\t"
526 "j\tsyscall_exit"
527 :/* no outputs */
528 :"r" (&regs));
529 /* Unreached */
530
531badframe:
532 force_sig(SIGSEGV, current);
533}
534
535save_static_function(sys32_rt_sigreturn);
536__attribute_used__ noinline static void
537_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
538{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900539 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000540 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 sigset_t set;
542 stack_t st;
543 s32 sp;
544
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900545 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
547 goto badframe;
548 if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
549 goto badframe;
550
551 sigdelsetmask(&set, ~_BLOCKABLE);
552 spin_lock_irq(&current->sighand->siglock);
553 current->blocked = set;
554 recalc_sigpending();
555 spin_unlock_irq(&current->sighand->siglock);
556
557 if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
558 goto badframe;
559
560 /* The ucontext contains a stack32_t, so we must convert! */
561 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
562 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900563 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
565 goto badframe;
566 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
567 goto badframe;
568
569 /* It is more difficult to avoid calling this function than to
570 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000571 old_fs = get_fs();
572 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900573 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000574 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 /*
577 * Don't let your children do this ...
578 */
579 __asm__ __volatile__(
580 "move\t$29, %0\n\t"
581 "j\tsyscall_exit"
582 :/* no outputs */
583 :"r" (&regs));
584 /* Unreached */
585
586badframe:
587 force_sig(SIGSEGV, current);
588}
589
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900590int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
591 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900593 struct sigframe __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 int err = 0;
595
596 frame = get_sigframe(ka, regs, sizeof(*frame));
597 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
598 goto give_sigsegv;
599
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100600 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 err |= setup_sigcontext32(regs, &frame->sf_sc);
603 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
604 if (err)
605 goto give_sigsegv;
606
607 /*
608 * Arguments to signal handler:
609 *
610 * a0 = signal number
611 * a1 = 0 (should be cause)
612 * a2 = pointer to struct sigcontext
613 *
614 * $25 and c0_epc point to the signal handler, $29 points to the
615 * struct sigframe.
616 */
617 regs->regs[ 4] = signr;
618 regs->regs[ 5] = 0;
619 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
620 regs->regs[29] = (unsigned long) frame;
621 regs->regs[31] = (unsigned long) frame->sf_code;
622 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
623
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100624 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100626 frame, regs->cp0_epc, regs->regs[31]);
627
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000628 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630give_sigsegv:
631 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000632 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633}
634
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900635int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
636 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900638 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 int err = 0;
640 s32 sp;
641
642 frame = get_sigframe(ka, regs, sizeof(*frame));
643 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
644 goto give_sigsegv;
645
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100646 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
649 err |= copy_siginfo_to_user32(&frame->rs_info, info);
650
651 /* Create the ucontext. */
652 err |= __put_user(0, &frame->rs_uc.uc_flags);
653 err |= __put_user(0, &frame->rs_uc.uc_link);
654 sp = (int) (long) current->sas_ss_sp;
655 err |= __put_user(sp,
656 &frame->rs_uc.uc_stack.ss_sp);
657 err |= __put_user(sas_ss_flags(regs->regs[29]),
658 &frame->rs_uc.uc_stack.ss_flags);
659 err |= __put_user(current->sas_ss_size,
660 &frame->rs_uc.uc_stack.ss_size);
661 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
662 err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
663
664 if (err)
665 goto give_sigsegv;
666
667 /*
668 * Arguments to signal handler:
669 *
670 * a0 = signal number
671 * a1 = 0 (should be cause)
672 * a2 = pointer to ucontext
673 *
674 * $25 and c0_epc point to the signal handler, $29 points to
675 * the struct rt_sigframe32.
676 */
677 regs->regs[ 4] = signr;
678 regs->regs[ 5] = (unsigned long) &frame->rs_info;
679 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
680 regs->regs[29] = (unsigned long) frame;
681 regs->regs[31] = (unsigned long) frame->rs_code;
682 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
683
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100684 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100686 frame, regs->cp0_epc, regs->regs[31]);
687
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000688 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690give_sigsegv:
691 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000692 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693}
694
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000695static inline int handle_signal(unsigned long sig, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
697{
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000698 int ret;
699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 switch (regs->regs[0]) {
701 case ERESTART_RESTARTBLOCK:
702 case ERESTARTNOHAND:
703 regs->regs[2] = EINTR;
704 break;
705 case ERESTARTSYS:
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000706 if (!(ka->sa.sa_flags & SA_RESTART)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 regs->regs[2] = EINTR;
708 break;
709 }
710 /* fallthrough */
711 case ERESTARTNOINTR: /* Userland will reload $v0. */
712 regs->regs[7] = regs->regs[26];
713 regs->cp0_epc -= 8;
714 }
715
716 regs->regs[0] = 0; /* Don't deal with this again. */
717
718 if (ka->sa.sa_flags & SA_SIGINFO)
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000719 ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 else
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000721 ret = current->thread.abi->setup_frame(ka, regs, sig, oldset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Steven Rostedt69be8f12005-08-29 11:44:09 -0400723 spin_lock_irq(&current->sighand->siglock);
724 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
725 if (!(ka->sa.sa_flags & SA_NODEFER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 sigaddset(&current->blocked,sig);
Steven Rostedt69be8f12005-08-29 11:44:09 -0400727 recalc_sigpending();
728 spin_unlock_irq(&current->sighand->siglock);
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000729
730 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
Martin Michlmayrdda73d02006-02-18 15:21:30 +0000733void do_signal32(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
735 struct k_sigaction ka;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000736 sigset_t *oldset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 siginfo_t info;
738 int signr;
739
740 /*
741 * We want the common case to go fast, which is why we may in certain
742 * cases get here from kernel mode. Just return without doing anything
743 * if so.
744 */
745 if (!user_mode(regs))
Martin Michlmayrdda73d02006-02-18 15:21:30 +0000746 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000748 if (test_thread_flag(TIF_RESTORE_SIGMASK))
749 oldset = &current->saved_sigmask;
750 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 oldset = &current->blocked;
752
753 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000754 if (signr > 0) {
755 /* Whee! Actually deliver the signal. */
756 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
757 /*
758 * A signal was successfully delivered; the saved
759 * sigmask will have been stored in the signal frame,
760 * and will be restored by sigreturn, so we can simply
761 * clear the TIF_RESTORE_SIGMASK flag.
762 */
763 if (test_thread_flag(TIF_RESTORE_SIGMASK))
764 clear_thread_flag(TIF_RESTORE_SIGMASK);
765 }
Ralf Baechle45887e12006-08-03 21:54:13 +0100766
767 return;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 /*
771 * Who's code doesn't conform to the restartable syscall convention
772 * dies here!!! The li instruction, a single machine instruction,
773 * must directly be followed by the syscall instruction.
774 */
775 if (regs->regs[0]) {
776 if (regs->regs[2] == ERESTARTNOHAND ||
777 regs->regs[2] == ERESTARTSYS ||
778 regs->regs[2] == ERESTARTNOINTR) {
779 regs->regs[7] = regs->regs[26];
780 regs->cp0_epc -= 8;
781 }
782 if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
783 regs->regs[2] = __NR_O32_restart_syscall;
784 regs->regs[7] = regs->regs[26];
785 regs->cp0_epc -= 4;
786 }
Ralf Baechle13fdd312006-08-08 03:47:01 +0100787 regs->regs[0] = 0; /* Don't deal with this again. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 }
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000789
790 /*
791 * If there's no signal to deliver, we just put the saved sigmask
792 * back
793 */
794 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
795 clear_thread_flag(TIF_RESTORE_SIGMASK);
796 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798}
799
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900800asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900801 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 unsigned int sigsetsize)
803{
804 struct k_sigaction new_sa, old_sa;
805 int ret = -EINVAL;
806
807 /* XXX: Don't preclude handling different sized sigset_t's. */
808 if (sigsetsize != sizeof(sigset_t))
809 goto out;
810
811 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000812 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 int err = 0;
814
815 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
816 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000817 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900818 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
820 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
821 if (err)
822 return -EFAULT;
823 }
824
825 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
826
827 if (!ret && oact) {
828 int err = 0;
829
830 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
831 return -EFAULT;
832
833 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
834 &oact->sa_handler);
835 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
836 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
837 if (err)
838 return -EFAULT;
839 }
840out:
841 return ret;
842}
843
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900844asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900845 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846{
847 sigset_t old_set, new_set;
848 int ret;
849 mm_segment_t old_fs = get_fs();
850
851 if (set && get_sigset(&new_set, set))
852 return -EFAULT;
853
854 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900855 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
856 oset ? (sigset_t __user *)&old_set : NULL,
857 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 set_fs (old_fs);
859
860 if (!ret && oset && put_sigset(&old_set, oset))
861 return -EFAULT;
862
863 return ret;
864}
865
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900866asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 unsigned int sigsetsize)
868{
869 int ret;
870 sigset_t set;
871 mm_segment_t old_fs = get_fs();
872
873 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900874 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 set_fs (old_fs);
876
877 if (!ret && put_sigset(&set, uset))
878 return -EFAULT;
879
880 return ret;
881}
882
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900883asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 siginfo_t info;
886 int ret;
887 mm_segment_t old_fs = get_fs();
888
889 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
890 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
891 return -EFAULT;
892 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900893 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 set_fs (old_fs);
895 return ret;
896}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000897
898asmlinkage long
899sys32_waitid(int which, compat_pid_t pid,
900 compat_siginfo_t __user *uinfo, int options,
901 struct compat_rusage __user *uru)
902{
903 siginfo_t info;
904 struct rusage ru;
905 long ret;
906 mm_segment_t old_fs = get_fs();
907
908 info.si_signo = 0;
909 set_fs (KERNEL_DS);
910 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
911 uru ? (struct rusage __user *) &ru : NULL);
912 set_fs (old_fs);
913
914 if (ret < 0 || info.si_signo == 0)
915 return ret;
916
917 if (uru && (ret = put_compat_rusage(&ru, uru)))
918 return ret;
919
920 BUG_ON(info.si_code & __SI_MASK);
921 info.si_code |= __SI_CHLD;
922 return copy_siginfo_to_user32(uinfo, &info);
923}