blob: 486b8e5f52d0b5e3f21e17b82f5a70f5cb3a3c17 [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-Huu36a1f2c22007-02-05 15:24:22 +010037#include "signal-common.h"
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039/*
40 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
41 */
42#define __NR_O32_sigreturn 4119
43#define __NR_O32_rt_sigreturn 4193
Ralf Baechle151fd6a2007-02-15 11:40:37 +000044#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046/* 32-bit compatibility types */
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048typedef unsigned int __sighandler32_t;
49typedef void (*vfptr_t)(void);
50
51struct sigaction32 {
52 unsigned int sa_flags;
53 __sighandler32_t sa_handler;
54 compat_sigset_t sa_mask;
55};
56
57/* IRIX compatible stack_t */
58typedef struct sigaltstack32 {
59 s32 ss_sp;
60 compat_size_t ss_size;
61 int ss_flags;
62} stack32_t;
63
64struct ucontext32 {
65 u32 uc_flags;
66 s32 uc_link;
67 stack32_t uc_stack;
68 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +000069 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070};
71
Ralf Baechledd02f062007-02-13 00:50:57 +000072/*
73 * Horribly complicated - with the bloody RM9000 workarounds enabled
74 * the signal trampolines is moving to the end of the structure so we can
75 * increase the alignment without breaking software compatibility.
76 */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010077#if ICACHE_REFILLS_WORKAROUND_WAR == 0
78
Ralf Baechledd02f062007-02-13 00:50:57 +000079struct sigframe32 {
80 u32 sf_ass[4]; /* argument save space for o32 */
81 u32 sf_code[2]; /* signal trampoline */
82 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090083 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000084};
85
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010086struct rt_sigframe32 {
87 u32 rs_ass[4]; /* argument save space for o32 */
88 u32 rs_code[2]; /* signal trampoline */
89 compat_siginfo_t rs_info;
90 struct ucontext32 rs_uc;
91};
92
93#else /* ICACHE_REFILLS_WORKAROUND_WAR */
94
Ralf Baechledd02f062007-02-13 00:50:57 +000095struct sigframe32 {
96 u32 sf_ass[4]; /* argument save space for o32 */
97 u32 sf_pad[2];
98 struct sigcontext32 sf_sc; /* hw context */
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090099 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +0000100 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
101};
102
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100103struct rt_sigframe32 {
104 u32 rs_ass[4]; /* argument save space for o32 */
105 u32 rs_pad[2];
106 compat_siginfo_t rs_info;
107 struct ucontext32 rs_uc;
108 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
109};
110
111#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
112
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100113/*
114 * sigcontext handlers
115 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900116static int protected_save_fp_context32(struct sigcontext32 __user *sc)
117{
118 int err;
119 while (1) {
120 lock_fpu_owner();
121 own_fpu_inatomic(1);
122 err = save_fp_context32(sc); /* this might fail */
123 unlock_fpu_owner();
124 if (likely(!err))
125 break;
126 /* touch the sigcontext and try again */
127 err = __put_user(0, &sc->sc_fpregs[0]) |
128 __put_user(0, &sc->sc_fpregs[31]) |
129 __put_user(0, &sc->sc_fpc_csr);
130 if (err)
131 break; /* really bad sigcontext */
132 }
133 return err;
134}
135
136static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
137{
138 int err, tmp;
139 while (1) {
140 lock_fpu_owner();
141 own_fpu_inatomic(0);
142 err = restore_fp_context32(sc); /* this might fail */
143 unlock_fpu_owner();
144 if (likely(!err))
145 break;
146 /* touch the sigcontext and try again */
147 err = __get_user(tmp, &sc->sc_fpregs[0]) |
148 __get_user(tmp, &sc->sc_fpregs[31]) |
149 __get_user(tmp, &sc->sc_fpc_csr);
150 if (err)
151 break; /* really bad sigcontext */
152 }
153 return err;
154}
155
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100156static int setup_sigcontext32(struct pt_regs *regs,
157 struct sigcontext32 __user *sc)
158{
159 int err = 0;
160 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900161 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100162
163 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100164
165 err |= __put_user(0, &sc->sc_regs[0]);
166 for (i = 1; i < 32; i++)
167 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
168
169 err |= __put_user(regs->hi, &sc->sc_mdhi);
170 err |= __put_user(regs->lo, &sc->sc_mdlo);
171 if (cpu_has_dsp) {
172 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
173 err |= __put_user(mfhi1(), &sc->sc_hi1);
174 err |= __put_user(mflo1(), &sc->sc_lo1);
175 err |= __put_user(mfhi2(), &sc->sc_hi2);
176 err |= __put_user(mflo2(), &sc->sc_lo2);
177 err |= __put_user(mfhi3(), &sc->sc_hi3);
178 err |= __put_user(mflo3(), &sc->sc_lo3);
179 }
180
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900181 used_math = !!used_math();
182 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100183
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900184 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100185 /*
186 * Save FPU state to signal context. Signal handler
187 * will "inherit" current FPU state.
188 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900189 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100190 }
191 return err;
192}
193
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900194static int
195check_and_restore_fp_context32(struct sigcontext32 __user *sc)
196{
197 int err, sig;
198
199 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
200 if (err > 0)
201 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900202 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900203 return err ?: sig;
204}
205
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100206static int restore_sigcontext32(struct pt_regs *regs,
207 struct sigcontext32 __user *sc)
208{
209 u32 used_math;
210 int err = 0;
211 s32 treg;
212 int i;
213
214 /* Always make any pending restarted system calls return -EINTR */
215 current_thread_info()->restart_block.fn = do_no_restart_syscall;
216
217 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
218 err |= __get_user(regs->hi, &sc->sc_mdhi);
219 err |= __get_user(regs->lo, &sc->sc_mdlo);
220 if (cpu_has_dsp) {
221 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
222 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
223 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
224 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
225 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
226 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
227 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
228 }
229
230 for (i = 1; i < 32; i++)
231 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
232
233 err |= __get_user(used_math, &sc->sc_used_math);
234 conditional_used_math(used_math);
235
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900236 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100237 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900238 if (!err)
239 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100240 } else {
241 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900242 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100243 }
244
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100245 return err;
246}
247
248/*
249 *
250 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251extern void __put_sigset_unknown_nsig(void);
252extern void __get_sigset_unknown_nsig(void);
253
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900254static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 int err = 0;
257
258 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
259 return -EFAULT;
260
261 switch (_NSIG_WORDS) {
262 default:
263 __put_sigset_unknown_nsig();
264 case 2:
265 err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
266 err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
267 case 1:
268 err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
269 err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
270 }
271
272 return err;
273}
274
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900275static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
277 int err = 0;
278 unsigned long sig[4];
279
280 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
281 return -EFAULT;
282
283 switch (_NSIG_WORDS) {
284 default:
285 __get_sigset_unknown_nsig();
286 case 2:
287 err |= __get_user (sig[3], &ubuf->sig[3]);
288 err |= __get_user (sig[2], &ubuf->sig[2]);
289 kbuf->sig[1] = sig[2] | (sig[3] << 32);
290 case 1:
291 err |= __get_user (sig[1], &ubuf->sig[1]);
292 err |= __get_user (sig[0], &ubuf->sig[0]);
293 kbuf->sig[0] = sig[0] | (sig[1] << 32);
294 }
295
296 return err;
297}
298
299/*
300 * Atomically swap in the new signal mask, and wait for a signal.
301 */
302
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100303asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900305 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000306 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900308 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 if (get_sigset(&newset, uset))
310 return -EFAULT;
311 sigdelsetmask(&newset, ~_BLOCKABLE);
312
313 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000314 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 current->blocked = newset;
316 recalc_sigpending();
317 spin_unlock_irq(&current->sighand->siglock);
318
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000319 current->state = TASK_INTERRUPTIBLE;
320 schedule();
321 set_thread_flag(TIF_RESTORE_SIGMASK);
322 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100325asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900327 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000328 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000329 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 /* XXX Don't preclude handling different sized sigset_t's. */
332 sigsetsize = regs.regs[5];
333 if (sigsetsize != sizeof(compat_sigset_t))
334 return -EINVAL;
335
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900336 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 if (get_sigset(&newset, uset))
338 return -EFAULT;
339 sigdelsetmask(&newset, ~_BLOCKABLE);
340
341 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000342 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000344 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 spin_unlock_irq(&current->sighand->siglock);
346
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000347 current->state = TASK_INTERRUPTIBLE;
348 schedule();
349 set_thread_flag(TIF_RESTORE_SIGMASK);
350 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351}
352
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900353asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
354 struct sigaction32 __user *oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356 struct k_sigaction new_ka, old_ka;
357 int ret;
358 int err = 0;
359
360 if (act) {
361 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000362 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
365 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000366 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900367 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
369 err |= __get_user(mask, &act->sa_mask.sig[0]);
370 if (err)
371 return -EFAULT;
372
373 siginitset(&new_ka.sa.sa_mask, mask);
374 }
375
376 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
377
378 if (!ret && oact) {
379 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000380 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
382 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
383 &oact->sa_handler);
384 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000385 err |= __put_user(0, &oact->sa_mask.sig[1]);
386 err |= __put_user(0, &oact->sa_mask.sig[2]);
387 err |= __put_user(0, &oact->sa_mask.sig[3]);
388 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return -EFAULT;
390 }
391
392 return ret;
393}
394
395asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
396{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900397 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
398 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 unsigned long usp = regs.regs[29];
400 stack_t kss, koss;
401 int ret, err = 0;
402 mm_segment_t old_fs = get_fs();
403 s32 sp;
404
405 if (uss) {
406 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
407 return -EFAULT;
408 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900409 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 err |= __get_user(kss.ss_size, &uss->ss_size);
411 err |= __get_user(kss.ss_flags, &uss->ss_flags);
412 if (err)
413 return -EFAULT;
414 }
415
416 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900417 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
418 uoss ? (stack_t __user *)&koss : NULL, usp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 set_fs (old_fs);
420
421 if (!ret && uoss) {
422 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
423 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900424 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 err |= __put_user(sp, &uoss->ss_sp);
426 err |= __put_user(koss.ss_size, &uoss->ss_size);
427 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
428 if (err)
429 return -EFAULT;
430 }
431 return ret;
432}
433
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900434int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 int err;
437
438 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
439 return -EFAULT;
440
441 /* If you change siginfo_t structure, please be sure
442 this code is fixed accordingly.
443 It should never copy any pad contained in the structure
444 to avoid security leaks, but must copy the generic
445 3 ints plus the relevant union member.
446 This routine must convert siginfo from 64bit to 32bit as well
447 at the same time. */
448 err = __put_user(from->si_signo, &to->si_signo);
449 err |= __put_user(from->si_errno, &to->si_errno);
450 err |= __put_user((short)from->si_code, &to->si_code);
451 if (from->si_code < 0)
452 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
453 else {
454 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000455 case __SI_TIMER >> 16:
456 err |= __put_user(from->si_tid, &to->si_tid);
457 err |= __put_user(from->si_overrun, &to->si_overrun);
458 err |= __put_user(from->si_int, &to->si_int);
459 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 case __SI_CHLD >> 16:
461 err |= __put_user(from->si_utime, &to->si_utime);
462 err |= __put_user(from->si_stime, &to->si_stime);
463 err |= __put_user(from->si_status, &to->si_status);
464 default:
465 err |= __put_user(from->si_pid, &to->si_pid);
466 err |= __put_user(from->si_uid, &to->si_uid);
467 break;
468 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900469 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 break;
471 case __SI_POLL >> 16:
472 err |= __put_user(from->si_band, &to->si_band);
473 err |= __put_user(from->si_fd, &to->si_fd);
474 break;
475 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
476 case __SI_MESGQ >> 16:
477 err |= __put_user(from->si_pid, &to->si_pid);
478 err |= __put_user(from->si_uid, &to->si_uid);
479 err |= __put_user(from->si_int, &to->si_int);
480 break;
481 }
482 }
483 return err;
484}
485
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100486asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Ralf Baechledd02f062007-02-13 00:50:57 +0000488 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900490 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Ralf Baechledd02f062007-02-13 00:50:57 +0000492 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
494 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000495 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 goto badframe;
497
498 sigdelsetmask(&blocked, ~_BLOCKABLE);
499 spin_lock_irq(&current->sighand->siglock);
500 current->blocked = blocked;
501 recalc_sigpending();
502 spin_unlock_irq(&current->sighand->siglock);
503
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900504 sig = restore_sigcontext32(&regs, &frame->sf_sc);
505 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900507 else if (sig)
508 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 /*
511 * Don't let your children do this ...
512 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 __asm__ __volatile__(
514 "move\t$29, %0\n\t"
515 "j\tsyscall_exit"
516 :/* no outputs */
517 :"r" (&regs));
518 /* Unreached */
519
520badframe:
521 force_sig(SIGSEGV, current);
522}
523
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100524asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900526 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000527 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 sigset_t set;
529 stack_t st;
530 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900531 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900533 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
535 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000536 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 goto badframe;
538
539 sigdelsetmask(&set, ~_BLOCKABLE);
540 spin_lock_irq(&current->sighand->siglock);
541 current->blocked = set;
542 recalc_sigpending();
543 spin_unlock_irq(&current->sighand->siglock);
544
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900545 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
546 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900548 else if (sig)
549 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 /* The ucontext contains a stack32_t, so we must convert! */
552 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
553 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900554 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
556 goto badframe;
557 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
558 goto badframe;
559
560 /* It is more difficult to avoid calling this function than to
561 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000562 old_fs = get_fs();
563 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900564 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000565 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 /*
568 * Don't let your children do this ...
569 */
570 __asm__ __volatile__(
571 "move\t$29, %0\n\t"
572 "j\tsyscall_exit"
573 :/* no outputs */
574 :"r" (&regs));
575 /* Unreached */
576
577badframe:
578 force_sig(SIGSEGV, current);
579}
580
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000581static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900582 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Ralf Baechledd02f062007-02-13 00:50:57 +0000584 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 int err = 0;
586
587 frame = get_sigframe(ka, regs, sizeof(*frame));
588 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
589 goto give_sigsegv;
590
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100591 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000594 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 if (err)
597 goto give_sigsegv;
598
599 /*
600 * Arguments to signal handler:
601 *
602 * a0 = signal number
603 * a1 = 0 (should be cause)
604 * a2 = pointer to struct sigcontext
605 *
606 * $25 and c0_epc point to the signal handler, $29 points to the
607 * struct sigframe.
608 */
609 regs->regs[ 4] = signr;
610 regs->regs[ 5] = 0;
611 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
612 regs->regs[29] = (unsigned long) frame;
613 regs->regs[31] = (unsigned long) frame->sf_code;
614 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
615
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100616 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100618 frame, regs->cp0_epc, regs->regs[31]);
619
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000620 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622give_sigsegv:
623 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000624 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625}
626
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000627static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900628 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900630 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 int err = 0;
632 s32 sp;
633
634 frame = get_sigframe(ka, regs, sizeof(*frame));
635 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
636 goto give_sigsegv;
637
Franck Bui-Huu36a1f2c22007-02-05 15:24:22 +0100638 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
641 err |= copy_siginfo_to_user32(&frame->rs_info, info);
642
643 /* Create the ucontext. */
644 err |= __put_user(0, &frame->rs_uc.uc_flags);
645 err |= __put_user(0, &frame->rs_uc.uc_link);
646 sp = (int) (long) current->sas_ss_sp;
647 err |= __put_user(sp,
648 &frame->rs_uc.uc_stack.ss_sp);
649 err |= __put_user(sas_ss_flags(regs->regs[29]),
650 &frame->rs_uc.uc_stack.ss_flags);
651 err |= __put_user(current->sas_ss_size,
652 &frame->rs_uc.uc_stack.ss_size);
653 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000654 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 if (err)
657 goto give_sigsegv;
658
659 /*
660 * Arguments to signal handler:
661 *
662 * a0 = signal number
663 * a1 = 0 (should be cause)
664 * a2 = pointer to ucontext
665 *
666 * $25 and c0_epc point to the signal handler, $29 points to
667 * the struct rt_sigframe32.
668 */
669 regs->regs[ 4] = signr;
670 regs->regs[ 5] = (unsigned long) &frame->rs_info;
671 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
672 regs->regs[29] = (unsigned long) frame;
673 regs->regs[31] = (unsigned long) frame->rs_code;
674 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
675
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100676 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100678 frame, regs->cp0_epc, regs->regs[31]);
679
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000680 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682give_sigsegv:
683 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000684 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685}
686
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000687/*
688 * o32 compatibility on 64-bit kernels, without DSP ASE
689 */
690struct mips_abi mips_abi_32 = {
691 .setup_frame = setup_frame_32,
692 .setup_rt_frame = setup_rt_frame_32,
693 .restart = __NR_O32_restart_syscall
694};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900696asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900697 struct sigaction32 __user *oact,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 unsigned int sigsetsize)
699{
700 struct k_sigaction new_sa, old_sa;
701 int ret = -EINVAL;
702
703 /* XXX: Don't preclude handling different sized sigset_t's. */
704 if (sigsetsize != sizeof(sigset_t))
705 goto out;
706
707 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000708 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 int err = 0;
710
711 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
712 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000713 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900714 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
716 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
717 if (err)
718 return -EFAULT;
719 }
720
721 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
722
723 if (!ret && oact) {
724 int err = 0;
725
726 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
727 return -EFAULT;
728
729 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
730 &oact->sa_handler);
731 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
732 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
733 if (err)
734 return -EFAULT;
735 }
736out:
737 return ret;
738}
739
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900740asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900741 compat_sigset_t __user *oset, unsigned int sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
743 sigset_t old_set, new_set;
744 int ret;
745 mm_segment_t old_fs = get_fs();
746
747 if (set && get_sigset(&new_set, set))
748 return -EFAULT;
749
750 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900751 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
752 oset ? (sigset_t __user *)&old_set : NULL,
753 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 set_fs (old_fs);
755
756 if (!ret && oset && put_sigset(&old_set, oset))
757 return -EFAULT;
758
759 return ret;
760}
761
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900762asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 unsigned int sigsetsize)
764{
765 int ret;
766 sigset_t set;
767 mm_segment_t old_fs = get_fs();
768
769 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900770 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 set_fs (old_fs);
772
773 if (!ret && put_sigset(&set, uset))
774 return -EFAULT;
775
776 return ret;
777}
778
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900779asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 siginfo_t info;
782 int ret;
783 mm_segment_t old_fs = get_fs();
784
785 if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
786 copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
787 return -EFAULT;
788 set_fs (KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900789 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 set_fs (old_fs);
791 return ret;
792}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000793
794asmlinkage long
795sys32_waitid(int which, compat_pid_t pid,
796 compat_siginfo_t __user *uinfo, int options,
797 struct compat_rusage __user *uru)
798{
799 siginfo_t info;
800 struct rusage ru;
801 long ret;
802 mm_segment_t old_fs = get_fs();
803
804 info.si_signo = 0;
805 set_fs (KERNEL_DS);
806 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
807 uru ? (struct rusage __user *) &ru : NULL);
808 set_fs (old_fs);
809
810 if (ret < 0 || info.si_signo == 0)
811 return ret;
812
813 if (uru && (ret = put_compat_rusage(&ru, uru)))
814 return ret;
815
816 BUG_ON(info.si_code & __SI_MASK);
817 info.si_code |= __SI_CHLD;
818 return copy_siginfo_to_user32(uinfo, &info);
819}