blob: 1a99a57739e1a2f97cc257532fa565fb1ee3c25a [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163extern void __put_sigset_unknown_nsig(void);
164extern void __get_sigset_unknown_nsig(void);
165
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900166static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
168 int err = 0;
169
170 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
171 return -EFAULT;
172
173 switch (_NSIG_WORDS) {
174 default:
175 __put_sigset_unknown_nsig();
176 case 2:
177 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
178 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
179 case 1:
180 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
181 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
182 }
183
184 return err;
185}
186
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900187static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
189 int err = 0;
190 unsigned long sig[4];
191
192 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
193 return -EFAULT;
194
195 switch (_NSIG_WORDS) {
196 default:
197 __get_sigset_unknown_nsig();
198 case 2:
199 err |= __get_user (sig[3], &ubuf->sig[3]);
200 err |= __get_user (sig[2], &ubuf->sig[2]);
201 kbuf->sig[1] = sig[2] | (sig[3] << 32);
202 case 1:
203 err |= __get_user (sig[1], &ubuf->sig[1]);
204 err |= __get_user (sig[0], &ubuf->sig[0]);
205 kbuf->sig[0] = sig[0] | (sig[1] << 32);
206 }
207
208 return err;
209}
210
211/*
212 * Atomically swap in the new signal mask, and wait for a signal.
213 */
214
215save_static_function(sys32_sigsuspend);
216__attribute_used__ noinline static int
217_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
218{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900219 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000220 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900222 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 if (get_sigset(&newset, uset))
224 return -EFAULT;
225 sigdelsetmask(&newset, ~_BLOCKABLE);
226
227 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000228 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 current->blocked = newset;
230 recalc_sigpending();
231 spin_unlock_irq(&current->sighand->siglock);
232
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000233 current->state = TASK_INTERRUPTIBLE;
234 schedule();
235 set_thread_flag(TIF_RESTORE_SIGMASK);
236 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
238
239save_static_function(sys32_rt_sigsuspend);
240__attribute_used__ noinline static int
241_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
242{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900243 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000244 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000245 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 /* XXX Don't preclude handling different sized sigset_t's. */
248 sigsetsize = regs.regs[5];
249 if (sigsetsize != sizeof(compat_sigset_t))
250 return -EINVAL;
251
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900252 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 if (get_sigset(&newset, uset))
254 return -EFAULT;
255 sigdelsetmask(&newset, ~_BLOCKABLE);
256
257 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000258 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000260 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 spin_unlock_irq(&current->sighand->siglock);
262
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000263 current->state = TASK_INTERRUPTIBLE;
264 schedule();
265 set_thread_flag(TIF_RESTORE_SIGMASK);
266 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267}
268
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900269asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
270 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
272 struct k_sigaction new_ka, old_ka;
273 int ret;
274 int err = 0;
275
276 if (act) {
277 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000278 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
281 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000282 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900283 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
285 err |= __get_user(mask, &act->sa_mask.sig[0]);
286 if (err)
287 return -EFAULT;
288
289 siginitset(&new_ka.sa.sa_mask, mask);
290 }
291
292 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
293
294 if (!ret && oact) {
295 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000296 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
298 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
299 &oact->sa_handler);
300 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000301 err |= __put_user(0, &oact->sa_mask.sig[1]);
302 err |= __put_user(0, &oact->sa_mask.sig[2]);
303 err |= __put_user(0, &oact->sa_mask.sig[3]);
304 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return -EFAULT;
306 }
307
308 return ret;
309}
310
311asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
312{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900313 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
314 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 unsigned long usp = regs.regs[29];
316 stack_t kss, koss;
317 int ret, err = 0;
318 mm_segment_t old_fs = get_fs();
319 s32 sp;
320
321 if (uss) {
322 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
323 return -EFAULT;
324 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900325 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 err |= __get_user(kss.ss_size, &uss->ss_size);
327 err |= __get_user(kss.ss_flags, &uss->ss_flags);
328 if (err)
329 return -EFAULT;
330 }
331
332 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900333 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
334 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 set_fs (old_fs);
336
337 if (!ret && uoss) {
338 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
339 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900340 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 err |= __put_user(sp, &uoss->ss_sp);
342 err |= __put_user(koss.ss_size, &uoss->ss_size);
343 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
344 if (err)
345 return -EFAULT;
346 }
347 return ret;
348}
349
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900350static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000352 u32 used_math;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 int err = 0;
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000354 s32 treg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /* Always make any pending restarted system calls return -EINTR */
357 current_thread_info()->restart_block.fn = do_no_restart_syscall;
358
359 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
360 err |= __get_user(regs->hi, &sc->sc_mdhi);
361 err |= __get_user(regs->lo, &sc->sc_mdlo);
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000362 if (cpu_has_dsp) {
363 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
364 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
365 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
366 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
367 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
368 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
369 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372#define restore_gp_reg(i) do { \
373 err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \
374} while(0)
375 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
376 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
377 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
378 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
379 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
380 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
381 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
382 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
383 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
384 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
385 restore_gp_reg(31);
386#undef restore_gp_reg
387
388 err |= __get_user(used_math, &sc->sc_used_math);
389 conditional_used_math(used_math);
390
391 preempt_disable();
392
393 if (used_math()) {
394 /* restore fpu context if we have used it before */
395 own_fpu();
396 err |= restore_fp_context32(sc);
397 } else {
398 /* signal handler may have used FPU. Give it up. */
399 lose_fpu();
400 }
401
402 preempt_enable();
403
404 return err;
405}
406
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900407int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int err;
410
411 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
412 return -EFAULT;
413
414 /* If you change siginfo_t structure, please be sure
415 this code is fixed accordingly.
416 It should never copy any pad contained in the structure
417 to avoid security leaks, but must copy the generic
418 3 ints plus the relevant union member.
419 This routine must convert siginfo from 64bit to 32bit as well
420 at the same time. */
421 err = __put_user(from->si_signo, &to->si_signo);
422 err |= __put_user(from->si_errno, &to->si_errno);
423 err |= __put_user((short)from->si_code, &to->si_code);
424 if (from->si_code < 0)
425 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
426 else {
427 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000428 case __SI_TIMER >> 16:
429 err |= __put_user(from->si_tid, &to->si_tid);
430 err |= __put_user(from->si_overrun, &to->si_overrun);
431 err |= __put_user(from->si_int, &to->si_int);
432 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 case __SI_CHLD >> 16:
434 err |= __put_user(from->si_utime, &to->si_utime);
435 err |= __put_user(from->si_stime, &to->si_stime);
436 err |= __put_user(from->si_status, &to->si_status);
437 default:
438 err |= __put_user(from->si_pid, &to->si_pid);
439 err |= __put_user(from->si_uid, &to->si_uid);
440 break;
441 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900442 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 break;
444 case __SI_POLL >> 16:
445 err |= __put_user(from->si_band, &to->si_band);
446 err |= __put_user(from->si_fd, &to->si_fd);
447 break;
448 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
449 case __SI_MESGQ >> 16:
450 err |= __put_user(from->si_pid, &to->si_pid);
451 err |= __put_user(from->si_uid, &to->si_uid);
452 err |= __put_user(from->si_int, &to->si_int);
453 break;
454 }
455 }
456 return err;
457}
458
459save_static_function(sys32_sigreturn);
460__attribute_used__ noinline static void
461_sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
462{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900463 struct sigframe __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 sigset_t blocked;
465
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900466 frame = (struct sigframe __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
468 goto badframe;
469 if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
470 goto badframe;
471
472 sigdelsetmask(&blocked, ~_BLOCKABLE);
473 spin_lock_irq(&current->sighand->siglock);
474 current->blocked = blocked;
475 recalc_sigpending();
476 spin_unlock_irq(&current->sighand->siglock);
477
478 if (restore_sigcontext32(&regs, &frame->sf_sc))
479 goto badframe;
480
481 /*
482 * Don't let your children do this ...
483 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 __asm__ __volatile__(
485 "move\t$29, %0\n\t"
486 "j\tsyscall_exit"
487 :/* no outputs */
488 :"r" (&regs));
489 /* Unreached */
490
491badframe:
492 force_sig(SIGSEGV, current);
493}
494
495save_static_function(sys32_rt_sigreturn);
496__attribute_used__ noinline static void
497_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
498{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900499 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000500 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 sigset_t set;
502 stack_t st;
503 s32 sp;
504
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900505 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
507 goto badframe;
508 if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
509 goto badframe;
510
511 sigdelsetmask(&set, ~_BLOCKABLE);
512 spin_lock_irq(&current->sighand->siglock);
513 current->blocked = set;
514 recalc_sigpending();
515 spin_unlock_irq(&current->sighand->siglock);
516
517 if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
518 goto badframe;
519
520 /* The ucontext contains a stack32_t, so we must convert! */
521 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
522 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900523 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
525 goto badframe;
526 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
527 goto badframe;
528
529 /* It is more difficult to avoid calling this function than to
530 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000531 old_fs = get_fs();
532 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900533 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000534 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 /*
537 * Don't let your children do this ...
538 */
539 __asm__ __volatile__(
540 "move\t$29, %0\n\t"
541 "j\tsyscall_exit"
542 :/* no outputs */
543 :"r" (&regs));
544 /* Unreached */
545
546badframe:
547 force_sig(SIGSEGV, current);
548}
549
550static inline int setup_sigcontext32(struct pt_regs *regs,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900551 struct sigcontext32 __user *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 int err = 0;
554
555 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
556 err |= __put_user(regs->cp0_status, &sc->sc_status);
557
558#define save_gp_reg(i) { \
559 err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \
560} while(0)
561 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
562 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
563 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
564 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
565 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
566 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
567 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
568 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
569 save_gp_reg(31);
570#undef save_gp_reg
571
572 err |= __put_user(regs->hi, &sc->sc_mdhi);
573 err |= __put_user(regs->lo, &sc->sc_mdlo);
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000574 if (cpu_has_dsp) {
Ralf Baechlec4fa6342005-12-07 17:50:48 +0000575 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
Ralf Baechlee50c0a82005-05-31 11:49:19 +0000576 err |= __put_user(mfhi1(), &sc->sc_hi1);
577 err |= __put_user(mflo1(), &sc->sc_lo1);
578 err |= __put_user(mfhi2(), &sc->sc_hi2);
579 err |= __put_user(mflo2(), &sc->sc_lo2);
580 err |= __put_user(mfhi3(), &sc->sc_hi3);
581 err |= __put_user(mflo3(), &sc->sc_lo3);
582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
584 err |= __put_user(!!used_math(), &sc->sc_used_math);
585
586 if (!used_math())
587 goto out;
588
Ralf Baechle42a3b4f2005-09-03 15:56:17 -0700589 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 * Save FPU state to signal context. Signal handler will "inherit"
591 * current FPU state.
592 */
593 preempt_disable();
594
595 if (!is_fpu_owner()) {
596 own_fpu();
597 restore_fp(current);
598 }
599 err |= save_fp_context32(sc);
600
601 preempt_enable();
602
603out:
604 return err;
605}
606
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900607int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
608 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900610 struct sigframe __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 int err = 0;
612
613 frame = get_sigframe(ka, regs, sizeof(*frame));
614 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
615 goto give_sigsegv;
616
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100617 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 err |= setup_sigcontext32(regs, &frame->sf_sc);
620 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
621 if (err)
622 goto give_sigsegv;
623
624 /*
625 * Arguments to signal handler:
626 *
627 * a0 = signal number
628 * a1 = 0 (should be cause)
629 * a2 = pointer to struct sigcontext
630 *
631 * $25 and c0_epc point to the signal handler, $29 points to the
632 * struct sigframe.
633 */
634 regs->regs[ 4] = signr;
635 regs->regs[ 5] = 0;
636 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
637 regs->regs[29] = (unsigned long) frame;
638 regs->regs[31] = (unsigned long) frame->sf_code;
639 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
640
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100641 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100643 frame, regs->cp0_epc, regs->regs[31]);
644
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000645 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647give_sigsegv:
648 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000649 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900652int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
653 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900655 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 int err = 0;
657 s32 sp;
658
659 frame = get_sigframe(ka, regs, sizeof(*frame));
660 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
661 goto give_sigsegv;
662
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100663 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
666 err |= copy_siginfo_to_user32(&frame->rs_info, info);
667
668 /* Create the ucontext. */
669 err |= __put_user(0, &frame->rs_uc.uc_flags);
670 err |= __put_user(0, &frame->rs_uc.uc_link);
671 sp = (int) (long) current->sas_ss_sp;
672 err |= __put_user(sp,
673 &frame->rs_uc.uc_stack.ss_sp);
674 err |= __put_user(sas_ss_flags(regs->regs[29]),
675 &frame->rs_uc.uc_stack.ss_flags);
676 err |= __put_user(current->sas_ss_size,
677 &frame->rs_uc.uc_stack.ss_size);
678 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
679 err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
680
681 if (err)
682 goto give_sigsegv;
683
684 /*
685 * Arguments to signal handler:
686 *
687 * a0 = signal number
688 * a1 = 0 (should be cause)
689 * a2 = pointer to ucontext
690 *
691 * $25 and c0_epc point to the signal handler, $29 points to
692 * the struct rt_sigframe32.
693 */
694 regs->regs[ 4] = signr;
695 regs->regs[ 5] = (unsigned long) &frame->rs_info;
696 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
697 regs->regs[29] = (unsigned long) frame;
698 regs->regs[31] = (unsigned long) frame->rs_code;
699 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
700
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100701 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100703 frame, regs->cp0_epc, regs->regs[31]);
704
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000705 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707give_sigsegv:
708 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000709 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000712static inline int handle_signal(unsigned long sig, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
714{
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000715 int ret;
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 switch (regs->regs[0]) {
718 case ERESTART_RESTARTBLOCK:
719 case ERESTARTNOHAND:
720 regs->regs[2] = EINTR;
721 break;
722 case ERESTARTSYS:
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000723 if (!(ka->sa.sa_flags & SA_RESTART)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 regs->regs[2] = EINTR;
725 break;
726 }
727 /* fallthrough */
728 case ERESTARTNOINTR: /* Userland will reload $v0. */
729 regs->regs[7] = regs->regs[26];
730 regs->cp0_epc -= 8;
731 }
732
733 regs->regs[0] = 0; /* Don't deal with this again. */
734
735 if (ka->sa.sa_flags & SA_SIGINFO)
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000736 ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 else
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000738 ret = current->thread.abi->setup_frame(ka, regs, sig, oldset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Steven Rostedt69be8f12005-08-29 11:44:09 -0400740 spin_lock_irq(&current->sighand->siglock);
741 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
742 if (!(ka->sa.sa_flags & SA_NODEFER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 sigaddset(&current->blocked,sig);
Steven Rostedt69be8f12005-08-29 11:44:09 -0400744 recalc_sigpending();
745 spin_unlock_irq(&current->sighand->siglock);
Ralf Baechle129bc8f2005-07-11 20:45:51 +0000746
747 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
Martin Michlmayrdda73d02006-02-18 15:21:30 +0000750void do_signal32(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 struct k_sigaction ka;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000753 sigset_t *oldset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 siginfo_t info;
755 int signr;
756
757 /*
758 * We want the common case to go fast, which is why we may in certain
759 * cases get here from kernel mode. Just return without doing anything
760 * if so.
761 */
762 if (!user_mode(regs))
Martin Michlmayrdda73d02006-02-18 15:21:30 +0000763 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000765 if (test_thread_flag(TIF_RESTORE_SIGMASK))
766 oldset = &current->saved_sigmask;
767 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 oldset = &current->blocked;
769
770 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000771 if (signr > 0) {
772 /* Whee! Actually deliver the signal. */
773 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
774 /*
775 * A signal was successfully delivered; the saved
776 * sigmask will have been stored in the signal frame,
777 * and will be restored by sigreturn, so we can simply
778 * clear the TIF_RESTORE_SIGMASK flag.
779 */
780 if (test_thread_flag(TIF_RESTORE_SIGMASK))
781 clear_thread_flag(TIF_RESTORE_SIGMASK);
782 }
Ralf Baechle45887e12006-08-03 21:54:13 +0100783
784 return;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 /*
788 * Who's code doesn't conform to the restartable syscall convention
789 * dies here!!! The li instruction, a single machine instruction,
790 * must directly be followed by the syscall instruction.
791 */
792 if (regs->regs[0]) {
793 if (regs->regs[2] == ERESTARTNOHAND ||
794 regs->regs[2] == ERESTARTSYS ||
795 regs->regs[2] == ERESTARTNOINTR) {
796 regs->regs[7] = regs->regs[26];
797 regs->cp0_epc -= 8;
798 }
799 if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
800 regs->regs[2] = __NR_O32_restart_syscall;
801 regs->regs[7] = regs->regs[26];
802 regs->cp0_epc -= 4;
803 }
Ralf Baechle13fdd312006-08-08 03:47:01 +0100804 regs->regs[0] = 0; /* Don't deal with this again. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 }
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000806
807 /*
808 * If there's no signal to deliver, we just put the saved sigmask
809 * back
810 */
811 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
812 clear_thread_flag(TIF_RESTORE_SIGMASK);
813 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815}
816
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900817asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900818 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 unsigned int sigsetsize)
820{
821 struct k_sigaction new_sa, old_sa;
822 int ret = -EINVAL;
823
824 /* XXX: Don't preclude handling different sized sigset_t's. */
825 if (sigsetsize != sizeof(sigset_t))
826 goto out;
827
828 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000829 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 int err = 0;
831
832 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
833 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000834 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900835 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
837 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
838 if (err)
839 return -EFAULT;
840 }
841
842 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
843
844 if (!ret && oact) {
845 int err = 0;
846
847 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
848 return -EFAULT;
849
850 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
851 &oact->sa_handler);
852 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
853 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
854 if (err)
855 return -EFAULT;
856 }
857out:
858 return ret;
859}
860
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900861asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900862 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
864 sigset_t old_set, new_set;
865 int ret;
866 mm_segment_t old_fs = get_fs();
867
868 if (set && get_sigset(&new_set, set))
869 return -EFAULT;
870
871 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900872 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
873 oset ? (sigset_t __user *)&old_set : NULL,
874 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 set_fs (old_fs);
876
877 if (!ret && oset && put_sigset(&old_set, oset))
878 return -EFAULT;
879
880 return ret;
881}
882
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900883asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 unsigned int sigsetsize)
885{
886 int ret;
887 sigset_t set;
888 mm_segment_t old_fs = get_fs();
889
890 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900891 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 set_fs (old_fs);
893
894 if (!ret && put_sigset(&set, uset))
895 return -EFAULT;
896
897 return ret;
898}
899
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900900asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 siginfo_t info;
903 int ret;
904 mm_segment_t old_fs = get_fs();
905
906 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
907 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
908 return -EFAULT;
909 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900910 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 set_fs (old_fs);
912 return ret;
913}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000914
915asmlinkage long
916sys32_waitid(int which, compat_pid_t pid,
917 compat_siginfo_t __user *uinfo, int options,
918 struct compat_rusage __user *uru)
919{
920 siginfo_t info;
921 struct rusage ru;
922 long ret;
923 mm_segment_t old_fs = get_fs();
924
925 info.si_signo = 0;
926 set_fs (KERNEL_DS);
927 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
928 uru ? (struct rusage __user *) &ru : NULL);
929 set_fs (old_fs);
930
931 if (ret < 0 || info.si_signo == 0)
932 return ret;
933
934 if (uru && (ret = put_compat_rusage(&ru, uru)))
935 return ret;
936
937 BUG_ON(info.si_code & __SI_MASK);
938 info.si_code |= __SI_CHLD;
939 return copy_siginfo_to_user32(uinfo, &info);
940}