blob: 20013b6fe7251da0ae0ce048ed2acd14726e0044 [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>
Ralf Baechle431dc802007-02-13 00:05:11 +000011#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/sched.h>
13#include <linux/mm.h>
14#include <linux/smp.h>
15#include <linux/smp_lock.h>
16#include <linux/kernel.h>
17#include <linux/signal.h>
18#include <linux/syscalls.h>
19#include <linux/errno.h>
20#include <linux/wait.h>
21#include <linux/ptrace.h>
22#include <linux/compat.h>
23#include <linux/suspend.h>
24#include <linux/compiler.h>
25
Ralf Baechlee50c0a82005-05-31 11:49:19 +000026#include <asm/abi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/asm.h>
Ralf Baechle431dc802007-02-13 00:05:11 +000028#include <asm/compat-signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/bitops.h>
30#include <asm/cacheflush.h>
31#include <asm/sim.h>
32#include <asm/uaccess.h>
33#include <asm/ucontext.h>
34#include <asm/system.h>
35#include <asm/fpu.h>
Ralf Baechle02416dc2005-06-15 13:00:12 +000036#include <asm/war.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +010038#include "signal-common.h"
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
41
42typedef struct compat_siginfo {
43 int si_signo;
44 int si_code;
45 int si_errno;
46
47 union {
48 int _pad[SI_PAD_SIZE32];
49
50 /* kill() */
51 struct {
52 compat_pid_t _pid; /* sender's pid */
53 compat_uid_t _uid; /* sender's uid */
54 } _kill;
55
56 /* SIGCHLD */
57 struct {
58 compat_pid_t _pid; /* which child */
59 compat_uid_t _uid; /* sender's uid */
60 int _status; /* exit code */
61 compat_clock_t _utime;
62 compat_clock_t _stime;
63 } _sigchld;
64
65 /* IRIX SIGCHLD */
66 struct {
67 compat_pid_t _pid; /* which child */
68 compat_clock_t _utime;
69 int _status; /* exit code */
70 compat_clock_t _stime;
71 } _irix_sigchld;
72
73 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
74 struct {
75 s32 _addr; /* faulting insn/memory ref. */
76 } _sigfault;
77
78 /* SIGPOLL, SIGXFSZ (To do ...) */
79 struct {
80 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
81 int _fd;
82 } _sigpoll;
83
84 /* POSIX.1b timers */
85 struct {
Ralf Baechlea9820992005-02-16 21:24:16 +000086 timer_t _tid; /* timer id */
87 int _overrun; /* overrun count */
Ralf Baechle209ac8d2005-03-18 17:36:42 +000088 compat_sigval_t _sigval;/* same as below */
Ralf Baechlea9820992005-02-16 21:24:16 +000089 int _sys_private; /* not to be passed to user */
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 } _timer;
91
92 /* POSIX.1b signals */
93 struct {
94 compat_pid_t _pid; /* sender's pid */
95 compat_uid_t _uid; /* sender's uid */
96 compat_sigval_t _sigval;
97 } _rt;
98
99 } _sifields;
100} compat_siginfo_t;
101
102/*
103 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
104 */
105#define __NR_O32_sigreturn 4119
106#define __NR_O32_rt_sigreturn 4193
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000107#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/* 32-bit compatibility types */
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111typedef unsigned int __sighandler32_t;
112typedef void (*vfptr_t)(void);
113
114struct sigaction32 {
115 unsigned int sa_flags;
116 __sighandler32_t sa_handler;
117 compat_sigset_t sa_mask;
118};
119
120/* IRIX compatible stack_t */
121typedef struct sigaltstack32 {
122 s32 ss_sp;
123 compat_size_t ss_size;
124 int ss_flags;
125} stack32_t;
126
127struct ucontext32 {
128 u32 uc_flags;
129 s32 uc_link;
130 stack32_t uc_stack;
131 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +0000132 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133};
134
Ralf Baechledd02f062007-02-13 00:50:57 +0000135/*
136 * Horribly complicated - with the bloody RM9000 workarounds enabled
137 * the signal trampolines is moving to the end of the structure so we can
138 * increase the alignment without breaking software compatibility.
139 */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100140#if ICACHE_REFILLS_WORKAROUND_WAR == 0
141
Ralf Baechledd02f062007-02-13 00:50:57 +0000142struct sigframe32 {
143 u32 sf_ass[4]; /* argument save space for o32 */
144 u32 sf_code[2]; /* signal trampoline */
145 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +0900146 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +0000147};
148
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100149struct rt_sigframe32 {
150 u32 rs_ass[4]; /* argument save space for o32 */
151 u32 rs_code[2]; /* signal trampoline */
152 compat_siginfo_t rs_info;
153 struct ucontext32 rs_uc;
154};
155
156#else /* ICACHE_REFILLS_WORKAROUND_WAR */
157
Ralf Baechledd02f062007-02-13 00:50:57 +0000158struct sigframe32 {
159 u32 sf_ass[4]; /* argument save space for o32 */
160 u32 sf_pad[2];
161 struct sigcontext32 sf_sc; /* hw context */
Atsushi Nemoto755f21b2007-02-14 14:41:01 +0900162 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +0000163 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
164};
165
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100166struct rt_sigframe32 {
167 u32 rs_ass[4]; /* argument save space for o32 */
168 u32 rs_pad[2];
169 compat_siginfo_t rs_info;
170 struct ucontext32 rs_uc;
171 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
172};
173
174#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
175
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100176/*
177 * sigcontext handlers
178 */
179static int setup_sigcontext32(struct pt_regs *regs,
180 struct sigcontext32 __user *sc)
181{
182 int err = 0;
183 int i;
184
185 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100186
187 err |= __put_user(0, &sc->sc_regs[0]);
188 for (i = 1; i < 32; i++)
189 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
190
191 err |= __put_user(regs->hi, &sc->sc_mdhi);
192 err |= __put_user(regs->lo, &sc->sc_mdlo);
193 if (cpu_has_dsp) {
194 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
195 err |= __put_user(mfhi1(), &sc->sc_hi1);
196 err |= __put_user(mflo1(), &sc->sc_lo1);
197 err |= __put_user(mfhi2(), &sc->sc_hi2);
198 err |= __put_user(mflo2(), &sc->sc_lo2);
199 err |= __put_user(mfhi3(), &sc->sc_hi3);
200 err |= __put_user(mflo3(), &sc->sc_lo3);
201 }
202
203 err |= __put_user(!!used_math(), &sc->sc_used_math);
204
205 if (used_math()) {
206 /*
207 * Save FPU state to signal context. Signal handler
208 * will "inherit" current FPU state.
209 */
210 preempt_disable();
211
212 if (!is_fpu_owner()) {
213 own_fpu();
214 restore_fp(current);
215 }
216 err |= save_fp_context32(sc);
217
218 preempt_enable();
219 }
220 return err;
221}
222
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900223static int
224check_and_restore_fp_context32(struct sigcontext32 __user *sc)
225{
226 int err, sig;
227
228 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
229 if (err > 0)
230 err = 0;
231 err |= restore_fp_context32(sc);
232 return err ?: sig;
233}
234
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100235static int restore_sigcontext32(struct pt_regs *regs,
236 struct sigcontext32 __user *sc)
237{
238 u32 used_math;
239 int err = 0;
240 s32 treg;
241 int i;
242
243 /* Always make any pending restarted system calls return -EINTR */
244 current_thread_info()->restart_block.fn = do_no_restart_syscall;
245
246 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
247 err |= __get_user(regs->hi, &sc->sc_mdhi);
248 err |= __get_user(regs->lo, &sc->sc_mdlo);
249 if (cpu_has_dsp) {
250 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
251 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
252 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
253 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
254 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
255 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
256 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
257 }
258
259 for (i = 1; i < 32; i++)
260 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
261
262 err |= __get_user(used_math, &sc->sc_used_math);
263 conditional_used_math(used_math);
264
265 preempt_disable();
266
267 if (used_math()) {
268 /* restore fpu context if we have used it before */
269 own_fpu();
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900270 if (!err)
271 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100272 } else {
273 /* signal handler may have used FPU. Give it up. */
274 lose_fpu();
275 }
276
277 preempt_enable();
278
279 return err;
280}
281
282/*
283 *
284 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285extern void __put_sigset_unknown_nsig(void);
286extern void __get_sigset_unknown_nsig(void);
287
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900288static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 int err = 0;
291
292 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
293 return -EFAULT;
294
295 switch (_NSIG_WORDS) {
296 default:
297 __put_sigset_unknown_nsig();
298 case 2:
299 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
300 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
301 case 1:
302 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
303 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
304 }
305
306 return err;
307}
308
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900309static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 int err = 0;
312 unsigned long sig[4];
313
314 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
315 return -EFAULT;
316
317 switch (_NSIG_WORDS) {
318 default:
319 __get_sigset_unknown_nsig();
320 case 2:
321 err |= __get_user (sig[3], &ubuf->sig[3]);
322 err |= __get_user (sig[2], &ubuf->sig[2]);
323 kbuf->sig[1] = sig[2] | (sig[3] << 32);
324 case 1:
325 err |= __get_user (sig[1], &ubuf->sig[1]);
326 err |= __get_user (sig[0], &ubuf->sig[0]);
327 kbuf->sig[0] = sig[0] | (sig[1] << 32);
328 }
329
330 return err;
331}
332
333/*
334 * Atomically swap in the new signal mask, and wait for a signal.
335 */
336
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100337asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900339 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000340 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900342 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 if (get_sigset(&newset, uset))
344 return -EFAULT;
345 sigdelsetmask(&newset, ~_BLOCKABLE);
346
347 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000348 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 current->blocked = newset;
350 recalc_sigpending();
351 spin_unlock_irq(&current->sighand->siglock);
352
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000353 current->state = TASK_INTERRUPTIBLE;
354 schedule();
355 set_thread_flag(TIF_RESTORE_SIGMASK);
356 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357}
358
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100359asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900361 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000362 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000363 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 /* XXX Don't preclude handling different sized sigset_t's. */
366 sigsetsize = regs.regs[5];
367 if (sigsetsize != sizeof(compat_sigset_t))
368 return -EINVAL;
369
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900370 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 if (get_sigset(&newset, uset))
372 return -EFAULT;
373 sigdelsetmask(&newset, ~_BLOCKABLE);
374
375 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000376 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000378 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 spin_unlock_irq(&current->sighand->siglock);
380
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000381 current->state = TASK_INTERRUPTIBLE;
382 schedule();
383 set_thread_flag(TIF_RESTORE_SIGMASK);
384 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900387asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
388 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389{
390 struct k_sigaction new_ka, old_ka;
391 int ret;
392 int err = 0;
393
394 if (act) {
395 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000396 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
399 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000400 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900401 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
403 err |= __get_user(mask, &act->sa_mask.sig[0]);
404 if (err)
405 return -EFAULT;
406
407 siginitset(&new_ka.sa.sa_mask, mask);
408 }
409
410 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
411
412 if (!ret && oact) {
413 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000414 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
416 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
417 &oact->sa_handler);
418 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000419 err |= __put_user(0, &oact->sa_mask.sig[1]);
420 err |= __put_user(0, &oact->sa_mask.sig[2]);
421 err |= __put_user(0, &oact->sa_mask.sig[3]);
422 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return -EFAULT;
424 }
425
426 return ret;
427}
428
429asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
430{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900431 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
432 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 unsigned long usp = regs.regs[29];
434 stack_t kss, koss;
435 int ret, err = 0;
436 mm_segment_t old_fs = get_fs();
437 s32 sp;
438
439 if (uss) {
440 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
441 return -EFAULT;
442 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900443 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 err |= __get_user(kss.ss_size, &uss->ss_size);
445 err |= __get_user(kss.ss_flags, &uss->ss_flags);
446 if (err)
447 return -EFAULT;
448 }
449
450 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900451 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
452 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 set_fs (old_fs);
454
455 if (!ret && uoss) {
456 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
457 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900458 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 err |= __put_user(sp, &uoss->ss_sp);
460 err |= __put_user(koss.ss_size, &uoss->ss_size);
461 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
462 if (err)
463 return -EFAULT;
464 }
465 return ret;
466}
467
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900468int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
470 int err;
471
472 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
473 return -EFAULT;
474
475 /* If you change siginfo_t structure, please be sure
476 this code is fixed accordingly.
477 It should never copy any pad contained in the structure
478 to avoid security leaks, but must copy the generic
479 3 ints plus the relevant union member.
480 This routine must convert siginfo from 64bit to 32bit as well
481 at the same time. */
482 err = __put_user(from->si_signo, &to->si_signo);
483 err |= __put_user(from->si_errno, &to->si_errno);
484 err |= __put_user((short)from->si_code, &to->si_code);
485 if (from->si_code < 0)
486 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
487 else {
488 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000489 case __SI_TIMER >> 16:
490 err |= __put_user(from->si_tid, &to->si_tid);
491 err |= __put_user(from->si_overrun, &to->si_overrun);
492 err |= __put_user(from->si_int, &to->si_int);
493 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 case __SI_CHLD >> 16:
495 err |= __put_user(from->si_utime, &to->si_utime);
496 err |= __put_user(from->si_stime, &to->si_stime);
497 err |= __put_user(from->si_status, &to->si_status);
498 default:
499 err |= __put_user(from->si_pid, &to->si_pid);
500 err |= __put_user(from->si_uid, &to->si_uid);
501 break;
502 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900503 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 break;
505 case __SI_POLL >> 16:
506 err |= __put_user(from->si_band, &to->si_band);
507 err |= __put_user(from->si_fd, &to->si_fd);
508 break;
509 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
510 case __SI_MESGQ >> 16:
511 err |= __put_user(from->si_pid, &to->si_pid);
512 err |= __put_user(from->si_uid, &to->si_uid);
513 err |= __put_user(from->si_int, &to->si_int);
514 break;
515 }
516 }
517 return err;
518}
519
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100520asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Ralf Baechledd02f062007-02-13 00:50:57 +0000522 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900524 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Ralf Baechledd02f062007-02-13 00:50:57 +0000526 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
528 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000529 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 goto badframe;
531
532 sigdelsetmask(&blocked, ~_BLOCKABLE);
533 spin_lock_irq(&current->sighand->siglock);
534 current->blocked = blocked;
535 recalc_sigpending();
536 spin_unlock_irq(&current->sighand->siglock);
537
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900538 sig = restore_sigcontext32(&regs, &frame->sf_sc);
539 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900541 else if (sig)
542 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 /*
545 * Don't let your children do this ...
546 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 __asm__ __volatile__(
548 "move\t$29, %0\n\t"
549 "j\tsyscall_exit"
550 :/* no outputs */
551 :"r" (&regs));
552 /* Unreached */
553
554badframe:
555 force_sig(SIGSEGV, current);
556}
557
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100558asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900560 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000561 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 sigset_t set;
563 stack_t st;
564 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900565 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900567 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
569 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000570 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 goto badframe;
572
573 sigdelsetmask(&set, ~_BLOCKABLE);
574 spin_lock_irq(&current->sighand->siglock);
575 current->blocked = set;
576 recalc_sigpending();
577 spin_unlock_irq(&current->sighand->siglock);
578
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900579 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
580 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900582 else if (sig)
583 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585 /* The ucontext contains a stack32_t, so we must convert! */
586 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
587 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900588 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
590 goto badframe;
591 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
592 goto badframe;
593
594 /* It is more difficult to avoid calling this function than to
595 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000596 old_fs = get_fs();
597 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900598 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000599 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 /*
602 * Don't let your children do this ...
603 */
604 __asm__ __volatile__(
605 "move\t$29, %0\n\t"
606 "j\tsyscall_exit"
607 :/* no outputs */
608 :"r" (&regs));
609 /* Unreached */
610
611badframe:
612 force_sig(SIGSEGV, current);
613}
614
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000615static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900616 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
Ralf Baechledd02f062007-02-13 00:50:57 +0000618 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 int err = 0;
620
621 frame = get_sigframe(ka, regs, sizeof(*frame));
622 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
623 goto give_sigsegv;
624
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100625 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000628 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 if (err)
631 goto give_sigsegv;
632
633 /*
634 * Arguments to signal handler:
635 *
636 * a0 = signal number
637 * a1 = 0 (should be cause)
638 * a2 = pointer to struct sigcontext
639 *
640 * $25 and c0_epc point to the signal handler, $29 points to the
641 * struct sigframe.
642 */
643 regs->regs[ 4] = signr;
644 regs->regs[ 5] = 0;
645 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
646 regs->regs[29] = (unsigned long) frame;
647 regs->regs[31] = (unsigned long) frame->sf_code;
648 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
649
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100650 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100652 frame, regs->cp0_epc, regs->regs[31]);
653
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000654 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656give_sigsegv:
657 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000658 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659}
660
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000661static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900662 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900664 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 int err = 0;
666 s32 sp;
667
668 frame = get_sigframe(ka, regs, sizeof(*frame));
669 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
670 goto give_sigsegv;
671
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100672 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
675 err |= copy_siginfo_to_user32(&frame->rs_info, info);
676
677 /* Create the ucontext. */
678 err |= __put_user(0, &frame->rs_uc.uc_flags);
679 err |= __put_user(0, &frame->rs_uc.uc_link);
680 sp = (int) (long) current->sas_ss_sp;
681 err |= __put_user(sp,
682 &frame->rs_uc.uc_stack.ss_sp);
683 err |= __put_user(sas_ss_flags(regs->regs[29]),
684 &frame->rs_uc.uc_stack.ss_flags);
685 err |= __put_user(current->sas_ss_size,
686 &frame->rs_uc.uc_stack.ss_size);
687 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000688 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 if (err)
691 goto give_sigsegv;
692
693 /*
694 * Arguments to signal handler:
695 *
696 * a0 = signal number
697 * a1 = 0 (should be cause)
698 * a2 = pointer to ucontext
699 *
700 * $25 and c0_epc point to the signal handler, $29 points to
701 * the struct rt_sigframe32.
702 */
703 regs->regs[ 4] = signr;
704 regs->regs[ 5] = (unsigned long) &frame->rs_info;
705 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
706 regs->regs[29] = (unsigned long) frame;
707 regs->regs[31] = (unsigned long) frame->rs_code;
708 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
709
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100710 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100712 frame, regs->cp0_epc, regs->regs[31]);
713
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000714 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716give_sigsegv:
717 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000718 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719}
720
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000721/*
722 * o32 compatibility on 64-bit kernels, without DSP ASE
723 */
724struct mips_abi mips_abi_32 = {
725 .setup_frame = setup_frame_32,
726 .setup_rt_frame = setup_rt_frame_32,
727 .restart = __NR_O32_restart_syscall
728};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900730asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900731 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 unsigned int sigsetsize)
733{
734 struct k_sigaction new_sa, old_sa;
735 int ret = -EINVAL;
736
737 /* XXX: Don't preclude handling different sized sigset_t's. */
738 if (sigsetsize != sizeof(sigset_t))
739 goto out;
740
741 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000742 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 int err = 0;
744
745 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
746 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000747 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900748 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
750 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
751 if (err)
752 return -EFAULT;
753 }
754
755 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
756
757 if (!ret && oact) {
758 int err = 0;
759
760 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
761 return -EFAULT;
762
763 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
764 &oact->sa_handler);
765 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
766 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
767 if (err)
768 return -EFAULT;
769 }
770out:
771 return ret;
772}
773
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900774asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900775 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
777 sigset_t old_set, new_set;
778 int ret;
779 mm_segment_t old_fs = get_fs();
780
781 if (set && get_sigset(&new_set, set))
782 return -EFAULT;
783
784 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900785 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
786 oset ? (sigset_t __user *)&old_set : NULL,
787 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 set_fs (old_fs);
789
790 if (!ret && oset && put_sigset(&old_set, oset))
791 return -EFAULT;
792
793 return ret;
794}
795
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900796asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 unsigned int sigsetsize)
798{
799 int ret;
800 sigset_t set;
801 mm_segment_t old_fs = get_fs();
802
803 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900804 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 set_fs (old_fs);
806
807 if (!ret && put_sigset(&set, uset))
808 return -EFAULT;
809
810 return ret;
811}
812
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900813asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 siginfo_t info;
816 int ret;
817 mm_segment_t old_fs = get_fs();
818
819 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
820 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
821 return -EFAULT;
822 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900823 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 set_fs (old_fs);
825 return ret;
826}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000827
828asmlinkage long
829sys32_waitid(int which, compat_pid_t pid,
830 compat_siginfo_t __user *uinfo, int options,
831 struct compat_rusage __user *uru)
832{
833 siginfo_t info;
834 struct rusage ru;
835 long ret;
836 mm_segment_t old_fs = get_fs();
837
838 info.si_signo = 0;
839 set_fs (KERNEL_DS);
840 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
841 uru ? (struct rusage __user *) &ru : NULL);
842 set_fs (old_fs);
843
844 if (ret < 0 || info.si_signo == 0)
845 return ret;
846
847 if (uru && (ret = put_compat_rusage(&ru, uru)))
848 return ret;
849
850 BUG_ON(info.si_code & __SI_MASK);
851 info.si_code |= __SI_CHLD;
852 return copy_siginfo_to_user32(uinfo, &info);
853}