blob: 003f8152b9ed7e6ea7383358872a7bab98c1b682 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#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>
Atsushi Nemotofaea6232007-04-16 23:19:44 +090024#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/ucontext.h>
33#include <asm/system.h>
34#include <asm/fpu.h>
Ralf Baechle02416dc2005-06-15 13:00:12 +000035#include <asm/war.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +010037#include "signal-common.h"
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
40
41typedef struct compat_siginfo {
42 int si_signo;
43 int si_code;
44 int si_errno;
45
46 union {
47 int _pad[SI_PAD_SIZE32];
48
49 /* kill() */
50 struct {
51 compat_pid_t _pid; /* sender's pid */
52 compat_uid_t _uid; /* sender's uid */
53 } _kill;
54
55 /* SIGCHLD */
56 struct {
57 compat_pid_t _pid; /* which child */
58 compat_uid_t _uid; /* sender's uid */
59 int _status; /* exit code */
60 compat_clock_t _utime;
61 compat_clock_t _stime;
62 } _sigchld;
63
64 /* IRIX SIGCHLD */
65 struct {
66 compat_pid_t _pid; /* which child */
67 compat_clock_t _utime;
68 int _status; /* exit code */
69 compat_clock_t _stime;
70 } _irix_sigchld;
71
72 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
73 struct {
74 s32 _addr; /* faulting insn/memory ref. */
75 } _sigfault;
76
77 /* SIGPOLL, SIGXFSZ (To do ...) */
78 struct {
79 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
80 int _fd;
81 } _sigpoll;
82
83 /* POSIX.1b timers */
84 struct {
Ralf Baechlea9820992005-02-16 21:24:16 +000085 timer_t _tid; /* timer id */
86 int _overrun; /* overrun count */
Ralf Baechle209ac8d2005-03-18 17:36:42 +000087 compat_sigval_t _sigval;/* same as below */
Ralf Baechlea9820992005-02-16 21:24:16 +000088 int _sys_private; /* not to be passed to user */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 } _timer;
90
91 /* POSIX.1b signals */
92 struct {
93 compat_pid_t _pid; /* sender's pid */
94 compat_uid_t _uid; /* sender's uid */
95 compat_sigval_t _sigval;
96 } _rt;
97
98 } _sifields;
99} compat_siginfo_t;
100
101/*
102 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
103 */
104#define __NR_O32_sigreturn 4119
105#define __NR_O32_rt_sigreturn 4193
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000106#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108/* 32-bit compatibility types */
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110typedef unsigned int __sighandler32_t;
111typedef void (*vfptr_t)(void);
112
113struct sigaction32 {
114 unsigned int sa_flags;
115 __sighandler32_t sa_handler;
116 compat_sigset_t sa_mask;
117};
118
119/* IRIX compatible stack_t */
120typedef struct sigaltstack32 {
121 s32 ss_sp;
122 compat_size_t ss_size;
123 int ss_flags;
124} stack32_t;
125
126struct ucontext32 {
127 u32 uc_flags;
128 s32 uc_link;
129 stack32_t uc_stack;
130 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +0000131 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132};
133
Ralf Baechledd02f062007-02-13 00:50:57 +0000134/*
135 * Horribly complicated - with the bloody RM9000 workarounds enabled
136 * the signal trampolines is moving to the end of the structure so we can
137 * increase the alignment without breaking software compatibility.
138 */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100139#if ICACHE_REFILLS_WORKAROUND_WAR == 0
140
Ralf Baechledd02f062007-02-13 00:50:57 +0000141struct sigframe32 {
142 u32 sf_ass[4]; /* argument save space for o32 */
143 u32 sf_code[2]; /* signal trampoline */
144 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +0900145 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +0000146};
147
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100148struct rt_sigframe32 {
149 u32 rs_ass[4]; /* argument save space for o32 */
150 u32 rs_code[2]; /* signal trampoline */
151 compat_siginfo_t rs_info;
152 struct ucontext32 rs_uc;
153};
154
155#else /* ICACHE_REFILLS_WORKAROUND_WAR */
156
Ralf Baechledd02f062007-02-13 00:50:57 +0000157struct sigframe32 {
158 u32 sf_ass[4]; /* argument save space for o32 */
159 u32 sf_pad[2];
160 struct sigcontext32 sf_sc; /* hw context */
Atsushi Nemoto755f21b2007-02-14 14:41:01 +0900161 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +0000162 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
163};
164
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100165struct rt_sigframe32 {
166 u32 rs_ass[4]; /* argument save space for o32 */
167 u32 rs_pad[2];
168 compat_siginfo_t rs_info;
169 struct ucontext32 rs_uc;
170 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
171};
172
173#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
174
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100175/*
176 * sigcontext handlers
177 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900178static int protected_save_fp_context32(struct sigcontext32 __user *sc)
179{
180 int err;
181 while (1) {
182 lock_fpu_owner();
183 own_fpu_inatomic(1);
184 err = save_fp_context32(sc); /* this might fail */
185 unlock_fpu_owner();
186 if (likely(!err))
187 break;
188 /* touch the sigcontext and try again */
189 err = __put_user(0, &sc->sc_fpregs[0]) |
190 __put_user(0, &sc->sc_fpregs[31]) |
191 __put_user(0, &sc->sc_fpc_csr);
192 if (err)
193 break; /* really bad sigcontext */
194 }
195 return err;
196}
197
198static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
199{
200 int err, tmp;
201 while (1) {
202 lock_fpu_owner();
203 own_fpu_inatomic(0);
204 err = restore_fp_context32(sc); /* this might fail */
205 unlock_fpu_owner();
206 if (likely(!err))
207 break;
208 /* touch the sigcontext and try again */
209 err = __get_user(tmp, &sc->sc_fpregs[0]) |
210 __get_user(tmp, &sc->sc_fpregs[31]) |
211 __get_user(tmp, &sc->sc_fpc_csr);
212 if (err)
213 break; /* really bad sigcontext */
214 }
215 return err;
216}
217
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100218static int setup_sigcontext32(struct pt_regs *regs,
219 struct sigcontext32 __user *sc)
220{
221 int err = 0;
222 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900223 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100224
225 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100226
227 err |= __put_user(0, &sc->sc_regs[0]);
228 for (i = 1; i < 32; i++)
229 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
230
231 err |= __put_user(regs->hi, &sc->sc_mdhi);
232 err |= __put_user(regs->lo, &sc->sc_mdlo);
233 if (cpu_has_dsp) {
234 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
235 err |= __put_user(mfhi1(), &sc->sc_hi1);
236 err |= __put_user(mflo1(), &sc->sc_lo1);
237 err |= __put_user(mfhi2(), &sc->sc_hi2);
238 err |= __put_user(mflo2(), &sc->sc_lo2);
239 err |= __put_user(mfhi3(), &sc->sc_hi3);
240 err |= __put_user(mflo3(), &sc->sc_lo3);
241 }
242
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900243 used_math = !!used_math();
244 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100245
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900246 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100247 /*
248 * Save FPU state to signal context. Signal handler
249 * will "inherit" current FPU state.
250 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900251 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100252 }
253 return err;
254}
255
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900256static int
257check_and_restore_fp_context32(struct sigcontext32 __user *sc)
258{
259 int err, sig;
260
261 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
262 if (err > 0)
263 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900264 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900265 return err ?: sig;
266}
267
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100268static int restore_sigcontext32(struct pt_regs *regs,
269 struct sigcontext32 __user *sc)
270{
271 u32 used_math;
272 int err = 0;
273 s32 treg;
274 int i;
275
276 /* Always make any pending restarted system calls return -EINTR */
277 current_thread_info()->restart_block.fn = do_no_restart_syscall;
278
279 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
280 err |= __get_user(regs->hi, &sc->sc_mdhi);
281 err |= __get_user(regs->lo, &sc->sc_mdlo);
282 if (cpu_has_dsp) {
283 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
284 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
285 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
286 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
287 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
288 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
289 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
290 }
291
292 for (i = 1; i < 32; i++)
293 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
294
295 err |= __get_user(used_math, &sc->sc_used_math);
296 conditional_used_math(used_math);
297
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900298 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100299 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900300 if (!err)
301 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100302 } else {
303 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900304 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100305 }
306
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100307 return err;
308}
309
310/*
311 *
312 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313extern void __put_sigset_unknown_nsig(void);
314extern void __get_sigset_unknown_nsig(void);
315
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900316static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 int err = 0;
319
320 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
321 return -EFAULT;
322
323 switch (_NSIG_WORDS) {
324 default:
325 __put_sigset_unknown_nsig();
326 case 2:
327 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
328 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
329 case 1:
330 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
331 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
332 }
333
334 return err;
335}
336
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900337static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 int err = 0;
340 unsigned long sig[4];
341
342 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
343 return -EFAULT;
344
345 switch (_NSIG_WORDS) {
346 default:
347 __get_sigset_unknown_nsig();
348 case 2:
349 err |= __get_user (sig[3], &ubuf->sig[3]);
350 err |= __get_user (sig[2], &ubuf->sig[2]);
351 kbuf->sig[1] = sig[2] | (sig[3] << 32);
352 case 1:
353 err |= __get_user (sig[1], &ubuf->sig[1]);
354 err |= __get_user (sig[0], &ubuf->sig[0]);
355 kbuf->sig[0] = sig[0] | (sig[1] << 32);
356 }
357
358 return err;
359}
360
361/*
362 * Atomically swap in the new signal mask, and wait for a signal.
363 */
364
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100365asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900367 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000368 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
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;
378 recalc_sigpending();
379 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
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100387asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900389 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000390 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000391 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 /* XXX Don't preclude handling different sized sigset_t's. */
394 sigsetsize = regs.regs[5];
395 if (sigsetsize != sizeof(compat_sigset_t))
396 return -EINVAL;
397
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900398 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (get_sigset(&newset, uset))
400 return -EFAULT;
401 sigdelsetmask(&newset, ~_BLOCKABLE);
402
403 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000404 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000406 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 spin_unlock_irq(&current->sighand->siglock);
408
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000409 current->state = TASK_INTERRUPTIBLE;
410 schedule();
411 set_thread_flag(TIF_RESTORE_SIGMASK);
412 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900415asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
416 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 struct k_sigaction new_ka, old_ka;
419 int ret;
420 int err = 0;
421
422 if (act) {
423 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000424 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
427 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000428 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900429 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
431 err |= __get_user(mask, &act->sa_mask.sig[0]);
432 if (err)
433 return -EFAULT;
434
435 siginitset(&new_ka.sa.sa_mask, mask);
436 }
437
438 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
439
440 if (!ret && oact) {
441 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000442 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
444 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
445 &oact->sa_handler);
446 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000447 err |= __put_user(0, &oact->sa_mask.sig[1]);
448 err |= __put_user(0, &oact->sa_mask.sig[2]);
449 err |= __put_user(0, &oact->sa_mask.sig[3]);
450 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return -EFAULT;
452 }
453
454 return ret;
455}
456
457asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
458{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900459 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
460 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 unsigned long usp = regs.regs[29];
462 stack_t kss, koss;
463 int ret, err = 0;
464 mm_segment_t old_fs = get_fs();
465 s32 sp;
466
467 if (uss) {
468 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
469 return -EFAULT;
470 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900471 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 err |= __get_user(kss.ss_size, &uss->ss_size);
473 err |= __get_user(kss.ss_flags, &uss->ss_flags);
474 if (err)
475 return -EFAULT;
476 }
477
478 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900479 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
480 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 set_fs (old_fs);
482
483 if (!ret && uoss) {
484 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
485 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900486 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 err |= __put_user(sp, &uoss->ss_sp);
488 err |= __put_user(koss.ss_size, &uoss->ss_size);
489 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
490 if (err)
491 return -EFAULT;
492 }
493 return ret;
494}
495
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900496int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
498 int err;
499
500 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
501 return -EFAULT;
502
503 /* If you change siginfo_t structure, please be sure
504 this code is fixed accordingly.
505 It should never copy any pad contained in the structure
506 to avoid security leaks, but must copy the generic
507 3 ints plus the relevant union member.
508 This routine must convert siginfo from 64bit to 32bit as well
509 at the same time. */
510 err = __put_user(from->si_signo, &to->si_signo);
511 err |= __put_user(from->si_errno, &to->si_errno);
512 err |= __put_user((short)from->si_code, &to->si_code);
513 if (from->si_code < 0)
514 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
515 else {
516 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000517 case __SI_TIMER >> 16:
518 err |= __put_user(from->si_tid, &to->si_tid);
519 err |= __put_user(from->si_overrun, &to->si_overrun);
520 err |= __put_user(from->si_int, &to->si_int);
521 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 case __SI_CHLD >> 16:
523 err |= __put_user(from->si_utime, &to->si_utime);
524 err |= __put_user(from->si_stime, &to->si_stime);
525 err |= __put_user(from->si_status, &to->si_status);
526 default:
527 err |= __put_user(from->si_pid, &to->si_pid);
528 err |= __put_user(from->si_uid, &to->si_uid);
529 break;
530 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900531 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 break;
533 case __SI_POLL >> 16:
534 err |= __put_user(from->si_band, &to->si_band);
535 err |= __put_user(from->si_fd, &to->si_fd);
536 break;
537 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
538 case __SI_MESGQ >> 16:
539 err |= __put_user(from->si_pid, &to->si_pid);
540 err |= __put_user(from->si_uid, &to->si_uid);
541 err |= __put_user(from->si_int, &to->si_int);
542 break;
543 }
544 }
545 return err;
546}
547
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100548asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Ralf Baechledd02f062007-02-13 00:50:57 +0000550 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900552 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Ralf Baechledd02f062007-02-13 00:50:57 +0000554 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
556 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000557 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 goto badframe;
559
560 sigdelsetmask(&blocked, ~_BLOCKABLE);
561 spin_lock_irq(&current->sighand->siglock);
562 current->blocked = blocked;
563 recalc_sigpending();
564 spin_unlock_irq(&current->sighand->siglock);
565
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900566 sig = restore_sigcontext32(&regs, &frame->sf_sc);
567 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900569 else if (sig)
570 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 /*
573 * Don't let your children do this ...
574 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 __asm__ __volatile__(
576 "move\t$29, %0\n\t"
577 "j\tsyscall_exit"
578 :/* no outputs */
579 :"r" (&regs));
580 /* Unreached */
581
582badframe:
583 force_sig(SIGSEGV, current);
584}
585
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100586asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900588 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000589 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 sigset_t set;
591 stack_t st;
592 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900593 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900595 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
597 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000598 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 goto badframe;
600
601 sigdelsetmask(&set, ~_BLOCKABLE);
602 spin_lock_irq(&current->sighand->siglock);
603 current->blocked = set;
604 recalc_sigpending();
605 spin_unlock_irq(&current->sighand->siglock);
606
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900607 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
608 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900610 else if (sig)
611 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 /* The ucontext contains a stack32_t, so we must convert! */
614 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
615 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900616 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
618 goto badframe;
619 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
620 goto badframe;
621
622 /* It is more difficult to avoid calling this function than to
623 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000624 old_fs = get_fs();
625 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900626 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000627 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 /*
630 * Don't let your children do this ...
631 */
632 __asm__ __volatile__(
633 "move\t$29, %0\n\t"
634 "j\tsyscall_exit"
635 :/* no outputs */
636 :"r" (&regs));
637 /* Unreached */
638
639badframe:
640 force_sig(SIGSEGV, current);
641}
642
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000643static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900644 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Ralf Baechledd02f062007-02-13 00:50:57 +0000646 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 int err = 0;
648
649 frame = get_sigframe(ka, regs, sizeof(*frame));
650 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
651 goto give_sigsegv;
652
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100653 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000656 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if (err)
659 goto give_sigsegv;
660
661 /*
662 * Arguments to signal handler:
663 *
664 * a0 = signal number
665 * a1 = 0 (should be cause)
666 * a2 = pointer to struct sigcontext
667 *
668 * $25 and c0_epc point to the signal handler, $29 points to the
669 * struct sigframe.
670 */
671 regs->regs[ 4] = signr;
672 regs->regs[ 5] = 0;
673 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
674 regs->regs[29] = (unsigned long) frame;
675 regs->regs[31] = (unsigned long) frame->sf_code;
676 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
677
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100678 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100680 frame, regs->cp0_epc, regs->regs[31]);
681
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000682 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684give_sigsegv:
685 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000686 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000689static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900690 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900692 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 int err = 0;
694 s32 sp;
695
696 frame = get_sigframe(ka, regs, sizeof(*frame));
697 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
698 goto give_sigsegv;
699
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100700 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
703 err |= copy_siginfo_to_user32(&frame->rs_info, info);
704
705 /* Create the ucontext. */
706 err |= __put_user(0, &frame->rs_uc.uc_flags);
707 err |= __put_user(0, &frame->rs_uc.uc_link);
708 sp = (int) (long) current->sas_ss_sp;
709 err |= __put_user(sp,
710 &frame->rs_uc.uc_stack.ss_sp);
711 err |= __put_user(sas_ss_flags(regs->regs[29]),
712 &frame->rs_uc.uc_stack.ss_flags);
713 err |= __put_user(current->sas_ss_size,
714 &frame->rs_uc.uc_stack.ss_size);
715 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000716 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718 if (err)
719 goto give_sigsegv;
720
721 /*
722 * Arguments to signal handler:
723 *
724 * a0 = signal number
725 * a1 = 0 (should be cause)
726 * a2 = pointer to ucontext
727 *
728 * $25 and c0_epc point to the signal handler, $29 points to
729 * the struct rt_sigframe32.
730 */
731 regs->regs[ 4] = signr;
732 regs->regs[ 5] = (unsigned long) &frame->rs_info;
733 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
734 regs->regs[29] = (unsigned long) frame;
735 regs->regs[31] = (unsigned long) frame->rs_code;
736 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
737
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100738 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100740 frame, regs->cp0_epc, regs->regs[31]);
741
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000742 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744give_sigsegv:
745 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000746 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000749/*
750 * o32 compatibility on 64-bit kernels, without DSP ASE
751 */
752struct mips_abi mips_abi_32 = {
753 .setup_frame = setup_frame_32,
754 .setup_rt_frame = setup_rt_frame_32,
755 .restart = __NR_O32_restart_syscall
756};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900758asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900759 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 unsigned int sigsetsize)
761{
762 struct k_sigaction new_sa, old_sa;
763 int ret = -EINVAL;
764
765 /* XXX: Don't preclude handling different sized sigset_t's. */
766 if (sigsetsize != sizeof(sigset_t))
767 goto out;
768
769 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000770 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 int err = 0;
772
773 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
774 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000775 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900776 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
778 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
779 if (err)
780 return -EFAULT;
781 }
782
783 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
784
785 if (!ret && oact) {
786 int err = 0;
787
788 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
789 return -EFAULT;
790
791 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
792 &oact->sa_handler);
793 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
794 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
795 if (err)
796 return -EFAULT;
797 }
798out:
799 return ret;
800}
801
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900802asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900803 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
805 sigset_t old_set, new_set;
806 int ret;
807 mm_segment_t old_fs = get_fs();
808
809 if (set && get_sigset(&new_set, set))
810 return -EFAULT;
811
812 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900813 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
814 oset ? (sigset_t __user *)&old_set : NULL,
815 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 set_fs (old_fs);
817
818 if (!ret && oset && put_sigset(&old_set, oset))
819 return -EFAULT;
820
821 return ret;
822}
823
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900824asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 unsigned int sigsetsize)
826{
827 int ret;
828 sigset_t set;
829 mm_segment_t old_fs = get_fs();
830
831 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900832 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 set_fs (old_fs);
834
835 if (!ret && put_sigset(&set, uset))
836 return -EFAULT;
837
838 return ret;
839}
840
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900841asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 siginfo_t info;
844 int ret;
845 mm_segment_t old_fs = get_fs();
846
847 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
848 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
849 return -EFAULT;
850 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900851 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 set_fs (old_fs);
853 return ret;
854}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000855
856asmlinkage long
857sys32_waitid(int which, compat_pid_t pid,
858 compat_siginfo_t __user *uinfo, int options,
859 struct compat_rusage __user *uru)
860{
861 siginfo_t info;
862 struct rusage ru;
863 long ret;
864 mm_segment_t old_fs = get_fs();
865
866 info.si_signo = 0;
867 set_fs (KERNEL_DS);
868 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
869 uru ? (struct rusage __user *) &ru : NULL);
870 set_fs (old_fs);
871
872 if (ret < 0 || info.si_signo == 0)
873 return ret;
874
875 if (uru && (ret = put_compat_rusage(&ru, uru)))
876 return ret;
877
878 BUG_ON(info.si_code & __SI_MASK);
879 info.si_code |= __SI_CHLD;
880 return copy_siginfo_to_user32(uinfo, &info);
881}