blob: 03abaf048f09b3257ad7240378a53e6ddcc5588d [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 Baechlee50c0a82005-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
Ralf Baechle137f6f32009-11-24 19:35:41 +000038static int (*save_fp_context32)(struct sigcontext32 __user *sc);
39static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
40
41extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
42extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
43
44extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
45extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047/*
48 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
49 */
50#define __NR_O32_sigreturn 4119
51#define __NR_O32_rt_sigreturn 4193
Ralf Baechle151fd6a2007-02-15 11:40:37 +000052#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054/* 32-bit compatibility types */
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056typedef unsigned int __sighandler32_t;
57typedef void (*vfptr_t)(void);
58
59struct sigaction32 {
60 unsigned int sa_flags;
61 __sighandler32_t sa_handler;
62 compat_sigset_t sa_mask;
63};
64
65/* IRIX compatible stack_t */
66typedef struct sigaltstack32 {
67 s32 ss_sp;
68 compat_size_t ss_size;
69 int ss_flags;
70} stack32_t;
71
72struct ucontext32 {
73 u32 uc_flags;
74 s32 uc_link;
75 stack32_t uc_stack;
76 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +000077 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
Ralf Baechledd02f062007-02-13 00:50:57 +000080/*
81 * Horribly complicated - with the bloody RM9000 workarounds enabled
82 * the signal trampolines is moving to the end of the structure so we can
83 * increase the alignment without breaking software compatibility.
84 */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010085#if ICACHE_REFILLS_WORKAROUND_WAR == 0
86
Ralf Baechledd02f062007-02-13 00:50:57 +000087struct sigframe32 {
88 u32 sf_ass[4]; /* argument save space for o32 */
89 u32 sf_code[2]; /* signal trampoline */
90 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090091 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000092};
93
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010094struct rt_sigframe32 {
95 u32 rs_ass[4]; /* argument save space for o32 */
96 u32 rs_code[2]; /* signal trampoline */
97 compat_siginfo_t rs_info;
98 struct ucontext32 rs_uc;
99};
100
101#else /* ICACHE_REFILLS_WORKAROUND_WAR */
102
Ralf Baechledd02f062007-02-13 00:50:57 +0000103struct sigframe32 {
104 u32 sf_ass[4]; /* argument save space for o32 */
105 u32 sf_pad[2];
106 struct sigcontext32 sf_sc; /* hw context */
Atsushi Nemoto755f21b2007-02-14 14:41:01 +0900107 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +0000108 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
109};
110
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +0100111struct rt_sigframe32 {
112 u32 rs_ass[4]; /* argument save space for o32 */
113 u32 rs_pad[2];
114 compat_siginfo_t rs_info;
115 struct ucontext32 rs_uc;
116 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
117};
118
119#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
120
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100121/*
122 * sigcontext handlers
123 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900124static int protected_save_fp_context32(struct sigcontext32 __user *sc)
125{
126 int err;
127 while (1) {
128 lock_fpu_owner();
129 own_fpu_inatomic(1);
130 err = save_fp_context32(sc); /* this might fail */
131 unlock_fpu_owner();
132 if (likely(!err))
133 break;
134 /* touch the sigcontext and try again */
135 err = __put_user(0, &sc->sc_fpregs[0]) |
136 __put_user(0, &sc->sc_fpregs[31]) |
137 __put_user(0, &sc->sc_fpc_csr);
138 if (err)
139 break; /* really bad sigcontext */
140 }
141 return err;
142}
143
144static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
145{
146 int err, tmp;
147 while (1) {
148 lock_fpu_owner();
149 own_fpu_inatomic(0);
150 err = restore_fp_context32(sc); /* this might fail */
151 unlock_fpu_owner();
152 if (likely(!err))
153 break;
154 /* touch the sigcontext and try again */
155 err = __get_user(tmp, &sc->sc_fpregs[0]) |
156 __get_user(tmp, &sc->sc_fpregs[31]) |
157 __get_user(tmp, &sc->sc_fpc_csr);
158 if (err)
159 break; /* really bad sigcontext */
160 }
161 return err;
162}
163
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100164static int setup_sigcontext32(struct pt_regs *regs,
165 struct sigcontext32 __user *sc)
166{
167 int err = 0;
168 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900169 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100170
171 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100172
173 err |= __put_user(0, &sc->sc_regs[0]);
174 for (i = 1; i < 32; i++)
175 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
176
177 err |= __put_user(regs->hi, &sc->sc_mdhi);
178 err |= __put_user(regs->lo, &sc->sc_mdlo);
179 if (cpu_has_dsp) {
180 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
181 err |= __put_user(mfhi1(), &sc->sc_hi1);
182 err |= __put_user(mflo1(), &sc->sc_lo1);
183 err |= __put_user(mfhi2(), &sc->sc_hi2);
184 err |= __put_user(mflo2(), &sc->sc_lo2);
185 err |= __put_user(mfhi3(), &sc->sc_hi3);
186 err |= __put_user(mflo3(), &sc->sc_lo3);
187 }
188
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900189 used_math = !!used_math();
190 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100191
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900192 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100193 /*
194 * Save FPU state to signal context. Signal handler
195 * will "inherit" current FPU state.
196 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900197 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100198 }
199 return err;
200}
201
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900202static int
203check_and_restore_fp_context32(struct sigcontext32 __user *sc)
204{
205 int err, sig;
206
207 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
208 if (err > 0)
209 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900210 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900211 return err ?: sig;
212}
213
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100214static int restore_sigcontext32(struct pt_regs *regs,
215 struct sigcontext32 __user *sc)
216{
217 u32 used_math;
218 int err = 0;
219 s32 treg;
220 int i;
221
222 /* Always make any pending restarted system calls return -EINTR */
223 current_thread_info()->restart_block.fn = do_no_restart_syscall;
224
225 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
226 err |= __get_user(regs->hi, &sc->sc_mdhi);
227 err |= __get_user(regs->lo, &sc->sc_mdlo);
228 if (cpu_has_dsp) {
229 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
230 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
231 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
232 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
233 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
234 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
235 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
236 }
237
238 for (i = 1; i < 32; i++)
239 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
240
241 err |= __get_user(used_math, &sc->sc_used_math);
242 conditional_used_math(used_math);
243
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900244 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100245 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900246 if (!err)
247 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100248 } else {
249 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900250 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100251 }
252
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100253 return err;
254}
255
256/*
257 *
258 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259extern void __put_sigset_unknown_nsig(void);
260extern void __get_sigset_unknown_nsig(void);
261
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900262static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
264 int err = 0;
265
266 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
267 return -EFAULT;
268
269 switch (_NSIG_WORDS) {
270 default:
271 __put_sigset_unknown_nsig();
272 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100273 err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
274 err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100276 err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
277 err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 }
279
280 return err;
281}
282
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900283static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 int err = 0;
286 unsigned long sig[4];
287
288 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
289 return -EFAULT;
290
291 switch (_NSIG_WORDS) {
292 default:
293 __get_sigset_unknown_nsig();
294 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100295 err |= __get_user(sig[3], &ubuf->sig[3]);
296 err |= __get_user(sig[2], &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 kbuf->sig[1] = sig[2] | (sig[3] << 32);
298 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100299 err |= __get_user(sig[1], &ubuf->sig[1]);
300 err |= __get_user(sig[0], &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 kbuf->sig[0] = sig[0] | (sig[1] << 32);
302 }
303
304 return err;
305}
306
307/*
308 * Atomically swap in the new signal mask, and wait for a signal.
309 */
310
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100311asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900313 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000314 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900316 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (get_sigset(&newset, uset))
318 return -EFAULT;
319 sigdelsetmask(&newset, ~_BLOCKABLE);
320
321 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000322 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 current->blocked = newset;
324 recalc_sigpending();
325 spin_unlock_irq(&current->sighand->siglock);
326
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000327 current->state = TASK_INTERRUPTIBLE;
328 schedule();
329 set_thread_flag(TIF_RESTORE_SIGMASK);
330 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100333asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900335 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000336 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000337 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339 /* XXX Don't preclude handling different sized sigset_t's. */
340 sigsetsize = regs.regs[5];
341 if (sigsetsize != sizeof(compat_sigset_t))
342 return -EINVAL;
343
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900344 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 if (get_sigset(&newset, uset))
346 return -EFAULT;
347 sigdelsetmask(&newset, ~_BLOCKABLE);
348
349 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000350 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 current->blocked = newset;
Martin Michlmayr62549442006-02-18 20:06:32 +0000352 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 spin_unlock_irq(&current->sighand->siglock);
354
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000355 current->state = TASK_INTERRUPTIBLE;
356 schedule();
357 set_thread_flag(TIF_RESTORE_SIGMASK);
358 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000361SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
362 struct sigaction32 __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 struct k_sigaction new_ka, old_ka;
365 int ret;
366 int err = 0;
367
368 if (act) {
369 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000370 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
373 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000374 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900375 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
377 err |= __get_user(mask, &act->sa_mask.sig[0]);
378 if (err)
379 return -EFAULT;
380
381 siginitset(&new_ka.sa.sa_mask, mask);
382 }
383
384 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
385
386 if (!ret && oact) {
387 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000388 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
390 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
391 &oact->sa_handler);
392 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000393 err |= __put_user(0, &oact->sa_mask.sig[1]);
394 err |= __put_user(0, &oact->sa_mask.sig[2]);
395 err |= __put_user(0, &oact->sa_mask.sig[3]);
396 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return -EFAULT;
398 }
399
400 return ret;
401}
402
403asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
404{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900405 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
406 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 unsigned long usp = regs.regs[29];
408 stack_t kss, koss;
409 int ret, err = 0;
410 mm_segment_t old_fs = get_fs();
411 s32 sp;
412
413 if (uss) {
414 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
415 return -EFAULT;
416 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900417 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 err |= __get_user(kss.ss_size, &uss->ss_size);
419 err |= __get_user(kss.ss_flags, &uss->ss_flags);
420 if (err)
421 return -EFAULT;
422 }
423
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100424 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900425 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
426 uoss ? (stack_t __user *)&koss : NULL, usp);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100427 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 if (!ret && uoss) {
430 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
431 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900432 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 err |= __put_user(sp, &uoss->ss_sp);
434 err |= __put_user(koss.ss_size, &uoss->ss_size);
435 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
436 if (err)
437 return -EFAULT;
438 }
439 return ret;
440}
441
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900442int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
444 int err;
445
446 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
447 return -EFAULT;
448
449 /* If you change siginfo_t structure, please be sure
450 this code is fixed accordingly.
451 It should never copy any pad contained in the structure
452 to avoid security leaks, but must copy the generic
453 3 ints plus the relevant union member.
454 This routine must convert siginfo from 64bit to 32bit as well
455 at the same time. */
456 err = __put_user(from->si_signo, &to->si_signo);
457 err |= __put_user(from->si_errno, &to->si_errno);
458 err |= __put_user((short)from->si_code, &to->si_code);
459 if (from->si_code < 0)
460 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
461 else {
462 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000463 case __SI_TIMER >> 16:
464 err |= __put_user(from->si_tid, &to->si_tid);
465 err |= __put_user(from->si_overrun, &to->si_overrun);
466 err |= __put_user(from->si_int, &to->si_int);
467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 case __SI_CHLD >> 16:
469 err |= __put_user(from->si_utime, &to->si_utime);
470 err |= __put_user(from->si_stime, &to->si_stime);
471 err |= __put_user(from->si_status, &to->si_status);
472 default:
473 err |= __put_user(from->si_pid, &to->si_pid);
474 err |= __put_user(from->si_uid, &to->si_uid);
475 break;
476 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900477 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 break;
479 case __SI_POLL >> 16:
480 err |= __put_user(from->si_band, &to->si_band);
481 err |= __put_user(from->si_fd, &to->si_fd);
482 break;
483 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
484 case __SI_MESGQ >> 16:
485 err |= __put_user(from->si_pid, &to->si_pid);
486 err |= __put_user(from->si_uid, &to->si_uid);
487 err |= __put_user(from->si_int, &to->si_int);
488 break;
489 }
490 }
491 return err;
492}
493
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200494int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
495{
496 memset(to, 0, sizeof *to);
497
498 if (copy_from_user(to, from, 3*sizeof(int)) ||
499 copy_from_user(to->_sifields._pad,
500 from->_sifields._pad, SI_PAD_SIZE32))
501 return -EFAULT;
502
503 return 0;
504}
505
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100506asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Ralf Baechledd02f062007-02-13 00:50:57 +0000508 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900510 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Ralf Baechledd02f062007-02-13 00:50:57 +0000512 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
514 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000515 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 goto badframe;
517
518 sigdelsetmask(&blocked, ~_BLOCKABLE);
519 spin_lock_irq(&current->sighand->siglock);
520 current->blocked = blocked;
521 recalc_sigpending();
522 spin_unlock_irq(&current->sighand->siglock);
523
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900524 sig = restore_sigcontext32(&regs, &frame->sf_sc);
525 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900527 else if (sig)
528 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 /*
531 * Don't let your children do this ...
532 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 __asm__ __volatile__(
534 "move\t$29, %0\n\t"
535 "j\tsyscall_exit"
536 :/* no outputs */
537 :"r" (&regs));
538 /* Unreached */
539
540badframe:
541 force_sig(SIGSEGV, current);
542}
543
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100544asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900546 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000547 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 sigset_t set;
549 stack_t st;
550 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900551 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900553 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
555 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000556 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 goto badframe;
558
559 sigdelsetmask(&set, ~_BLOCKABLE);
560 spin_lock_irq(&current->sighand->siglock);
561 current->blocked = set;
562 recalc_sigpending();
563 spin_unlock_irq(&current->sighand->siglock);
564
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900565 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
566 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900568 else if (sig)
569 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* The ucontext contains a stack32_t, so we must convert! */
572 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
573 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900574 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
576 goto badframe;
577 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
578 goto badframe;
579
580 /* It is more difficult to avoid calling this function than to
581 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000582 old_fs = get_fs();
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100583 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900584 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100585 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
587 /*
588 * Don't let your children do this ...
589 */
590 __asm__ __volatile__(
591 "move\t$29, %0\n\t"
592 "j\tsyscall_exit"
593 :/* no outputs */
594 :"r" (&regs));
595 /* Unreached */
596
597badframe:
598 force_sig(SIGSEGV, current);
599}
600
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000601static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900602 int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Ralf Baechledd02f062007-02-13 00:50:57 +0000604 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 int err = 0;
606
607 frame = get_sigframe(ka, regs, sizeof(*frame));
608 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
609 goto give_sigsegv;
610
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100611 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000614 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (err)
617 goto give_sigsegv;
618
619 /*
620 * Arguments to signal handler:
621 *
622 * a0 = signal number
623 * a1 = 0 (should be cause)
624 * a2 = pointer to struct sigcontext
625 *
626 * $25 and c0_epc point to the signal handler, $29 points to the
627 * struct sigframe.
628 */
629 regs->regs[ 4] = signr;
630 regs->regs[ 5] = 0;
631 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
632 regs->regs[29] = (unsigned long) frame;
633 regs->regs[31] = (unsigned long) frame->sf_code;
634 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
635
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100636 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100638 frame, regs->cp0_epc, regs->regs[31]);
639
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000640 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642give_sigsegv:
643 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000644 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000647static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
Atsushi Nemoto16cd3952005-11-05 23:00:58 +0900648 int signr, sigset_t *set, siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900650 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 int err = 0;
652 s32 sp;
653
654 frame = get_sigframe(ka, regs, sizeof(*frame));
655 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
656 goto give_sigsegv;
657
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +0100658 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
661 err |= copy_siginfo_to_user32(&frame->rs_info, info);
662
663 /* Create the ucontext. */
664 err |= __put_user(0, &frame->rs_uc.uc_flags);
665 err |= __put_user(0, &frame->rs_uc.uc_link);
666 sp = (int) (long) current->sas_ss_sp;
667 err |= __put_user(sp,
668 &frame->rs_uc.uc_stack.ss_sp);
669 err |= __put_user(sas_ss_flags(regs->regs[29]),
670 &frame->rs_uc.uc_stack.ss_flags);
671 err |= __put_user(current->sas_ss_size,
672 &frame->rs_uc.uc_stack.ss_size);
673 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000674 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 if (err)
677 goto give_sigsegv;
678
679 /*
680 * Arguments to signal handler:
681 *
682 * a0 = signal number
683 * a1 = 0 (should be cause)
684 * a2 = pointer to ucontext
685 *
686 * $25 and c0_epc point to the signal handler, $29 points to
687 * the struct rt_sigframe32.
688 */
689 regs->regs[ 4] = signr;
690 regs->regs[ 5] = (unsigned long) &frame->rs_info;
691 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
692 regs->regs[29] = (unsigned long) frame;
693 regs->regs[31] = (unsigned long) frame->rs_code;
694 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
695
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100696 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100698 frame, regs->cp0_epc, regs->regs[31]);
699
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000700 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702give_sigsegv:
703 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000704 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000707/*
708 * o32 compatibility on 64-bit kernels, without DSP ASE
709 */
710struct mips_abi mips_abi_32 = {
711 .setup_frame = setup_frame_32,
712 .setup_rt_frame = setup_rt_frame_32,
713 .restart = __NR_O32_restart_syscall
714};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000716SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
717 const struct sigaction32 __user *, act,
718 struct sigaction32 __user *, oact, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 struct k_sigaction new_sa, old_sa;
721 int ret = -EINVAL;
722
723 /* XXX: Don't preclude handling different sized sigset_t's. */
724 if (sigsetsize != sizeof(sigset_t))
725 goto out;
726
727 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000728 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 int err = 0;
730
731 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
732 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000733 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900734 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
736 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
737 if (err)
738 return -EFAULT;
739 }
740
741 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
742
743 if (!ret && oact) {
744 int err = 0;
745
746 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
747 return -EFAULT;
748
749 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
750 &oact->sa_handler);
751 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
752 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
753 if (err)
754 return -EFAULT;
755 }
756out:
757 return ret;
758}
759
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000760SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
761 compat_sigset_t __user *, oset, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 sigset_t old_set, new_set;
764 int ret;
765 mm_segment_t old_fs = get_fs();
766
767 if (set && get_sigset(&new_set, set))
768 return -EFAULT;
769
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100770 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900771 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
772 oset ? (sigset_t __user *)&old_set : NULL,
773 sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100774 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 if (!ret && oset && put_sigset(&old_set, oset))
777 return -EFAULT;
778
779 return ret;
780}
781
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000782SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
783 unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
785 int ret;
786 sigset_t set;
787 mm_segment_t old_fs = get_fs();
788
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100789 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900790 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100791 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 if (!ret && put_sigset(&set, uset))
794 return -EFAULT;
795
796 return ret;
797}
798
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000799SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
800 compat_siginfo_t __user *, uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 siginfo_t info;
803 int ret;
804 mm_segment_t old_fs = get_fs();
805
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100806 if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
807 copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return -EFAULT;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100809 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900810 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100811 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 return ret;
813}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000814
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000815SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
816 compat_siginfo_t __user *, uinfo, int, options,
817 struct compat_rusage __user *, uru)
Ralf Baechle54f2da72005-02-16 21:21:29 +0000818{
819 siginfo_t info;
820 struct rusage ru;
821 long ret;
822 mm_segment_t old_fs = get_fs();
823
824 info.si_signo = 0;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100825 set_fs(KERNEL_DS);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000826 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
827 uru ? (struct rusage __user *) &ru : NULL);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100828 set_fs(old_fs);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000829
830 if (ret < 0 || info.si_signo == 0)
831 return ret;
832
833 if (uru && (ret = put_compat_rusage(&ru, uru)))
834 return ret;
835
836 BUG_ON(info.si_code & __SI_MASK);
837 info.si_code |= __SI_CHLD;
838 return copy_siginfo_to_user32(uinfo, &info);
839}
Ralf Baechle137f6f32009-11-24 19:35:41 +0000840
841static int signal32_init(void)
842{
843 if (cpu_has_fpu) {
844 save_fp_context32 = _save_fp_context32;
845 restore_fp_context32 = _restore_fp_context32;
846 } else {
847 save_fp_context32 = fpu_emulator_save_context32;
848 restore_fp_context32 = fpu_emulator_restore_context32;
849 }
850
851 return 0;
852}
853
854arch_initcall(signal32_init);