blob: 572c610db1b11c4fe2b31da5150abaa431936be1 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/suspend.h>
22#include <linux/compiler.h>
Atsushi Nemotofaea6232007-04-16 23:19:44 +090023#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Ralf Baechlee50c0a8f2005-05-31 11:49:19 +000025#include <asm/abi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/asm.h>
Ralf Baechle431dc802007-02-13 00:05:11 +000027#include <asm/compat-signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/bitops.h>
29#include <asm/cacheflush.h>
30#include <asm/sim.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/ucontext.h>
32#include <asm/system.h>
33#include <asm/fpu.h>
Ralf Baechle02416dc2005-06-15 13:00:12 +000034#include <asm/war.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +010036#include "signal-common.h"
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/*
39 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
40 */
41#define __NR_O32_sigreturn 4119
42#define __NR_O32_rt_sigreturn 4193
Ralf Baechle151fd6a2007-02-15 11:40:37 +000043#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/* 32-bit compatibility types */
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047typedef unsigned int __sighandler32_t;
48typedef void (*vfptr_t)(void);
49
50struct sigaction32 {
51 unsigned int sa_flags;
52 __sighandler32_t sa_handler;
53 compat_sigset_t sa_mask;
54};
55
56/* IRIX compatible stack_t */
57typedef struct sigaltstack32 {
58 s32 ss_sp;
59 compat_size_t ss_size;
60 int ss_flags;
61} stack32_t;
62
63struct ucontext32 {
64 u32 uc_flags;
65 s32 uc_link;
66 stack32_t uc_stack;
67 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +000068 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069};
70
Ralf Baechledd02f062007-02-13 00:50:57 +000071/*
72 * Horribly complicated - with the bloody RM9000 workarounds enabled
73 * the signal trampolines is moving to the end of the structure so we can
74 * increase the alignment without breaking software compatibility.
75 */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010076#if ICACHE_REFILLS_WORKAROUND_WAR == 0
77
Ralf Baechledd02f062007-02-13 00:50:57 +000078struct sigframe32 {
79 u32 sf_ass[4]; /* argument save space for o32 */
80 u32 sf_code[2]; /* signal trampoline */
81 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090082 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000083};
84
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010085struct rt_sigframe32 {
86 u32 rs_ass[4]; /* argument save space for o32 */
87 u32 rs_code[2]; /* signal trampoline */
88 compat_siginfo_t rs_info;
89 struct ucontext32 rs_uc;
90};
91
92#else /* ICACHE_REFILLS_WORKAROUND_WAR */
93
Ralf Baechledd02f062007-02-13 00:50:57 +000094struct sigframe32 {
95 u32 sf_ass[4]; /* argument save space for o32 */
96 u32 sf_pad[2];
97 struct sigcontext32 sf_sc; /* hw context */
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090098 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000099 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
100};
101
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100102struct rt_sigframe32 {
103 u32 rs_ass[4]; /* argument save space for o32 */
104 u32 rs_pad[2];
105 compat_siginfo_t rs_info;
106 struct ucontext32 rs_uc;
107 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
108};
109
110#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
111
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100112/*
113 * sigcontext handlers
114 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900115static int protected_save_fp_context32(struct sigcontext32 __user *sc)
116{
117 int err;
118 while (1) {
119 lock_fpu_owner();
120 own_fpu_inatomic(1);
121 err = save_fp_context32(sc); /* this might fail */
122 unlock_fpu_owner();
123 if (likely(!err))
124 break;
125 /* touch the sigcontext and try again */
126 err = __put_user(0, &sc->sc_fpregs[0]) |
127 __put_user(0, &sc->sc_fpregs[31]) |
128 __put_user(0, &sc->sc_fpc_csr);
129 if (err)
130 break; /* really bad sigcontext */
131 }
132 return err;
133}
134
135static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
136{
137 int err, tmp;
138 while (1) {
139 lock_fpu_owner();
140 own_fpu_inatomic(0);
141 err = restore_fp_context32(sc); /* this might fail */
142 unlock_fpu_owner();
143 if (likely(!err))
144 break;
145 /* touch the sigcontext and try again */
146 err = __get_user(tmp, &sc->sc_fpregs[0]) |
147 __get_user(tmp, &sc->sc_fpregs[31]) |
148 __get_user(tmp, &sc->sc_fpc_csr);
149 if (err)
150 break; /* really bad sigcontext */
151 }
152 return err;
153}
154
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100155static int setup_sigcontext32(struct pt_regs *regs,
156 struct sigcontext32 __user *sc)
157{
158 int err = 0;
159 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900160 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100161
162 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100163
164 err |= __put_user(0, &sc->sc_regs[0]);
165 for (i = 1; i < 32; i++)
166 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
167
168 err |= __put_user(regs->hi, &sc->sc_mdhi);
169 err |= __put_user(regs->lo, &sc->sc_mdlo);
170 if (cpu_has_dsp) {
171 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
172 err |= __put_user(mfhi1(), &sc->sc_hi1);
173 err |= __put_user(mflo1(), &sc->sc_lo1);
174 err |= __put_user(mfhi2(), &sc->sc_hi2);
175 err |= __put_user(mflo2(), &sc->sc_lo2);
176 err |= __put_user(mfhi3(), &sc->sc_hi3);
177 err |= __put_user(mflo3(), &sc->sc_lo3);
178 }
179
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900180 used_math = !!used_math();
181 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100182
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900183 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100184 /*
185 * Save FPU state to signal context. Signal handler
186 * will "inherit" current FPU state.
187 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900188 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100189 }
190 return err;
191}
192
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900193static int
194check_and_restore_fp_context32(struct sigcontext32 __user *sc)
195{
196 int err, sig;
197
198 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
199 if (err > 0)
200 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900201 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900202 return err ?: sig;
203}
204
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100205static int restore_sigcontext32(struct pt_regs *regs,
206 struct sigcontext32 __user *sc)
207{
208 u32 used_math;
209 int err = 0;
210 s32 treg;
211 int i;
212
213 /* Always make any pending restarted system calls return -EINTR */
214 current_thread_info()->restart_block.fn = do_no_restart_syscall;
215
216 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
217 err |= __get_user(regs->hi, &sc->sc_mdhi);
218 err |= __get_user(regs->lo, &sc->sc_mdlo);
219 if (cpu_has_dsp) {
220 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
221 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
222 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
223 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
224 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
225 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
226 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
227 }
228
229 for (i = 1; i < 32; i++)
230 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
231
232 err |= __get_user(used_math, &sc->sc_used_math);
233 conditional_used_math(used_math);
234
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900235 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100236 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900237 if (!err)
238 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100239 } else {
240 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900241 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100242 }
243
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100244 return err;
245}
246
247/*
248 *
249 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250extern void __put_sigset_unknown_nsig(void);
251extern void __get_sigset_unknown_nsig(void);
252
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900253static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
255 int err = 0;
256
257 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
258 return -EFAULT;
259
260 switch (_NSIG_WORDS) {
261 default:
262 __put_sigset_unknown_nsig();
263 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100264 err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
265 err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100267 err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
268 err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 }
270
271 return err;
272}
273
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900274static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
276 int err = 0;
277 unsigned long sig[4];
278
279 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
280 return -EFAULT;
281
282 switch (_NSIG_WORDS) {
283 default:
284 __get_sigset_unknown_nsig();
285 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100286 err |= __get_user(sig[3], &ubuf->sig[3]);
287 err |= __get_user(sig[2], &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 kbuf->sig[1] = sig[2] | (sig[3] << 32);
289 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100290 err |= __get_user(sig[1], &ubuf->sig[1]);
291 err |= __get_user(sig[0], &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 kbuf->sig[0] = sig[0] | (sig[1] << 32);
293 }
294
295 return err;
296}
297
298/*
299 * Atomically swap in the new signal mask, and wait for a signal.
300 */
301
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100302asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900304 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000305 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900307 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (get_sigset(&newset, uset))
309 return -EFAULT;
310 sigdelsetmask(&newset, ~_BLOCKABLE);
311
312 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000313 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 current->blocked = newset;
315 recalc_sigpending();
316 spin_unlock_irq(&current->sighand->siglock);
317
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000318 current->state = TASK_INTERRUPTIBLE;
319 schedule();
320 set_thread_flag(TIF_RESTORE_SIGMASK);
321 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100324asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900326 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000327 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000328 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 /* XXX Don't preclude handling different sized sigset_t's. */
331 sigsetsize = regs.regs[5];
332 if (sigsetsize != sizeof(compat_sigset_t))
333 return -EINVAL;
334
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900335 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 if (get_sigset(&newset, uset))
337 return -EFAULT;
338 sigdelsetmask(&newset, ~_BLOCKABLE);
339
340 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000341 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000343 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 spin_unlock_irq(&current->sighand->siglock);
345
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000346 current->state = TASK_INTERRUPTIBLE;
347 schedule();
348 set_thread_flag(TIF_RESTORE_SIGMASK);
349 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900352asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
353 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 struct k_sigaction new_ka, old_ka;
356 int ret;
357 int err = 0;
358
359 if (act) {
360 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000361 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
364 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000365 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900366 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
368 err |= __get_user(mask, &act->sa_mask.sig[0]);
369 if (err)
370 return -EFAULT;
371
372 siginitset(&new_ka.sa.sa_mask, mask);
373 }
374
375 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
376
377 if (!ret && oact) {
378 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000379 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
381 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
382 &oact->sa_handler);
383 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000384 err |= __put_user(0, &oact->sa_mask.sig[1]);
385 err |= __put_user(0, &oact->sa_mask.sig[2]);
386 err |= __put_user(0, &oact->sa_mask.sig[3]);
387 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return -EFAULT;
389 }
390
391 return ret;
392}
393
394asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
395{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900396 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
397 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 unsigned long usp = regs.regs[29];
399 stack_t kss, koss;
400 int ret, err = 0;
401 mm_segment_t old_fs = get_fs();
402 s32 sp;
403
404 if (uss) {
405 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
406 return -EFAULT;
407 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900408 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 err |= __get_user(kss.ss_size, &uss->ss_size);
410 err |= __get_user(kss.ss_flags, &uss->ss_flags);
411 if (err)
412 return -EFAULT;
413 }
414
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100415 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900416 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
417 uoss ? (stack_t __user *)&koss : NULL, usp);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100418 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 if (!ret && uoss) {
421 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
422 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900423 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 err |= __put_user(sp, &uoss->ss_sp);
425 err |= __put_user(koss.ss_size, &uoss->ss_size);
426 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
427 if (err)
428 return -EFAULT;
429 }
430 return ret;
431}
432
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900433int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
435 int err;
436
437 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
438 return -EFAULT;
439
440 /* If you change siginfo_t structure, please be sure
441 this code is fixed accordingly.
442 It should never copy any pad contained in the structure
443 to avoid security leaks, but must copy the generic
444 3 ints plus the relevant union member.
445 This routine must convert siginfo from 64bit to 32bit as well
446 at the same time. */
447 err = __put_user(from->si_signo, &to->si_signo);
448 err |= __put_user(from->si_errno, &to->si_errno);
449 err |= __put_user((short)from->si_code, &to->si_code);
450 if (from->si_code < 0)
451 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
452 else {
453 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000454 case __SI_TIMER >> 16:
455 err |= __put_user(from->si_tid, &to->si_tid);
456 err |= __put_user(from->si_overrun, &to->si_overrun);
457 err |= __put_user(from->si_int, &to->si_int);
458 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 case __SI_CHLD >> 16:
460 err |= __put_user(from->si_utime, &to->si_utime);
461 err |= __put_user(from->si_stime, &to->si_stime);
462 err |= __put_user(from->si_status, &to->si_status);
463 default:
464 err |= __put_user(from->si_pid, &to->si_pid);
465 err |= __put_user(from->si_uid, &to->si_uid);
466 break;
467 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900468 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 break;
470 case __SI_POLL >> 16:
471 err |= __put_user(from->si_band, &to->si_band);
472 err |= __put_user(from->si_fd, &to->si_fd);
473 break;
474 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
475 case __SI_MESGQ >> 16:
476 err |= __put_user(from->si_pid, &to->si_pid);
477 err |= __put_user(from->si_uid, &to->si_uid);
478 err |= __put_user(from->si_int, &to->si_int);
479 break;
480 }
481 }
482 return err;
483}
484
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100485asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Ralf Baechledd02f062007-02-13 00:50:57 +0000487 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900489 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Ralf Baechledd02f062007-02-13 00:50:57 +0000491 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
493 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000494 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 goto badframe;
496
497 sigdelsetmask(&blocked, ~_BLOCKABLE);
498 spin_lock_irq(&current->sighand->siglock);
499 current->blocked = blocked;
500 recalc_sigpending();
501 spin_unlock_irq(&current->sighand->siglock);
502
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900503 sig = restore_sigcontext32(&regs, &frame->sf_sc);
504 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900506 else if (sig)
507 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 /*
510 * Don't let your children do this ...
511 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 __asm__ __volatile__(
513 "move\t$29, %0\n\t"
514 "j\tsyscall_exit"
515 :/* no outputs */
516 :"r" (&regs));
517 /* Unreached */
518
519badframe:
520 force_sig(SIGSEGV, current);
521}
522
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100523asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900525 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000526 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 sigset_t set;
528 stack_t st;
529 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900530 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900532 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
534 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000535 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 goto badframe;
537
538 sigdelsetmask(&set, ~_BLOCKABLE);
539 spin_lock_irq(&current->sighand->siglock);
540 current->blocked = set;
541 recalc_sigpending();
542 spin_unlock_irq(&current->sighand->siglock);
543
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900544 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
545 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900547 else if (sig)
548 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 /* The ucontext contains a stack32_t, so we must convert! */
551 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
552 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900553 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
555 goto badframe;
556 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
557 goto badframe;
558
559 /* It is more difficult to avoid calling this function than to
560 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000561 old_fs = get_fs();
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100562 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900563 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100564 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566 /*
567 * Don't let your children do this ...
568 */
569 __asm__ __volatile__(
570 "move\t$29, %0\n\t"
571 "j\tsyscall_exit"
572 :/* no outputs */
573 :"r" (&regs));
574 /* Unreached */
575
576badframe:
577 force_sig(SIGSEGV, current);
578}
579
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000580static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900581 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
Ralf Baechledd02f062007-02-13 00:50:57 +0000583 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 int err = 0;
585
586 frame = get_sigframe(ka, regs, sizeof(*frame));
587 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
588 goto give_sigsegv;
589
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100590 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000593 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 if (err)
596 goto give_sigsegv;
597
598 /*
599 * Arguments to signal handler:
600 *
601 * a0 = signal number
602 * a1 = 0 (should be cause)
603 * a2 = pointer to struct sigcontext
604 *
605 * $25 and c0_epc point to the signal handler, $29 points to the
606 * struct sigframe.
607 */
608 regs->regs[ 4] = signr;
609 regs->regs[ 5] = 0;
610 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
611 regs->regs[29] = (unsigned long) frame;
612 regs->regs[31] = (unsigned long) frame->sf_code;
613 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
614
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100615 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100617 frame, regs->cp0_epc, regs->regs[31]);
618
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000619 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621give_sigsegv:
622 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000623 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624}
625
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000626static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900627 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900629 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 int err = 0;
631 s32 sp;
632
633 frame = get_sigframe(ka, regs, sizeof(*frame));
634 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
635 goto give_sigsegv;
636
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100637 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
640 err |= copy_siginfo_to_user32(&frame->rs_info, info);
641
642 /* Create the ucontext. */
643 err |= __put_user(0, &frame->rs_uc.uc_flags);
644 err |= __put_user(0, &frame->rs_uc.uc_link);
645 sp = (int) (long) current->sas_ss_sp;
646 err |= __put_user(sp,
647 &frame->rs_uc.uc_stack.ss_sp);
648 err |= __put_user(sas_ss_flags(regs->regs[29]),
649 &frame->rs_uc.uc_stack.ss_flags);
650 err |= __put_user(current->sas_ss_size,
651 &frame->rs_uc.uc_stack.ss_size);
652 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000653 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 if (err)
656 goto give_sigsegv;
657
658 /*
659 * Arguments to signal handler:
660 *
661 * a0 = signal number
662 * a1 = 0 (should be cause)
663 * a2 = pointer to ucontext
664 *
665 * $25 and c0_epc point to the signal handler, $29 points to
666 * the struct rt_sigframe32.
667 */
668 regs->regs[ 4] = signr;
669 regs->regs[ 5] = (unsigned long) &frame->rs_info;
670 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
671 regs->regs[29] = (unsigned long) frame;
672 regs->regs[31] = (unsigned long) frame->rs_code;
673 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
674
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100675 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100677 frame, regs->cp0_epc, regs->regs[31]);
678
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000679 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681give_sigsegv:
682 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000683 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000686/*
687 * o32 compatibility on 64-bit kernels, without DSP ASE
688 */
689struct mips_abi mips_abi_32 = {
690 .setup_frame = setup_frame_32,
691 .setup_rt_frame = setup_rt_frame_32,
692 .restart = __NR_O32_restart_syscall
693};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900695asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900696 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 unsigned int sigsetsize)
698{
699 struct k_sigaction new_sa, old_sa;
700 int ret = -EINVAL;
701
702 /* XXX: Don't preclude handling different sized sigset_t's. */
703 if (sigsetsize != sizeof(sigset_t))
704 goto out;
705
706 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000707 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 int err = 0;
709
710 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
711 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000712 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900713 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
715 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
716 if (err)
717 return -EFAULT;
718 }
719
720 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
721
722 if (!ret && oact) {
723 int err = 0;
724
725 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
726 return -EFAULT;
727
728 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
729 &oact->sa_handler);
730 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
731 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
732 if (err)
733 return -EFAULT;
734 }
735out:
736 return ret;
737}
738
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900739asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900740 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
742 sigset_t old_set, new_set;
743 int ret;
744 mm_segment_t old_fs = get_fs();
745
746 if (set && get_sigset(&new_set, set))
747 return -EFAULT;
748
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100749 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900750 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
751 oset ? (sigset_t __user *)&old_set : NULL,
752 sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100753 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
755 if (!ret && oset && put_sigset(&old_set, oset))
756 return -EFAULT;
757
758 return ret;
759}
760
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900761asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 unsigned int sigsetsize)
763{
764 int ret;
765 sigset_t set;
766 mm_segment_t old_fs = get_fs();
767
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100768 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900769 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100770 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 if (!ret && put_sigset(&set, uset))
773 return -EFAULT;
774
775 return ret;
776}
777
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900778asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
780 siginfo_t info;
781 int ret;
782 mm_segment_t old_fs = get_fs();
783
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100784 if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
785 copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return -EFAULT;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100787 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900788 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100789 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return ret;
791}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000792
793asmlinkage long
794sys32_waitid(int which, compat_pid_t pid,
795 compat_siginfo_t __user *uinfo, int options,
796 struct compat_rusage __user *uru)
797{
798 siginfo_t info;
799 struct rusage ru;
800 long ret;
801 mm_segment_t old_fs = get_fs();
802
803 info.si_signo = 0;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100804 set_fs(KERNEL_DS);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000805 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
806 uru ? (struct rusage __user *) &ru : NULL);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100807 set_fs(old_fs);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000808
809 if (ret < 0 || info.si_signo == 0)
810 return ret;
811
812 if (uru && (ret = put_compat_rusage(&ru, uru)))
813 return ret;
814
815 BUG_ON(info.si_code & __SI_MASK);
816 info.si_code |= __SI_CHLD;
817 return copy_siginfo_to_user32(uinfo, &info);
818}