blob: 151fd2f0893ab7e1c2e2f94f91964d74cdfb1ba7 [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-Huu36a1f2c2007-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;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900184 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100185
186 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100187
188 err |= __put_user(0, &sc->sc_regs[0]);
189 for (i = 1; i < 32; i++)
190 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
191
192 err |= __put_user(regs->hi, &sc->sc_mdhi);
193 err |= __put_user(regs->lo, &sc->sc_mdlo);
194 if (cpu_has_dsp) {
195 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
196 err |= __put_user(mfhi1(), &sc->sc_hi1);
197 err |= __put_user(mflo1(), &sc->sc_lo1);
198 err |= __put_user(mfhi2(), &sc->sc_hi2);
199 err |= __put_user(mflo2(), &sc->sc_lo2);
200 err |= __put_user(mfhi3(), &sc->sc_hi3);
201 err |= __put_user(mflo3(), &sc->sc_lo3);
202 }
203
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900204 used_math = !!used_math();
205 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100206
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900207 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100208 /*
209 * Save FPU state to signal context. Signal handler
210 * will "inherit" current FPU state.
211 */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900212 own_fpu(1);
213 enable_fp_in_kernel();
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100214 err |= save_fp_context32(sc);
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900215 disable_fp_in_kernel();
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100216 }
217 return err;
218}
219
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900220static int
221check_and_restore_fp_context32(struct sigcontext32 __user *sc)
222{
223 int err, sig;
224
225 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
226 if (err > 0)
227 err = 0;
228 err |= restore_fp_context32(sc);
229 return err ?: sig;
230}
231
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100232static int restore_sigcontext32(struct pt_regs *regs,
233 struct sigcontext32 __user *sc)
234{
235 u32 used_math;
236 int err = 0;
237 s32 treg;
238 int i;
239
240 /* Always make any pending restarted system calls return -EINTR */
241 current_thread_info()->restart_block.fn = do_no_restart_syscall;
242
243 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
244 err |= __get_user(regs->hi, &sc->sc_mdhi);
245 err |= __get_user(regs->lo, &sc->sc_mdlo);
246 if (cpu_has_dsp) {
247 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
248 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
249 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
250 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
251 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
252 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
253 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
254 }
255
256 for (i = 1; i < 32; i++)
257 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
258
259 err |= __get_user(used_math, &sc->sc_used_math);
260 conditional_used_math(used_math);
261
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900262 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100263 /* restore fpu context if we have used it before */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900264 own_fpu(0);
265 enable_fp_in_kernel();
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900266 if (!err)
267 err = check_and_restore_fp_context32(sc);
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900268 disable_fp_in_kernel();
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100269 } else {
270 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900271 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100272 }
273
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100274 return err;
275}
276
277/*
278 *
279 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280extern void __put_sigset_unknown_nsig(void);
281extern void __get_sigset_unknown_nsig(void);
282
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900283static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 int err = 0;
286
287 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
288 return -EFAULT;
289
290 switch (_NSIG_WORDS) {
291 default:
292 __put_sigset_unknown_nsig();
293 case 2:
294 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
295 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
296 case 1:
297 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
298 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
299 }
300
301 return err;
302}
303
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900304static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 int err = 0;
307 unsigned long sig[4];
308
309 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
310 return -EFAULT;
311
312 switch (_NSIG_WORDS) {
313 default:
314 __get_sigset_unknown_nsig();
315 case 2:
316 err |= __get_user (sig[3], &ubuf->sig[3]);
317 err |= __get_user (sig[2], &ubuf->sig[2]);
318 kbuf->sig[1] = sig[2] | (sig[3] << 32);
319 case 1:
320 err |= __get_user (sig[1], &ubuf->sig[1]);
321 err |= __get_user (sig[0], &ubuf->sig[0]);
322 kbuf->sig[0] = sig[0] | (sig[1] << 32);
323 }
324
325 return err;
326}
327
328/*
329 * Atomically swap in the new signal mask, and wait for a signal.
330 */
331
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100332asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900334 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000335 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900337 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (get_sigset(&newset, uset))
339 return -EFAULT;
340 sigdelsetmask(&newset, ~_BLOCKABLE);
341
342 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000343 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 current->blocked = newset;
345 recalc_sigpending();
346 spin_unlock_irq(&current->sighand->siglock);
347
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000348 current->state = TASK_INTERRUPTIBLE;
349 schedule();
350 set_thread_flag(TIF_RESTORE_SIGMASK);
351 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100354asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900356 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000357 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000358 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 /* XXX Don't preclude handling different sized sigset_t's. */
361 sigsetsize = regs.regs[5];
362 if (sigsetsize != sizeof(compat_sigset_t))
363 return -EINVAL;
364
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900365 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 if (get_sigset(&newset, uset))
367 return -EFAULT;
368 sigdelsetmask(&newset, ~_BLOCKABLE);
369
370 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000371 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000373 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 spin_unlock_irq(&current->sighand->siglock);
375
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000376 current->state = TASK_INTERRUPTIBLE;
377 schedule();
378 set_thread_flag(TIF_RESTORE_SIGMASK);
379 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900382asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
383 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct k_sigaction new_ka, old_ka;
386 int ret;
387 int err = 0;
388
389 if (act) {
390 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000391 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
394 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000395 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900396 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
398 err |= __get_user(mask, &act->sa_mask.sig[0]);
399 if (err)
400 return -EFAULT;
401
402 siginitset(&new_ka.sa.sa_mask, mask);
403 }
404
405 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
406
407 if (!ret && oact) {
408 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000409 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
411 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
412 &oact->sa_handler);
413 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000414 err |= __put_user(0, &oact->sa_mask.sig[1]);
415 err |= __put_user(0, &oact->sa_mask.sig[2]);
416 err |= __put_user(0, &oact->sa_mask.sig[3]);
417 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return -EFAULT;
419 }
420
421 return ret;
422}
423
424asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
425{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900426 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
427 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 unsigned long usp = regs.regs[29];
429 stack_t kss, koss;
430 int ret, err = 0;
431 mm_segment_t old_fs = get_fs();
432 s32 sp;
433
434 if (uss) {
435 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
436 return -EFAULT;
437 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900438 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 err |= __get_user(kss.ss_size, &uss->ss_size);
440 err |= __get_user(kss.ss_flags, &uss->ss_flags);
441 if (err)
442 return -EFAULT;
443 }
444
445 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900446 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
447 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 set_fs (old_fs);
449
450 if (!ret && uoss) {
451 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
452 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900453 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 err |= __put_user(sp, &uoss->ss_sp);
455 err |= __put_user(koss.ss_size, &uoss->ss_size);
456 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
457 if (err)
458 return -EFAULT;
459 }
460 return ret;
461}
462
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900463int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
465 int err;
466
467 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
468 return -EFAULT;
469
470 /* If you change siginfo_t structure, please be sure
471 this code is fixed accordingly.
472 It should never copy any pad contained in the structure
473 to avoid security leaks, but must copy the generic
474 3 ints plus the relevant union member.
475 This routine must convert siginfo from 64bit to 32bit as well
476 at the same time. */
477 err = __put_user(from->si_signo, &to->si_signo);
478 err |= __put_user(from->si_errno, &to->si_errno);
479 err |= __put_user((short)from->si_code, &to->si_code);
480 if (from->si_code < 0)
481 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
482 else {
483 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000484 case __SI_TIMER >> 16:
485 err |= __put_user(from->si_tid, &to->si_tid);
486 err |= __put_user(from->si_overrun, &to->si_overrun);
487 err |= __put_user(from->si_int, &to->si_int);
488 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 case __SI_CHLD >> 16:
490 err |= __put_user(from->si_utime, &to->si_utime);
491 err |= __put_user(from->si_stime, &to->si_stime);
492 err |= __put_user(from->si_status, &to->si_status);
493 default:
494 err |= __put_user(from->si_pid, &to->si_pid);
495 err |= __put_user(from->si_uid, &to->si_uid);
496 break;
497 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900498 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 break;
500 case __SI_POLL >> 16:
501 err |= __put_user(from->si_band, &to->si_band);
502 err |= __put_user(from->si_fd, &to->si_fd);
503 break;
504 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
505 case __SI_MESGQ >> 16:
506 err |= __put_user(from->si_pid, &to->si_pid);
507 err |= __put_user(from->si_uid, &to->si_uid);
508 err |= __put_user(from->si_int, &to->si_int);
509 break;
510 }
511 }
512 return err;
513}
514
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100515asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
Ralf Baechledd02f062007-02-13 00:50:57 +0000517 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900519 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Ralf Baechledd02f062007-02-13 00:50:57 +0000521 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
523 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000524 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 goto badframe;
526
527 sigdelsetmask(&blocked, ~_BLOCKABLE);
528 spin_lock_irq(&current->sighand->siglock);
529 current->blocked = blocked;
530 recalc_sigpending();
531 spin_unlock_irq(&current->sighand->siglock);
532
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900533 sig = restore_sigcontext32(&regs, &frame->sf_sc);
534 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900536 else if (sig)
537 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 /*
540 * Don't let your children do this ...
541 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 __asm__ __volatile__(
543 "move\t$29, %0\n\t"
544 "j\tsyscall_exit"
545 :/* no outputs */
546 :"r" (&regs));
547 /* Unreached */
548
549badframe:
550 force_sig(SIGSEGV, current);
551}
552
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100553asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900555 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000556 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 sigset_t set;
558 stack_t st;
559 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900560 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900562 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
564 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000565 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 goto badframe;
567
568 sigdelsetmask(&set, ~_BLOCKABLE);
569 spin_lock_irq(&current->sighand->siglock);
570 current->blocked = set;
571 recalc_sigpending();
572 spin_unlock_irq(&current->sighand->siglock);
573
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900574 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
575 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900577 else if (sig)
578 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 /* The ucontext contains a stack32_t, so we must convert! */
581 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
582 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900583 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
585 goto badframe;
586 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
587 goto badframe;
588
589 /* It is more difficult to avoid calling this function than to
590 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000591 old_fs = get_fs();
592 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900593 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000594 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 /*
597 * Don't let your children do this ...
598 */
599 __asm__ __volatile__(
600 "move\t$29, %0\n\t"
601 "j\tsyscall_exit"
602 :/* no outputs */
603 :"r" (&regs));
604 /* Unreached */
605
606badframe:
607 force_sig(SIGSEGV, current);
608}
609
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000610static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900611 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
Ralf Baechledd02f062007-02-13 00:50:57 +0000613 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 int err = 0;
615
616 frame = get_sigframe(ka, regs, sizeof(*frame));
617 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
618 goto give_sigsegv;
619
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100620 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000623 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 if (err)
626 goto give_sigsegv;
627
628 /*
629 * Arguments to signal handler:
630 *
631 * a0 = signal number
632 * a1 = 0 (should be cause)
633 * a2 = pointer to struct sigcontext
634 *
635 * $25 and c0_epc point to the signal handler, $29 points to the
636 * struct sigframe.
637 */
638 regs->regs[ 4] = signr;
639 regs->regs[ 5] = 0;
640 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
641 regs->regs[29] = (unsigned long) frame;
642 regs->regs[31] = (unsigned long) frame->sf_code;
643 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
644
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100645 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100647 frame, regs->cp0_epc, regs->regs[31]);
648
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000649 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651give_sigsegv:
652 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000653 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000656static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900657 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900659 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 int err = 0;
661 s32 sp;
662
663 frame = get_sigframe(ka, regs, sizeof(*frame));
664 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
665 goto give_sigsegv;
666
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100667 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
670 err |= copy_siginfo_to_user32(&frame->rs_info, info);
671
672 /* Create the ucontext. */
673 err |= __put_user(0, &frame->rs_uc.uc_flags);
674 err |= __put_user(0, &frame->rs_uc.uc_link);
675 sp = (int) (long) current->sas_ss_sp;
676 err |= __put_user(sp,
677 &frame->rs_uc.uc_stack.ss_sp);
678 err |= __put_user(sas_ss_flags(regs->regs[29]),
679 &frame->rs_uc.uc_stack.ss_flags);
680 err |= __put_user(current->sas_ss_size,
681 &frame->rs_uc.uc_stack.ss_size);
682 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000683 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (err)
686 goto give_sigsegv;
687
688 /*
689 * Arguments to signal handler:
690 *
691 * a0 = signal number
692 * a1 = 0 (should be cause)
693 * a2 = pointer to ucontext
694 *
695 * $25 and c0_epc point to the signal handler, $29 points to
696 * the struct rt_sigframe32.
697 */
698 regs->regs[ 4] = signr;
699 regs->regs[ 5] = (unsigned long) &frame->rs_info;
700 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
701 regs->regs[29] = (unsigned long) frame;
702 regs->regs[31] = (unsigned long) frame->rs_code;
703 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
704
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100705 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100707 frame, regs->cp0_epc, regs->regs[31]);
708
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000709 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711give_sigsegv:
712 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000713 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714}
715
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000716/*
717 * o32 compatibility on 64-bit kernels, without DSP ASE
718 */
719struct mips_abi mips_abi_32 = {
720 .setup_frame = setup_frame_32,
721 .setup_rt_frame = setup_rt_frame_32,
722 .restart = __NR_O32_restart_syscall
723};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900725asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900726 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 unsigned int sigsetsize)
728{
729 struct k_sigaction new_sa, old_sa;
730 int ret = -EINVAL;
731
732 /* XXX: Don't preclude handling different sized sigset_t's. */
733 if (sigsetsize != sizeof(sigset_t))
734 goto out;
735
736 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000737 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 int err = 0;
739
740 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
741 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000742 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900743 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
745 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
746 if (err)
747 return -EFAULT;
748 }
749
750 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
751
752 if (!ret && oact) {
753 int err = 0;
754
755 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
756 return -EFAULT;
757
758 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
759 &oact->sa_handler);
760 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
761 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
762 if (err)
763 return -EFAULT;
764 }
765out:
766 return ret;
767}
768
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900769asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900770 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{
772 sigset_t old_set, new_set;
773 int ret;
774 mm_segment_t old_fs = get_fs();
775
776 if (set && get_sigset(&new_set, set))
777 return -EFAULT;
778
779 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900780 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
781 oset ? (sigset_t __user *)&old_set : NULL,
782 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 set_fs (old_fs);
784
785 if (!ret && oset && put_sigset(&old_set, oset))
786 return -EFAULT;
787
788 return ret;
789}
790
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900791asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 unsigned int sigsetsize)
793{
794 int ret;
795 sigset_t set;
796 mm_segment_t old_fs = get_fs();
797
798 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900799 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 set_fs (old_fs);
801
802 if (!ret && put_sigset(&set, uset))
803 return -EFAULT;
804
805 return ret;
806}
807
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900808asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
810 siginfo_t info;
811 int ret;
812 mm_segment_t old_fs = get_fs();
813
814 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
815 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
816 return -EFAULT;
817 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900818 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 set_fs (old_fs);
820 return ret;
821}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000822
823asmlinkage long
824sys32_waitid(int which, compat_pid_t pid,
825 compat_siginfo_t __user *uinfo, int options,
826 struct compat_rusage __user *uru)
827{
828 siginfo_t info;
829 struct rusage ru;
830 long ret;
831 mm_segment_t old_fs = get_fs();
832
833 info.si_signo = 0;
834 set_fs (KERNEL_DS);
835 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
836 uru ? (struct rusage __user *) &ru : NULL);
837 set_fs (old_fs);
838
839 if (ret < 0 || info.si_signo == 0)
840 return ret;
841
842 if (uru && (ret = put_compat_rusage(&ru, uru)))
843 return ret;
844
845 BUG_ON(info.si_code & __SI_MASK);
846 info.si_code |= __SI_CHLD;
847 return copy_siginfo_to_user32(uinfo, &info);
848}