blob: b9a014411f83db184c8a094d88f97b8c8d64b336 [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>
Atsushi Nemotofaea6232007-04-16 23:19:44 +090025#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Ralf Baechlee50c0a82005-05-31 11:49:19 +000027#include <asm/abi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/asm.h>
Ralf Baechle431dc802007-02-13 00:05:11 +000029#include <asm/compat-signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/bitops.h>
31#include <asm/cacheflush.h>
32#include <asm/sim.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#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 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900179static int protected_save_fp_context32(struct sigcontext32 __user *sc)
180{
181 int err;
182 while (1) {
183 lock_fpu_owner();
184 own_fpu_inatomic(1);
185 err = save_fp_context32(sc); /* this might fail */
186 unlock_fpu_owner();
187 if (likely(!err))
188 break;
189 /* touch the sigcontext and try again */
190 err = __put_user(0, &sc->sc_fpregs[0]) |
191 __put_user(0, &sc->sc_fpregs[31]) |
192 __put_user(0, &sc->sc_fpc_csr);
193 if (err)
194 break; /* really bad sigcontext */
195 }
196 return err;
197}
198
199static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
200{
201 int err, tmp;
202 while (1) {
203 lock_fpu_owner();
204 own_fpu_inatomic(0);
205 err = restore_fp_context32(sc); /* this might fail */
206 unlock_fpu_owner();
207 if (likely(!err))
208 break;
209 /* touch the sigcontext and try again */
210 err = __get_user(tmp, &sc->sc_fpregs[0]) |
211 __get_user(tmp, &sc->sc_fpregs[31]) |
212 __get_user(tmp, &sc->sc_fpc_csr);
213 if (err)
214 break; /* really bad sigcontext */
215 }
216 return err;
217}
218
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100219static int setup_sigcontext32(struct pt_regs *regs,
220 struct sigcontext32 __user *sc)
221{
222 int err = 0;
223 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900224 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100225
226 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100227
228 err |= __put_user(0, &sc->sc_regs[0]);
229 for (i = 1; i < 32; i++)
230 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
231
232 err |= __put_user(regs->hi, &sc->sc_mdhi);
233 err |= __put_user(regs->lo, &sc->sc_mdlo);
234 if (cpu_has_dsp) {
235 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
236 err |= __put_user(mfhi1(), &sc->sc_hi1);
237 err |= __put_user(mflo1(), &sc->sc_lo1);
238 err |= __put_user(mfhi2(), &sc->sc_hi2);
239 err |= __put_user(mflo2(), &sc->sc_lo2);
240 err |= __put_user(mfhi3(), &sc->sc_hi3);
241 err |= __put_user(mflo3(), &sc->sc_lo3);
242 }
243
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900244 used_math = !!used_math();
245 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100246
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900247 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100248 /*
249 * Save FPU state to signal context. Signal handler
250 * will "inherit" current FPU state.
251 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900252 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100253 }
254 return err;
255}
256
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900257static int
258check_and_restore_fp_context32(struct sigcontext32 __user *sc)
259{
260 int err, sig;
261
262 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
263 if (err > 0)
264 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900265 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900266 return err ?: sig;
267}
268
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100269static int restore_sigcontext32(struct pt_regs *regs,
270 struct sigcontext32 __user *sc)
271{
272 u32 used_math;
273 int err = 0;
274 s32 treg;
275 int i;
276
277 /* Always make any pending restarted system calls return -EINTR */
278 current_thread_info()->restart_block.fn = do_no_restart_syscall;
279
280 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
281 err |= __get_user(regs->hi, &sc->sc_mdhi);
282 err |= __get_user(regs->lo, &sc->sc_mdlo);
283 if (cpu_has_dsp) {
284 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
285 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
286 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
287 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
288 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
289 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
290 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
291 }
292
293 for (i = 1; i < 32; i++)
294 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
295
296 err |= __get_user(used_math, &sc->sc_used_math);
297 conditional_used_math(used_math);
298
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900299 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100300 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900301 if (!err)
302 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100303 } else {
304 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900305 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100306 }
307
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100308 return err;
309}
310
311/*
312 *
313 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314extern void __put_sigset_unknown_nsig(void);
315extern void __get_sigset_unknown_nsig(void);
316
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900317static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 int err = 0;
320
321 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
322 return -EFAULT;
323
324 switch (_NSIG_WORDS) {
325 default:
326 __put_sigset_unknown_nsig();
327 case 2:
328 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
329 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
330 case 1:
331 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
332 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
333 }
334
335 return err;
336}
337
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900338static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 int err = 0;
341 unsigned long sig[4];
342
343 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
344 return -EFAULT;
345
346 switch (_NSIG_WORDS) {
347 default:
348 __get_sigset_unknown_nsig();
349 case 2:
350 err |= __get_user (sig[3], &ubuf->sig[3]);
351 err |= __get_user (sig[2], &ubuf->sig[2]);
352 kbuf->sig[1] = sig[2] | (sig[3] << 32);
353 case 1:
354 err |= __get_user (sig[1], &ubuf->sig[1]);
355 err |= __get_user (sig[0], &ubuf->sig[0]);
356 kbuf->sig[0] = sig[0] | (sig[1] << 32);
357 }
358
359 return err;
360}
361
362/*
363 * Atomically swap in the new signal mask, and wait for a signal.
364 */
365
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100366asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900368 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000369 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900371 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 if (get_sigset(&newset, uset))
373 return -EFAULT;
374 sigdelsetmask(&newset, ~_BLOCKABLE);
375
376 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000377 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 current->blocked = newset;
379 recalc_sigpending();
380 spin_unlock_irq(&current->sighand->siglock);
381
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000382 current->state = TASK_INTERRUPTIBLE;
383 schedule();
384 set_thread_flag(TIF_RESTORE_SIGMASK);
385 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386}
387
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100388asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900390 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000391 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000392 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 /* XXX Don't preclude handling different sized sigset_t's. */
395 sigsetsize = regs.regs[5];
396 if (sigsetsize != sizeof(compat_sigset_t))
397 return -EINVAL;
398
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900399 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 if (get_sigset(&newset, uset))
401 return -EFAULT;
402 sigdelsetmask(&newset, ~_BLOCKABLE);
403
404 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000405 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000407 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 spin_unlock_irq(&current->sighand->siglock);
409
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000410 current->state = TASK_INTERRUPTIBLE;
411 schedule();
412 set_thread_flag(TIF_RESTORE_SIGMASK);
413 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900416asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
417 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
419 struct k_sigaction new_ka, old_ka;
420 int ret;
421 int err = 0;
422
423 if (act) {
424 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000425 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
428 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000429 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900430 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
432 err |= __get_user(mask, &act->sa_mask.sig[0]);
433 if (err)
434 return -EFAULT;
435
436 siginitset(&new_ka.sa.sa_mask, mask);
437 }
438
439 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
440
441 if (!ret && oact) {
442 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000443 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
445 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
446 &oact->sa_handler);
447 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000448 err |= __put_user(0, &oact->sa_mask.sig[1]);
449 err |= __put_user(0, &oact->sa_mask.sig[2]);
450 err |= __put_user(0, &oact->sa_mask.sig[3]);
451 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 return -EFAULT;
453 }
454
455 return ret;
456}
457
458asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
459{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900460 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
461 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 unsigned long usp = regs.regs[29];
463 stack_t kss, koss;
464 int ret, err = 0;
465 mm_segment_t old_fs = get_fs();
466 s32 sp;
467
468 if (uss) {
469 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
470 return -EFAULT;
471 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900472 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 err |= __get_user(kss.ss_size, &uss->ss_size);
474 err |= __get_user(kss.ss_flags, &uss->ss_flags);
475 if (err)
476 return -EFAULT;
477 }
478
479 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900480 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
481 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 set_fs (old_fs);
483
484 if (!ret && uoss) {
485 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
486 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900487 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 err |= __put_user(sp, &uoss->ss_sp);
489 err |= __put_user(koss.ss_size, &uoss->ss_size);
490 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
491 if (err)
492 return -EFAULT;
493 }
494 return ret;
495}
496
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900497int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
499 int err;
500
501 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
502 return -EFAULT;
503
504 /* If you change siginfo_t structure, please be sure
505 this code is fixed accordingly.
506 It should never copy any pad contained in the structure
507 to avoid security leaks, but must copy the generic
508 3 ints plus the relevant union member.
509 This routine must convert siginfo from 64bit to 32bit as well
510 at the same time. */
511 err = __put_user(from->si_signo, &to->si_signo);
512 err |= __put_user(from->si_errno, &to->si_errno);
513 err |= __put_user((short)from->si_code, &to->si_code);
514 if (from->si_code < 0)
515 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
516 else {
517 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000518 case __SI_TIMER >> 16:
519 err |= __put_user(from->si_tid, &to->si_tid);
520 err |= __put_user(from->si_overrun, &to->si_overrun);
521 err |= __put_user(from->si_int, &to->si_int);
522 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 case __SI_CHLD >> 16:
524 err |= __put_user(from->si_utime, &to->si_utime);
525 err |= __put_user(from->si_stime, &to->si_stime);
526 err |= __put_user(from->si_status, &to->si_status);
527 default:
528 err |= __put_user(from->si_pid, &to->si_pid);
529 err |= __put_user(from->si_uid, &to->si_uid);
530 break;
531 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900532 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 break;
534 case __SI_POLL >> 16:
535 err |= __put_user(from->si_band, &to->si_band);
536 err |= __put_user(from->si_fd, &to->si_fd);
537 break;
538 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
539 case __SI_MESGQ >> 16:
540 err |= __put_user(from->si_pid, &to->si_pid);
541 err |= __put_user(from->si_uid, &to->si_uid);
542 err |= __put_user(from->si_int, &to->si_int);
543 break;
544 }
545 }
546 return err;
547}
548
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100549asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
Ralf Baechledd02f062007-02-13 00:50:57 +0000551 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900553 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Ralf Baechledd02f062007-02-13 00:50:57 +0000555 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
557 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000558 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 goto badframe;
560
561 sigdelsetmask(&blocked, ~_BLOCKABLE);
562 spin_lock_irq(&current->sighand->siglock);
563 current->blocked = blocked;
564 recalc_sigpending();
565 spin_unlock_irq(&current->sighand->siglock);
566
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900567 sig = restore_sigcontext32(&regs, &frame->sf_sc);
568 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900570 else if (sig)
571 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573 /*
574 * Don't let your children do this ...
575 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 __asm__ __volatile__(
577 "move\t$29, %0\n\t"
578 "j\tsyscall_exit"
579 :/* no outputs */
580 :"r" (&regs));
581 /* Unreached */
582
583badframe:
584 force_sig(SIGSEGV, current);
585}
586
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100587asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900589 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000590 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 sigset_t set;
592 stack_t st;
593 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900594 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900596 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
598 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000599 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 goto badframe;
601
602 sigdelsetmask(&set, ~_BLOCKABLE);
603 spin_lock_irq(&current->sighand->siglock);
604 current->blocked = set;
605 recalc_sigpending();
606 spin_unlock_irq(&current->sighand->siglock);
607
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900608 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
609 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900611 else if (sig)
612 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 /* The ucontext contains a stack32_t, so we must convert! */
615 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
616 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900617 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
619 goto badframe;
620 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
621 goto badframe;
622
623 /* It is more difficult to avoid calling this function than to
624 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000625 old_fs = get_fs();
626 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900627 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000628 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 /*
631 * Don't let your children do this ...
632 */
633 __asm__ __volatile__(
634 "move\t$29, %0\n\t"
635 "j\tsyscall_exit"
636 :/* no outputs */
637 :"r" (&regs));
638 /* Unreached */
639
640badframe:
641 force_sig(SIGSEGV, current);
642}
643
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000644static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900645 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Ralf Baechledd02f062007-02-13 00:50:57 +0000647 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 int err = 0;
649
650 frame = get_sigframe(ka, regs, sizeof(*frame));
651 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
652 goto give_sigsegv;
653
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100654 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000657 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 if (err)
660 goto give_sigsegv;
661
662 /*
663 * Arguments to signal handler:
664 *
665 * a0 = signal number
666 * a1 = 0 (should be cause)
667 * a2 = pointer to struct sigcontext
668 *
669 * $25 and c0_epc point to the signal handler, $29 points to the
670 * struct sigframe.
671 */
672 regs->regs[ 4] = signr;
673 regs->regs[ 5] = 0;
674 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
675 regs->regs[29] = (unsigned long) frame;
676 regs->regs[31] = (unsigned long) frame->sf_code;
677 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
678
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100679 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100681 frame, regs->cp0_epc, regs->regs[31]);
682
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685give_sigsegv:
686 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000687 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000690static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900691 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900693 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 int err = 0;
695 s32 sp;
696
697 frame = get_sigframe(ka, regs, sizeof(*frame));
698 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
699 goto give_sigsegv;
700
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100701 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
704 err |= copy_siginfo_to_user32(&frame->rs_info, info);
705
706 /* Create the ucontext. */
707 err |= __put_user(0, &frame->rs_uc.uc_flags);
708 err |= __put_user(0, &frame->rs_uc.uc_link);
709 sp = (int) (long) current->sas_ss_sp;
710 err |= __put_user(sp,
711 &frame->rs_uc.uc_stack.ss_sp);
712 err |= __put_user(sas_ss_flags(regs->regs[29]),
713 &frame->rs_uc.uc_stack.ss_flags);
714 err |= __put_user(current->sas_ss_size,
715 &frame->rs_uc.uc_stack.ss_size);
716 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000717 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 if (err)
720 goto give_sigsegv;
721
722 /*
723 * Arguments to signal handler:
724 *
725 * a0 = signal number
726 * a1 = 0 (should be cause)
727 * a2 = pointer to ucontext
728 *
729 * $25 and c0_epc point to the signal handler, $29 points to
730 * the struct rt_sigframe32.
731 */
732 regs->regs[ 4] = signr;
733 regs->regs[ 5] = (unsigned long) &frame->rs_info;
734 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
735 regs->regs[29] = (unsigned long) frame;
736 regs->regs[31] = (unsigned long) frame->rs_code;
737 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
738
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100739 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100741 frame, regs->cp0_epc, regs->regs[31]);
742
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000743 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745give_sigsegv:
746 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000747 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000750/*
751 * o32 compatibility on 64-bit kernels, without DSP ASE
752 */
753struct mips_abi mips_abi_32 = {
754 .setup_frame = setup_frame_32,
755 .setup_rt_frame = setup_rt_frame_32,
756 .restart = __NR_O32_restart_syscall
757};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900759asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900760 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 unsigned int sigsetsize)
762{
763 struct k_sigaction new_sa, old_sa;
764 int ret = -EINVAL;
765
766 /* XXX: Don't preclude handling different sized sigset_t's. */
767 if (sigsetsize != sizeof(sigset_t))
768 goto out;
769
770 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000771 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 int err = 0;
773
774 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
775 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000776 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900777 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
779 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
780 if (err)
781 return -EFAULT;
782 }
783
784 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
785
786 if (!ret && oact) {
787 int err = 0;
788
789 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
790 return -EFAULT;
791
792 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
793 &oact->sa_handler);
794 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
795 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
796 if (err)
797 return -EFAULT;
798 }
799out:
800 return ret;
801}
802
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900803asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900804 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 sigset_t old_set, new_set;
807 int ret;
808 mm_segment_t old_fs = get_fs();
809
810 if (set && get_sigset(&new_set, set))
811 return -EFAULT;
812
813 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900814 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
815 oset ? (sigset_t __user *)&old_set : NULL,
816 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 set_fs (old_fs);
818
819 if (!ret && oset && put_sigset(&old_set, oset))
820 return -EFAULT;
821
822 return ret;
823}
824
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900825asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 unsigned int sigsetsize)
827{
828 int ret;
829 sigset_t set;
830 mm_segment_t old_fs = get_fs();
831
832 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900833 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 set_fs (old_fs);
835
836 if (!ret && put_sigset(&set, uset))
837 return -EFAULT;
838
839 return ret;
840}
841
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900842asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
844 siginfo_t info;
845 int ret;
846 mm_segment_t old_fs = get_fs();
847
848 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
849 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
850 return -EFAULT;
851 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900852 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 set_fs (old_fs);
854 return ret;
855}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000856
857asmlinkage long
858sys32_waitid(int which, compat_pid_t pid,
859 compat_siginfo_t __user *uinfo, int options,
860 struct compat_rusage __user *uru)
861{
862 siginfo_t info;
863 struct rusage ru;
864 long ret;
865 mm_segment_t old_fs = get_fs();
866
867 info.si_signo = 0;
868 set_fs (KERNEL_DS);
869 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
870 uru ? (struct rusage __user *) &ru : NULL);
871 set_fs (old_fs);
872
873 if (ret < 0 || info.si_signo == 0)
874 return ret;
875
876 if (uru && (ret = put_compat_rusage(&ru, uru)))
877 return ret;
878
879 BUG_ON(info.si_code & __SI_MASK);
880 info.si_code |= __SI_CHLD;
881 return copy_siginfo_to_user32(uinfo, &info);
882}