blob: a0ed0e052b2e8f630c34900d5b6e5958f945bbcc [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>
David Daneyd814c282010-02-18 16:13:05 -080035#include <asm/vdso.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Franck Bui-Huu36a1f2c2007-02-05 15:24:22 +010037#include "signal-common.h"
38
Ralf Baechle137f6f32009-11-24 19:35:41 +000039static int (*save_fp_context32)(struct sigcontext32 __user *sc);
40static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
41
42extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
43extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
44
45extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
46extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048/*
49 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
50 */
Ralf Baechle151fd6a2007-02-15 11:40:37 +000051#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Linus Torvalds1da177e2005-04-16 15:20:36 -070053/* 32-bit compatibility types */
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055typedef unsigned int __sighandler32_t;
56typedef void (*vfptr_t)(void);
57
58struct sigaction32 {
59 unsigned int sa_flags;
60 __sighandler32_t sa_handler;
61 compat_sigset_t sa_mask;
62};
63
64/* IRIX compatible stack_t */
65typedef struct sigaltstack32 {
66 s32 ss_sp;
67 compat_size_t ss_size;
68 int ss_flags;
69} stack32_t;
70
71struct ucontext32 {
72 u32 uc_flags;
73 s32 uc_link;
74 stack32_t uc_stack;
75 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +000076 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
Ralf Baechledd02f062007-02-13 00:50:57 +000079struct sigframe32 {
80 u32 sf_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080081 u32 sf_pad[2]; /* Was: signal trampoline */
Ralf Baechledd02f062007-02-13 00:50:57 +000082 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 */
David Daneyd814c282010-02-18 16:13:05 -080088 u32 rs_pad[2]; /* Was: signal trampoline */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010089 compat_siginfo_t rs_info;
90 struct ucontext32 rs_uc;
91};
92
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +010093/*
94 * sigcontext handlers
95 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +090096static int protected_save_fp_context32(struct sigcontext32 __user *sc)
97{
98 int err;
99 while (1) {
100 lock_fpu_owner();
101 own_fpu_inatomic(1);
102 err = save_fp_context32(sc); /* this might fail */
103 unlock_fpu_owner();
104 if (likely(!err))
105 break;
106 /* touch the sigcontext and try again */
107 err = __put_user(0, &sc->sc_fpregs[0]) |
108 __put_user(0, &sc->sc_fpregs[31]) |
109 __put_user(0, &sc->sc_fpc_csr);
110 if (err)
111 break; /* really bad sigcontext */
112 }
113 return err;
114}
115
116static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
117{
118 int err, tmp;
119 while (1) {
120 lock_fpu_owner();
121 own_fpu_inatomic(0);
122 err = restore_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 = __get_user(tmp, &sc->sc_fpregs[0]) |
128 __get_user(tmp, &sc->sc_fpregs[31]) |
129 __get_user(tmp, &sc->sc_fpc_csr);
130 if (err)
131 break; /* really bad sigcontext */
132 }
133 return err;
134}
135
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100136static int setup_sigcontext32(struct pt_regs *regs,
137 struct sigcontext32 __user *sc)
138{
139 int err = 0;
140 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900141 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100142
143 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100144
145 err |= __put_user(0, &sc->sc_regs[0]);
146 for (i = 1; i < 32; i++)
147 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
148
149 err |= __put_user(regs->hi, &sc->sc_mdhi);
150 err |= __put_user(regs->lo, &sc->sc_mdlo);
151 if (cpu_has_dsp) {
152 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
153 err |= __put_user(mfhi1(), &sc->sc_hi1);
154 err |= __put_user(mflo1(), &sc->sc_lo1);
155 err |= __put_user(mfhi2(), &sc->sc_hi2);
156 err |= __put_user(mflo2(), &sc->sc_lo2);
157 err |= __put_user(mfhi3(), &sc->sc_hi3);
158 err |= __put_user(mflo3(), &sc->sc_lo3);
159 }
160
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900161 used_math = !!used_math();
162 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100163
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900164 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100165 /*
166 * Save FPU state to signal context. Signal handler
167 * will "inherit" current FPU state.
168 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900169 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100170 }
171 return err;
172}
173
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900174static int
175check_and_restore_fp_context32(struct sigcontext32 __user *sc)
176{
177 int err, sig;
178
179 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
180 if (err > 0)
181 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900182 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900183 return err ?: sig;
184}
185
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100186static int restore_sigcontext32(struct pt_regs *regs,
187 struct sigcontext32 __user *sc)
188{
189 u32 used_math;
190 int err = 0;
191 s32 treg;
192 int i;
193
194 /* Always make any pending restarted system calls return -EINTR */
195 current_thread_info()->restart_block.fn = do_no_restart_syscall;
196
197 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
198 err |= __get_user(regs->hi, &sc->sc_mdhi);
199 err |= __get_user(regs->lo, &sc->sc_mdlo);
200 if (cpu_has_dsp) {
201 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
202 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
203 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
204 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
205 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
206 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
207 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
208 }
209
210 for (i = 1; i < 32; i++)
211 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
212
213 err |= __get_user(used_math, &sc->sc_used_math);
214 conditional_used_math(used_math);
215
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900216 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100217 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900218 if (!err)
219 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100220 } else {
221 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900222 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100223 }
224
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100225 return err;
226}
227
228/*
229 *
230 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231extern void __put_sigset_unknown_nsig(void);
232extern void __get_sigset_unknown_nsig(void);
233
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900234static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
236 int err = 0;
237
238 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
239 return -EFAULT;
240
241 switch (_NSIG_WORDS) {
242 default:
243 __put_sigset_unknown_nsig();
244 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100245 err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
246 err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100248 err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
249 err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 }
251
252 return err;
253}
254
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900255static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
257 int err = 0;
258 unsigned long sig[4];
259
260 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
261 return -EFAULT;
262
263 switch (_NSIG_WORDS) {
264 default:
265 __get_sigset_unknown_nsig();
266 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100267 err |= __get_user(sig[3], &ubuf->sig[3]);
268 err |= __get_user(sig[2], &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 kbuf->sig[1] = sig[2] | (sig[3] << 32);
270 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100271 err |= __get_user(sig[1], &ubuf->sig[1]);
272 err |= __get_user(sig[0], &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 kbuf->sig[0] = sig[0] | (sig[1] << 32);
274 }
275
276 return err;
277}
278
279/*
280 * Atomically swap in the new signal mask, and wait for a signal.
281 */
282
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100283asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900285 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000286 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900288 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if (get_sigset(&newset, uset))
290 return -EFAULT;
291 sigdelsetmask(&newset, ~_BLOCKABLE);
292
293 spin_lock_irq(&current->sighand->siglock);
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000294 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 current->blocked = newset;
296 recalc_sigpending();
297 spin_unlock_irq(&current->sighand->siglock);
298
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000299 current->state = TASK_INTERRUPTIBLE;
300 schedule();
301 set_thread_flag(TIF_RESTORE_SIGMASK);
302 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100305asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900307 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000308 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000309 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 /* XXX Don't preclude handling different sized sigset_t's. */
312 sigsetsize = regs.regs[5];
313 if (sigsetsize != sizeof(compat_sigset_t))
314 return -EINVAL;
315
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;
Martin Michlmayr62549442006-02-18 20:06:32 +0000324 recalc_sigpending();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 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
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000333SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
334 struct sigaction32 __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 struct k_sigaction new_ka, old_ka;
337 int ret;
338 int err = 0;
339
340 if (act) {
341 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000342 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
345 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000346 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900347 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
349 err |= __get_user(mask, &act->sa_mask.sig[0]);
350 if (err)
351 return -EFAULT;
352
353 siginitset(&new_ka.sa.sa_mask, mask);
354 }
355
356 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
357
358 if (!ret && oact) {
359 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000360 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
362 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
363 &oact->sa_handler);
364 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000365 err |= __put_user(0, &oact->sa_mask.sig[1]);
366 err |= __put_user(0, &oact->sa_mask.sig[2]);
367 err |= __put_user(0, &oact->sa_mask.sig[3]);
368 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return -EFAULT;
370 }
371
372 return ret;
373}
374
375asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
376{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900377 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
378 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 unsigned long usp = regs.regs[29];
380 stack_t kss, koss;
381 int ret, err = 0;
382 mm_segment_t old_fs = get_fs();
383 s32 sp;
384
385 if (uss) {
386 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
387 return -EFAULT;
388 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900389 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 err |= __get_user(kss.ss_size, &uss->ss_size);
391 err |= __get_user(kss.ss_flags, &uss->ss_flags);
392 if (err)
393 return -EFAULT;
394 }
395
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100396 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900397 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
398 uoss ? (stack_t __user *)&koss : NULL, usp);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100399 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 if (!ret && uoss) {
402 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
403 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900404 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 err |= __put_user(sp, &uoss->ss_sp);
406 err |= __put_user(koss.ss_size, &uoss->ss_size);
407 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
408 if (err)
409 return -EFAULT;
410 }
411 return ret;
412}
413
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900414int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int err;
417
418 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
419 return -EFAULT;
420
421 /* If you change siginfo_t structure, please be sure
422 this code is fixed accordingly.
423 It should never copy any pad contained in the structure
424 to avoid security leaks, but must copy the generic
425 3 ints plus the relevant union member.
426 This routine must convert siginfo from 64bit to 32bit as well
427 at the same time. */
428 err = __put_user(from->si_signo, &to->si_signo);
429 err |= __put_user(from->si_errno, &to->si_errno);
430 err |= __put_user((short)from->si_code, &to->si_code);
431 if (from->si_code < 0)
432 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
433 else {
434 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000435 case __SI_TIMER >> 16:
436 err |= __put_user(from->si_tid, &to->si_tid);
437 err |= __put_user(from->si_overrun, &to->si_overrun);
438 err |= __put_user(from->si_int, &to->si_int);
439 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 case __SI_CHLD >> 16:
441 err |= __put_user(from->si_utime, &to->si_utime);
442 err |= __put_user(from->si_stime, &to->si_stime);
443 err |= __put_user(from->si_status, &to->si_status);
444 default:
445 err |= __put_user(from->si_pid, &to->si_pid);
446 err |= __put_user(from->si_uid, &to->si_uid);
447 break;
448 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900449 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 break;
451 case __SI_POLL >> 16:
452 err |= __put_user(from->si_band, &to->si_band);
453 err |= __put_user(from->si_fd, &to->si_fd);
454 break;
455 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
456 case __SI_MESGQ >> 16:
457 err |= __put_user(from->si_pid, &to->si_pid);
458 err |= __put_user(from->si_uid, &to->si_uid);
459 err |= __put_user(from->si_int, &to->si_int);
460 break;
461 }
462 }
463 return err;
464}
465
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200466int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
467{
468 memset(to, 0, sizeof *to);
469
470 if (copy_from_user(to, from, 3*sizeof(int)) ||
471 copy_from_user(to->_sifields._pad,
472 from->_sifields._pad, SI_PAD_SIZE32))
473 return -EFAULT;
474
475 return 0;
476}
477
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100478asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
Ralf Baechledd02f062007-02-13 00:50:57 +0000480 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900482 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Ralf Baechledd02f062007-02-13 00:50:57 +0000484 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
486 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000487 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 goto badframe;
489
490 sigdelsetmask(&blocked, ~_BLOCKABLE);
491 spin_lock_irq(&current->sighand->siglock);
492 current->blocked = blocked;
493 recalc_sigpending();
494 spin_unlock_irq(&current->sighand->siglock);
495
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900496 sig = restore_sigcontext32(&regs, &frame->sf_sc);
497 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900499 else if (sig)
500 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 /*
503 * Don't let your children do this ...
504 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 __asm__ __volatile__(
506 "move\t$29, %0\n\t"
507 "j\tsyscall_exit"
508 :/* no outputs */
509 :"r" (&regs));
510 /* Unreached */
511
512badframe:
513 force_sig(SIGSEGV, current);
514}
515
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100516asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900518 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000519 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 sigset_t set;
521 stack_t st;
522 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900523 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900525 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
527 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000528 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 goto badframe;
530
531 sigdelsetmask(&set, ~_BLOCKABLE);
532 spin_lock_irq(&current->sighand->siglock);
533 current->blocked = set;
534 recalc_sigpending();
535 spin_unlock_irq(&current->sighand->siglock);
536
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900537 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
538 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900540 else if (sig)
541 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 /* The ucontext contains a stack32_t, so we must convert! */
544 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
545 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900546 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
548 goto badframe;
549 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
550 goto badframe;
551
552 /* It is more difficult to avoid calling this function than to
553 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000554 old_fs = get_fs();
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100555 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900556 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100557 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559 /*
560 * Don't let your children do this ...
561 */
562 __asm__ __volatile__(
563 "move\t$29, %0\n\t"
564 "j\tsyscall_exit"
565 :/* no outputs */
566 :"r" (&regs));
567 /* Unreached */
568
569badframe:
570 force_sig(SIGSEGV, current);
571}
572
David Daneyd814c282010-02-18 16:13:05 -0800573static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
574 struct pt_regs *regs, int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Ralf Baechledd02f062007-02-13 00:50:57 +0000576 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 int err = 0;
578
579 frame = get_sigframe(ka, regs, sizeof(*frame));
580 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
581 goto give_sigsegv;
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000584 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (err)
587 goto give_sigsegv;
588
589 /*
590 * Arguments to signal handler:
591 *
592 * a0 = signal number
593 * a1 = 0 (should be cause)
594 * a2 = pointer to struct sigcontext
595 *
596 * $25 and c0_epc point to the signal handler, $29 points to the
597 * struct sigframe.
598 */
599 regs->regs[ 4] = signr;
600 regs->regs[ 5] = 0;
601 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
602 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800603 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
605
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100606 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100608 frame, regs->cp0_epc, regs->regs[31]);
609
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000610 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612give_sigsegv:
613 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000614 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
David Daneyd814c282010-02-18 16:13:05 -0800617static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
618 struct pt_regs *regs, int signr, sigset_t *set,
619 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900621 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 int err = 0;
623 s32 sp;
624
625 frame = get_sigframe(ka, regs, sizeof(*frame));
626 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
627 goto give_sigsegv;
628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
630 err |= copy_siginfo_to_user32(&frame->rs_info, info);
631
632 /* Create the ucontext. */
633 err |= __put_user(0, &frame->rs_uc.uc_flags);
634 err |= __put_user(0, &frame->rs_uc.uc_link);
635 sp = (int) (long) current->sas_ss_sp;
636 err |= __put_user(sp,
637 &frame->rs_uc.uc_stack.ss_sp);
638 err |= __put_user(sas_ss_flags(regs->regs[29]),
639 &frame->rs_uc.uc_stack.ss_flags);
640 err |= __put_user(current->sas_ss_size,
641 &frame->rs_uc.uc_stack.ss_size);
642 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000643 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 if (err)
646 goto give_sigsegv;
647
648 /*
649 * Arguments to signal handler:
650 *
651 * a0 = signal number
652 * a1 = 0 (should be cause)
653 * a2 = pointer to ucontext
654 *
655 * $25 and c0_epc point to the signal handler, $29 points to
656 * the struct rt_sigframe32.
657 */
658 regs->regs[ 4] = signr;
659 regs->regs[ 5] = (unsigned long) &frame->rs_info;
660 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
661 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800662 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
664
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100665 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100667 frame, regs->cp0_epc, regs->regs[31]);
668
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671give_sigsegv:
672 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000673 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000676/*
677 * o32 compatibility on 64-bit kernels, without DSP ASE
678 */
679struct mips_abi mips_abi_32 = {
680 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800681 .signal_return_offset =
682 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000683 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800684 .rt_signal_return_offset =
685 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000686 .restart = __NR_O32_restart_syscall
687};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000689SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
690 const struct sigaction32 __user *, act,
691 struct sigaction32 __user *, oact, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 struct k_sigaction new_sa, old_sa;
694 int ret = -EINVAL;
695
696 /* XXX: Don't preclude handling different sized sigset_t's. */
697 if (sigsetsize != sizeof(sigset_t))
698 goto out;
699
700 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000701 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 int err = 0;
703
704 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
705 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000706 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900707 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
709 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
710 if (err)
711 return -EFAULT;
712 }
713
714 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
715
716 if (!ret && oact) {
717 int err = 0;
718
719 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
720 return -EFAULT;
721
722 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
723 &oact->sa_handler);
724 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
725 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
726 if (err)
727 return -EFAULT;
728 }
729out:
730 return ret;
731}
732
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000733SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
734 compat_sigset_t __user *, oset, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
736 sigset_t old_set, new_set;
737 int ret;
738 mm_segment_t old_fs = get_fs();
739
740 if (set && get_sigset(&new_set, set))
741 return -EFAULT;
742
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100743 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900744 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
745 oset ? (sigset_t __user *)&old_set : NULL,
746 sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100747 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 if (!ret && oset && put_sigset(&old_set, oset))
750 return -EFAULT;
751
752 return ret;
753}
754
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000755SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
756 unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
758 int ret;
759 sigset_t set;
760 mm_segment_t old_fs = get_fs();
761
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100762 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900763 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100764 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 if (!ret && put_sigset(&set, uset))
767 return -EFAULT;
768
769 return ret;
770}
771
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000772SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
773 compat_siginfo_t __user *, uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 siginfo_t info;
776 int ret;
777 mm_segment_t old_fs = get_fs();
778
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100779 if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
780 copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return -EFAULT;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100782 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900783 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100784 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return ret;
786}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000787
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000788SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
789 compat_siginfo_t __user *, uinfo, int, options,
790 struct compat_rusage __user *, uru)
Ralf Baechle54f2da72005-02-16 21:21:29 +0000791{
792 siginfo_t info;
793 struct rusage ru;
794 long ret;
795 mm_segment_t old_fs = get_fs();
796
797 info.si_signo = 0;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100798 set_fs(KERNEL_DS);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000799 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
800 uru ? (struct rusage __user *) &ru : NULL);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100801 set_fs(old_fs);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000802
803 if (ret < 0 || info.si_signo == 0)
804 return ret;
805
806 if (uru && (ret = put_compat_rusage(&ru, uru)))
807 return ret;
808
809 BUG_ON(info.si_code & __SI_MASK);
810 info.si_code |= __SI_CHLD;
811 return copy_siginfo_to_user32(uinfo, &info);
812}
Ralf Baechle137f6f32009-11-24 19:35:41 +0000813
814static int signal32_init(void)
815{
816 if (cpu_has_fpu) {
817 save_fp_context32 = _save_fp_context32;
818 restore_fp_context32 = _restore_fp_context32;
819 } else {
820 save_fp_context32 = fpu_emulator_save_context32;
821 restore_fp_context32 = fpu_emulator_restore_context32;
822 }
823
824 return 0;
825}
826
827arch_initcall(signal32_init);