blob: 183fc7e55f34cff2b38c88e5c8ec4f7412446d46 [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-Huu36a1f2c2007-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);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100173
174 err |= __put_user(0, &sc->sc_regs[0]);
175 for (i = 1; i < 32; i++)
176 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
177
178 err |= __put_user(regs->hi, &sc->sc_mdhi);
179 err |= __put_user(regs->lo, &sc->sc_mdlo);
180 if (cpu_has_dsp) {
181 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
182 err |= __put_user(mfhi1(), &sc->sc_hi1);
183 err |= __put_user(mflo1(), &sc->sc_lo1);
184 err |= __put_user(mfhi2(), &sc->sc_hi2);
185 err |= __put_user(mflo2(), &sc->sc_lo2);
186 err |= __put_user(mfhi3(), &sc->sc_hi3);
187 err |= __put_user(mflo3(), &sc->sc_lo3);
188 }
189
190 err |= __put_user(!!used_math(), &sc->sc_used_math);
191
192 if (used_math()) {
193 /*
194 * Save FPU state to signal context. Signal handler
195 * will "inherit" current FPU state.
196 */
197 preempt_disable();
198
199 if (!is_fpu_owner()) {
200 own_fpu();
201 restore_fp(current);
202 }
203 err |= save_fp_context32(sc);
204
205 preempt_enable();
206 }
207 return err;
208}
209
210static int restore_sigcontext32(struct pt_regs *regs,
211 struct sigcontext32 __user *sc)
212{
213 u32 used_math;
214 int err = 0;
215 s32 treg;
216 int i;
217
218 /* Always make any pending restarted system calls return -EINTR */
219 current_thread_info()->restart_block.fn = do_no_restart_syscall;
220
221 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
222 err |= __get_user(regs->hi, &sc->sc_mdhi);
223 err |= __get_user(regs->lo, &sc->sc_mdlo);
224 if (cpu_has_dsp) {
225 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
226 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
227 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
228 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
229 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
230 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
231 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
232 }
233
234 for (i = 1; i < 32; i++)
235 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
236
237 err |= __get_user(used_math, &sc->sc_used_math);
238 conditional_used_math(used_math);
239
240 preempt_disable();
241
242 if (used_math()) {
243 /* restore fpu context if we have used it before */
244 own_fpu();
245 err |= restore_fp_context32(sc);
246 } else {
247 /* signal handler may have used FPU. Give it up. */
248 lose_fpu();
249 }
250
251 preempt_enable();
252
253 return err;
254}
255
256/*
257 *
258 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259extern void __put_sigset_unknown_nsig(void);
260extern void __get_sigset_unknown_nsig(void);
261
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900262static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
264 int err = 0;
265
266 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
267 return -EFAULT;
268
269 switch (_NSIG_WORDS) {
270 default:
271 __put_sigset_unknown_nsig();
272 case 2:
273 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
274 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
275 case 1:
276 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
277 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
278 }
279
280 return err;
281}
282
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900283static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 int err = 0;
286 unsigned long sig[4];
287
288 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
289 return -EFAULT;
290
291 switch (_NSIG_WORDS) {
292 default:
293 __get_sigset_unknown_nsig();
294 case 2:
295 err |= __get_user (sig[3], &ubuf->sig[3]);
296 err |= __get_user (sig[2], &ubuf->sig[2]);
297 kbuf->sig[1] = sig[2] | (sig[3] << 32);
298 case 1:
299 err |= __get_user (sig[1], &ubuf->sig[1]);
300 err |= __get_user (sig[0], &ubuf->sig[0]);
301 kbuf->sig[0] = sig[0] | (sig[1] << 32);
302 }
303
304 return err;
305}
306
307/*
308 * Atomically swap in the new signal mask, and wait for a signal.
309 */
310
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100311asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900313 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000314 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900316 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (get_sigset(&newset, uset))
318 return -EFAULT;
319 sigdelsetmask(&newset, ~_BLOCKABLE);
320
321 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000322 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 current->blocked = newset;
324 recalc_sigpending();
325 spin_unlock_irq(&current->sighand->siglock);
326
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000327 current->state = TASK_INTERRUPTIBLE;
328 schedule();
329 set_thread_flag(TIF_RESTORE_SIGMASK);
330 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100333asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900335 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000336 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000337 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339 /* XXX Don't preclude handling different sized sigset_t's. */
340 sigsetsize = regs.regs[5];
341 if (sigsetsize != sizeof(compat_sigset_t))
342 return -EINVAL;
343
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900344 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 if (get_sigset(&newset, uset))
346 return -EFAULT;
347 sigdelsetmask(&newset, ~_BLOCKABLE);
348
349 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000350 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000352 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 spin_unlock_irq(&current->sighand->siglock);
354
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000355 current->state = TASK_INTERRUPTIBLE;
356 schedule();
357 set_thread_flag(TIF_RESTORE_SIGMASK);
358 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900361asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
362 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 struct k_sigaction new_ka, old_ka;
365 int ret;
366 int err = 0;
367
368 if (act) {
369 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000370 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
373 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000374 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900375 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
377 err |= __get_user(mask, &act->sa_mask.sig[0]);
378 if (err)
379 return -EFAULT;
380
381 siginitset(&new_ka.sa.sa_mask, mask);
382 }
383
384 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
385
386 if (!ret && oact) {
387 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000388 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
390 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
391 &oact->sa_handler);
392 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000393 err |= __put_user(0, &oact->sa_mask.sig[1]);
394 err |= __put_user(0, &oact->sa_mask.sig[2]);
395 err |= __put_user(0, &oact->sa_mask.sig[3]);
396 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return -EFAULT;
398 }
399
400 return ret;
401}
402
403asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
404{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900405 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
406 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 unsigned long usp = regs.regs[29];
408 stack_t kss, koss;
409 int ret, err = 0;
410 mm_segment_t old_fs = get_fs();
411 s32 sp;
412
413 if (uss) {
414 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
415 return -EFAULT;
416 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900417 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 err |= __get_user(kss.ss_size, &uss->ss_size);
419 err |= __get_user(kss.ss_flags, &uss->ss_flags);
420 if (err)
421 return -EFAULT;
422 }
423
424 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900425 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
426 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 set_fs (old_fs);
428
429 if (!ret && uoss) {
430 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
431 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900432 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 err |= __put_user(sp, &uoss->ss_sp);
434 err |= __put_user(koss.ss_size, &uoss->ss_size);
435 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
436 if (err)
437 return -EFAULT;
438 }
439 return ret;
440}
441
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900442int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
444 int err;
445
446 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
447 return -EFAULT;
448
449 /* If you change siginfo_t structure, please be sure
450 this code is fixed accordingly.
451 It should never copy any pad contained in the structure
452 to avoid security leaks, but must copy the generic
453 3 ints plus the relevant union member.
454 This routine must convert siginfo from 64bit to 32bit as well
455 at the same time. */
456 err = __put_user(from->si_signo, &to->si_signo);
457 err |= __put_user(from->si_errno, &to->si_errno);
458 err |= __put_user((short)from->si_code, &to->si_code);
459 if (from->si_code < 0)
460 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
461 else {
462 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000463 case __SI_TIMER >> 16:
464 err |= __put_user(from->si_tid, &to->si_tid);
465 err |= __put_user(from->si_overrun, &to->si_overrun);
466 err |= __put_user(from->si_int, &to->si_int);
467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 case __SI_CHLD >> 16:
469 err |= __put_user(from->si_utime, &to->si_utime);
470 err |= __put_user(from->si_stime, &to->si_stime);
471 err |= __put_user(from->si_status, &to->si_status);
472 default:
473 err |= __put_user(from->si_pid, &to->si_pid);
474 err |= __put_user(from->si_uid, &to->si_uid);
475 break;
476 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900477 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 break;
479 case __SI_POLL >> 16:
480 err |= __put_user(from->si_band, &to->si_band);
481 err |= __put_user(from->si_fd, &to->si_fd);
482 break;
483 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
484 case __SI_MESGQ >> 16:
485 err |= __put_user(from->si_pid, &to->si_pid);
486 err |= __put_user(from->si_uid, &to->si_uid);
487 err |= __put_user(from->si_int, &to->si_int);
488 break;
489 }
490 }
491 return err;
492}
493
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100494asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900496 struct sigframe __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 sigset_t blocked;
498
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900499 frame = (struct sigframe __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
501 goto badframe;
502 if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
503 goto badframe;
504
505 sigdelsetmask(&blocked, ~_BLOCKABLE);
506 spin_lock_irq(&current->sighand->siglock);
507 current->blocked = blocked;
508 recalc_sigpending();
509 spin_unlock_irq(&current->sighand->siglock);
510
511 if (restore_sigcontext32(&regs, &frame->sf_sc))
512 goto badframe;
513
514 /*
515 * Don't let your children do this ...
516 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 __asm__ __volatile__(
518 "move\t$29, %0\n\t"
519 "j\tsyscall_exit"
520 :/* no outputs */
521 :"r" (&regs));
522 /* Unreached */
523
524badframe:
525 force_sig(SIGSEGV, current);
526}
527
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100528asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900530 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000531 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 sigset_t set;
533 stack_t st;
534 s32 sp;
535
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900536 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
538 goto badframe;
539 if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
540 goto badframe;
541
542 sigdelsetmask(&set, ~_BLOCKABLE);
543 spin_lock_irq(&current->sighand->siglock);
544 current->blocked = set;
545 recalc_sigpending();
546 spin_unlock_irq(&current->sighand->siglock);
547
548 if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
549 goto badframe;
550
551 /* The ucontext contains a stack32_t, so we must convert! */
552 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
553 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900554 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
556 goto badframe;
557 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
558 goto badframe;
559
560 /* It is more difficult to avoid calling this function than to
561 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000562 old_fs = get_fs();
563 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900564 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000565 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 /*
568 * Don't let your children do this ...
569 */
570 __asm__ __volatile__(
571 "move\t$29, %0\n\t"
572 "j\tsyscall_exit"
573 :/* no outputs */
574 :"r" (&regs));
575 /* Unreached */
576
577badframe:
578 force_sig(SIGSEGV, current);
579}
580
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900581int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
582 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900584 struct sigframe __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 int err = 0;
586
587 frame = get_sigframe(ka, regs, sizeof(*frame));
588 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
589 goto give_sigsegv;
590
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100591 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 err |= setup_sigcontext32(regs, &frame->sf_sc);
594 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
595 if (err)
596 goto give_sigsegv;
597
598 /*
599 * Arguments to signal handler:
600 *
601 * a0 = signal number
602 * a1 = 0 (should be cause)
603 * a2 = pointer to struct sigcontext
604 *
605 * $25 and c0_epc point to the signal handler, $29 points to the
606 * struct sigframe.
607 */
608 regs->regs[ 4] = signr;
609 regs->regs[ 5] = 0;
610 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
611 regs->regs[29] = (unsigned long) frame;
612 regs->regs[31] = (unsigned long) frame->sf_code;
613 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
614
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100615 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100617 frame, regs->cp0_epc, regs->regs[31]);
618
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000619 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621give_sigsegv:
622 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000623 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624}
625
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900626int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
627 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900629 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 int err = 0;
631 s32 sp;
632
633 frame = get_sigframe(ka, regs, sizeof(*frame));
634 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
635 goto give_sigsegv;
636
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100637 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
640 err |= copy_siginfo_to_user32(&frame->rs_info, info);
641
642 /* Create the ucontext. */
643 err |= __put_user(0, &frame->rs_uc.uc_flags);
644 err |= __put_user(0, &frame->rs_uc.uc_link);
645 sp = (int) (long) current->sas_ss_sp;
646 err |= __put_user(sp,
647 &frame->rs_uc.uc_stack.ss_sp);
648 err |= __put_user(sas_ss_flags(regs->regs[29]),
649 &frame->rs_uc.uc_stack.ss_flags);
650 err |= __put_user(current->sas_ss_size,
651 &frame->rs_uc.uc_stack.ss_size);
652 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
653 err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
654
655 if (err)
656 goto give_sigsegv;
657
658 /*
659 * Arguments to signal handler:
660 *
661 * a0 = signal number
662 * a1 = 0 (should be cause)
663 * a2 = pointer to ucontext
664 *
665 * $25 and c0_epc point to the signal handler, $29 points to
666 * the struct rt_sigframe32.
667 */
668 regs->regs[ 4] = signr;
669 regs->regs[ 5] = (unsigned long) &frame->rs_info;
670 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
671 regs->regs[29] = (unsigned long) frame;
672 regs->regs[31] = (unsigned long) frame->rs_code;
673 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
674
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100675 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100677 frame, regs->cp0_epc, regs->regs[31]);
678
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000679 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681give_sigsegv:
682 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000683 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000686static inline int handle_signal(unsigned long sig, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
688{
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000689 int ret;
690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 switch (regs->regs[0]) {
692 case ERESTART_RESTARTBLOCK:
693 case ERESTARTNOHAND:
694 regs->regs[2] = EINTR;
695 break;
696 case ERESTARTSYS:
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000697 if (!(ka->sa.sa_flags & SA_RESTART)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 regs->regs[2] = EINTR;
699 break;
700 }
701 /* fallthrough */
702 case ERESTARTNOINTR: /* Userland will reload $v0. */
703 regs->regs[7] = regs->regs[26];
704 regs->cp0_epc -= 8;
705 }
706
707 regs->regs[0] = 0; /* Don't deal with this again. */
708
709 if (ka->sa.sa_flags & SA_SIGINFO)
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000710 ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 else
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000712 ret = current->thread.abi->setup_frame(ka, regs, sig, oldset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Steven Rostedt69be8f12005-08-29 11:44:09 -0400714 spin_lock_irq(&current->sighand->siglock);
715 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
716 if (!(ka->sa.sa_flags & SA_NODEFER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 sigaddset(&current->blocked,sig);
Steven Rostedt69be8f12005-08-29 11:44:09 -0400718 recalc_sigpending();
719 spin_unlock_irq(&current->sighand->siglock);
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000720
721 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722}
723
Martin Michlmayrdda73d02006-02-18 15:21:30 +0000724void do_signal32(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
726 struct k_sigaction ka;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000727 sigset_t *oldset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 siginfo_t info;
729 int signr;
730
731 /*
732 * We want the common case to go fast, which is why we may in certain
733 * cases get here from kernel mode. Just return without doing anything
734 * if so.
735 */
736 if (!user_mode(regs))
Martin Michlmayrdda73d02006-02-18 15:21:30 +0000737 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000739 if (test_thread_flag(TIF_RESTORE_SIGMASK))
740 oldset = &current->saved_sigmask;
741 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 oldset = &current->blocked;
743
744 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000745 if (signr > 0) {
746 /* Whee! Actually deliver the signal. */
747 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
748 /*
749 * A signal was successfully delivered; the saved
750 * sigmask will have been stored in the signal frame,
751 * and will be restored by sigreturn, so we can simply
752 * clear the TIF_RESTORE_SIGMASK flag.
753 */
754 if (test_thread_flag(TIF_RESTORE_SIGMASK))
755 clear_thread_flag(TIF_RESTORE_SIGMASK);
756 }
Ralf Baechle45887e12006-08-03 21:54:13 +0100757
758 return;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 /*
762 * Who's code doesn't conform to the restartable syscall convention
763 * dies here!!! The li instruction, a single machine instruction,
764 * must directly be followed by the syscall instruction.
765 */
766 if (regs->regs[0]) {
767 if (regs->regs[2] == ERESTARTNOHAND ||
768 regs->regs[2] == ERESTARTSYS ||
769 regs->regs[2] == ERESTARTNOINTR) {
770 regs->regs[7] = regs->regs[26];
771 regs->cp0_epc -= 8;
772 }
773 if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
774 regs->regs[2] = __NR_O32_restart_syscall;
775 regs->regs[7] = regs->regs[26];
776 regs->cp0_epc -= 4;
777 }
Ralf Baechle13fdd312006-08-08 03:47:01 +0100778 regs->regs[0] = 0; /* Don't deal with this again. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000780
781 /*
782 * If there's no signal to deliver, we just put the saved sigmask
783 * back
784 */
785 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
786 clear_thread_flag(TIF_RESTORE_SIGMASK);
787 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789}
790
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900791asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900792 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 unsigned int sigsetsize)
794{
795 struct k_sigaction new_sa, old_sa;
796 int ret = -EINVAL;
797
798 /* XXX: Don't preclude handling different sized sigset_t's. */
799 if (sigsetsize != sizeof(sigset_t))
800 goto out;
801
802 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000803 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 int err = 0;
805
806 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
807 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000808 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900809 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
811 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
812 if (err)
813 return -EFAULT;
814 }
815
816 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
817
818 if (!ret && oact) {
819 int err = 0;
820
821 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
822 return -EFAULT;
823
824 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
825 &oact->sa_handler);
826 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
827 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
828 if (err)
829 return -EFAULT;
830 }
831out:
832 return ret;
833}
834
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900835asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900836 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
838 sigset_t old_set, new_set;
839 int ret;
840 mm_segment_t old_fs = get_fs();
841
842 if (set && get_sigset(&new_set, set))
843 return -EFAULT;
844
845 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900846 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
847 oset ? (sigset_t __user *)&old_set : NULL,
848 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 set_fs (old_fs);
850
851 if (!ret && oset && put_sigset(&old_set, oset))
852 return -EFAULT;
853
854 return ret;
855}
856
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900857asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 unsigned int sigsetsize)
859{
860 int ret;
861 sigset_t set;
862 mm_segment_t old_fs = get_fs();
863
864 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900865 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 set_fs (old_fs);
867
868 if (!ret && put_sigset(&set, uset))
869 return -EFAULT;
870
871 return ret;
872}
873
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900874asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 siginfo_t info;
877 int ret;
878 mm_segment_t old_fs = get_fs();
879
880 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
881 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
882 return -EFAULT;
883 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900884 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 set_fs (old_fs);
886 return ret;
887}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000888
889asmlinkage long
890sys32_waitid(int which, compat_pid_t pid,
891 compat_siginfo_t __user *uinfo, int options,
892 struct compat_rusage __user *uru)
893{
894 siginfo_t info;
895 struct rusage ru;
896 long ret;
897 mm_segment_t old_fs = get_fs();
898
899 info.si_signo = 0;
900 set_fs (KERNEL_DS);
901 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
902 uru ? (struct rusage __user *) &ru : NULL);
903 set_fs (old_fs);
904
905 if (ret < 0 || info.si_signo == 0)
906 return ret;
907
908 if (uru && (ret = put_compat_rusage(&ru, uru)))
909 return ret;
910
911 BUG_ON(info.si_code & __SI_MASK);
912 info.si_code |= __SI_CHLD;
913 return copy_siginfo_to_user32(uinfo, &info);
914}