blob: b4fe2eacbd5d258a55146f5d51154491119569e8 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/fpu.h>
Ralf Baechle02416dc2005-06-15 13:00:12 +000033#include <asm/war.h>
David Daneyd814c282010-02-18 16:13:05 -080034#include <asm/vdso.h>
David Howellsb81947c2012-03-28 18:30:02 +010035#include <asm/dsp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Franck Bui-Huu36a1f2c22007-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{
David Daneyc726b822011-01-24 14:51:34 -0800118 int err, tmp __maybe_unused;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900119 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;
Al Viro68f3f162012-05-21 21:42:32 -0400291 return sigsuspend(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100294asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900296 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000297 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000298 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 /* XXX Don't preclude handling different sized sigset_t's. */
301 sigsetsize = regs.regs[5];
302 if (sigsetsize != sizeof(compat_sigset_t))
303 return -EINVAL;
304
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900305 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 if (get_sigset(&newset, uset))
307 return -EFAULT;
Al Viro68f3f162012-05-21 21:42:32 -0400308 return sigsuspend(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309}
310
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000311SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
312 struct sigaction32 __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 struct k_sigaction new_ka, old_ka;
315 int ret;
316 int err = 0;
317
318 if (act) {
319 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000320 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
323 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000324 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900325 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
327 err |= __get_user(mask, &act->sa_mask.sig[0]);
328 if (err)
329 return -EFAULT;
330
331 siginitset(&new_ka.sa.sa_mask, mask);
332 }
333
334 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
335
336 if (!ret && oact) {
337 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000338 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
340 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
341 &oact->sa_handler);
342 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000343 err |= __put_user(0, &oact->sa_mask.sig[1]);
344 err |= __put_user(0, &oact->sa_mask.sig[2]);
345 err |= __put_user(0, &oact->sa_mask.sig[3]);
346 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return -EFAULT;
348 }
349
350 return ret;
351}
352
353asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
354{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900355 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
356 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 unsigned long usp = regs.regs[29];
358 stack_t kss, koss;
359 int ret, err = 0;
360 mm_segment_t old_fs = get_fs();
361 s32 sp;
362
363 if (uss) {
364 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
365 return -EFAULT;
366 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900367 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 err |= __get_user(kss.ss_size, &uss->ss_size);
369 err |= __get_user(kss.ss_flags, &uss->ss_flags);
370 if (err)
371 return -EFAULT;
372 }
373
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100374 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900375 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
376 uoss ? (stack_t __user *)&koss : NULL, usp);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100377 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 if (!ret && uoss) {
380 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
381 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900382 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 err |= __put_user(sp, &uoss->ss_sp);
384 err |= __put_user(koss.ss_size, &uoss->ss_size);
385 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
386 if (err)
387 return -EFAULT;
388 }
389 return ret;
390}
391
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900392int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
394 int err;
395
396 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
397 return -EFAULT;
398
399 /* If you change siginfo_t structure, please be sure
400 this code is fixed accordingly.
401 It should never copy any pad contained in the structure
402 to avoid security leaks, but must copy the generic
403 3 ints plus the relevant union member.
404 This routine must convert siginfo from 64bit to 32bit as well
405 at the same time. */
406 err = __put_user(from->si_signo, &to->si_signo);
407 err |= __put_user(from->si_errno, &to->si_errno);
408 err |= __put_user((short)from->si_code, &to->si_code);
409 if (from->si_code < 0)
410 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
411 else {
412 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000413 case __SI_TIMER >> 16:
414 err |= __put_user(from->si_tid, &to->si_tid);
415 err |= __put_user(from->si_overrun, &to->si_overrun);
416 err |= __put_user(from->si_int, &to->si_int);
417 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 case __SI_CHLD >> 16:
419 err |= __put_user(from->si_utime, &to->si_utime);
420 err |= __put_user(from->si_stime, &to->si_stime);
421 err |= __put_user(from->si_status, &to->si_status);
422 default:
423 err |= __put_user(from->si_pid, &to->si_pid);
424 err |= __put_user(from->si_uid, &to->si_uid);
425 break;
426 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900427 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 break;
429 case __SI_POLL >> 16:
430 err |= __put_user(from->si_band, &to->si_band);
431 err |= __put_user(from->si_fd, &to->si_fd);
432 break;
433 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
434 case __SI_MESGQ >> 16:
435 err |= __put_user(from->si_pid, &to->si_pid);
436 err |= __put_user(from->si_uid, &to->si_uid);
437 err |= __put_user(from->si_int, &to->si_int);
438 break;
439 }
440 }
441 return err;
442}
443
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200444int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
445{
446 memset(to, 0, sizeof *to);
447
448 if (copy_from_user(to, from, 3*sizeof(int)) ||
449 copy_from_user(to->_sifields._pad,
450 from->_sifields._pad, SI_PAD_SIZE32))
451 return -EFAULT;
452
453 return 0;
454}
455
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100456asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
Ralf Baechledd02f062007-02-13 00:50:57 +0000458 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900460 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Ralf Baechledd02f062007-02-13 00:50:57 +0000462 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
464 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000465 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 goto badframe;
467
468 sigdelsetmask(&blocked, ~_BLOCKABLE);
Matt Fleming8598f3c2012-02-14 11:40:52 +0000469 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900471 sig = restore_sigcontext32(&regs, &frame->sf_sc);
472 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900474 else if (sig)
475 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 /*
478 * Don't let your children do this ...
479 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 __asm__ __volatile__(
481 "move\t$29, %0\n\t"
482 "j\tsyscall_exit"
483 :/* no outputs */
484 :"r" (&regs));
485 /* Unreached */
486
487badframe:
488 force_sig(SIGSEGV, current);
489}
490
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100491asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900493 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000494 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 sigset_t set;
496 stack_t st;
497 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900498 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900500 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
502 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000503 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 goto badframe;
505
506 sigdelsetmask(&set, ~_BLOCKABLE);
Matt Fleming8598f3c2012-02-14 11:40:52 +0000507 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900509 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
510 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900512 else if (sig)
513 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 /* The ucontext contains a stack32_t, so we must convert! */
516 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
517 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900518 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
520 goto badframe;
521 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
522 goto badframe;
523
524 /* It is more difficult to avoid calling this function than to
525 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000526 old_fs = get_fs();
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100527 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900528 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100529 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 /*
532 * Don't let your children do this ...
533 */
534 __asm__ __volatile__(
535 "move\t$29, %0\n\t"
536 "j\tsyscall_exit"
537 :/* no outputs */
538 :"r" (&regs));
539 /* Unreached */
540
541badframe:
542 force_sig(SIGSEGV, current);
543}
544
David Daneyd814c282010-02-18 16:13:05 -0800545static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
546 struct pt_regs *regs, int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
Ralf Baechledd02f062007-02-13 00:50:57 +0000548 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 int err = 0;
550
551 frame = get_sigframe(ka, regs, sizeof(*frame));
552 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
553 goto give_sigsegv;
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000556 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (err)
559 goto give_sigsegv;
560
561 /*
562 * Arguments to signal handler:
563 *
564 * a0 = signal number
565 * a1 = 0 (should be cause)
566 * a2 = pointer to struct sigcontext
567 *
568 * $25 and c0_epc point to the signal handler, $29 points to the
569 * struct sigframe.
570 */
571 regs->regs[ 4] = signr;
572 regs->regs[ 5] = 0;
573 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
574 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800575 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
577
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100578 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100580 frame, regs->cp0_epc, regs->regs[31]);
581
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000582 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
584give_sigsegv:
585 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000586 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587}
588
David Daneyd814c282010-02-18 16:13:05 -0800589static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
590 struct pt_regs *regs, int signr, sigset_t *set,
591 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900593 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 int err = 0;
595 s32 sp;
596
597 frame = get_sigframe(ka, regs, sizeof(*frame));
598 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
599 goto give_sigsegv;
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
602 err |= copy_siginfo_to_user32(&frame->rs_info, info);
603
604 /* Create the ucontext. */
605 err |= __put_user(0, &frame->rs_uc.uc_flags);
606 err |= __put_user(0, &frame->rs_uc.uc_link);
607 sp = (int) (long) current->sas_ss_sp;
608 err |= __put_user(sp,
609 &frame->rs_uc.uc_stack.ss_sp);
610 err |= __put_user(sas_ss_flags(regs->regs[29]),
611 &frame->rs_uc.uc_stack.ss_flags);
612 err |= __put_user(current->sas_ss_size,
613 &frame->rs_uc.uc_stack.ss_size);
614 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000615 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 if (err)
618 goto give_sigsegv;
619
620 /*
621 * Arguments to signal handler:
622 *
623 * a0 = signal number
624 * a1 = 0 (should be cause)
625 * a2 = pointer to ucontext
626 *
627 * $25 and c0_epc point to the signal handler, $29 points to
628 * the struct rt_sigframe32.
629 */
630 regs->regs[ 4] = signr;
631 regs->regs[ 5] = (unsigned long) &frame->rs_info;
632 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
633 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800634 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
636
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100637 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100639 frame, regs->cp0_epc, regs->regs[31]);
640
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000641 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643give_sigsegv:
644 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000645 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000648/*
649 * o32 compatibility on 64-bit kernels, without DSP ASE
650 */
651struct mips_abi mips_abi_32 = {
652 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800653 .signal_return_offset =
654 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000655 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800656 .rt_signal_return_offset =
657 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000658 .restart = __NR_O32_restart_syscall
659};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000661SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
662 const struct sigaction32 __user *, act,
663 struct sigaction32 __user *, oact, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 struct k_sigaction new_sa, old_sa;
666 int ret = -EINVAL;
667
668 /* XXX: Don't preclude handling different sized sigset_t's. */
669 if (sigsetsize != sizeof(sigset_t))
670 goto out;
671
672 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000673 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 int err = 0;
675
676 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
677 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000678 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900679 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
681 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
682 if (err)
683 return -EFAULT;
684 }
685
686 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
687
688 if (!ret && oact) {
689 int err = 0;
690
691 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
692 return -EFAULT;
693
694 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
695 &oact->sa_handler);
696 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
697 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
698 if (err)
699 return -EFAULT;
700 }
701out:
702 return ret;
703}
704
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000705SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
706 compat_sigset_t __user *, oset, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
708 sigset_t old_set, new_set;
709 int ret;
710 mm_segment_t old_fs = get_fs();
711
712 if (set && get_sigset(&new_set, set))
713 return -EFAULT;
714
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100715 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900716 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
717 oset ? (sigset_t __user *)&old_set : NULL,
718 sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100719 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 if (!ret && oset && put_sigset(&old_set, oset))
722 return -EFAULT;
723
724 return ret;
725}
726
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000727SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
728 unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
730 int ret;
731 sigset_t set;
732 mm_segment_t old_fs = get_fs();
733
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100734 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900735 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100736 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 if (!ret && put_sigset(&set, uset))
739 return -EFAULT;
740
741 return ret;
742}
743
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000744SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
745 compat_siginfo_t __user *, uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 siginfo_t info;
748 int ret;
749 mm_segment_t old_fs = get_fs();
750
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100751 if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
752 copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return -EFAULT;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100754 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900755 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100756 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return ret;
758}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000759
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000760SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
761 compat_siginfo_t __user *, uinfo, int, options,
762 struct compat_rusage __user *, uru)
Ralf Baechle54f2da72005-02-16 21:21:29 +0000763{
764 siginfo_t info;
765 struct rusage ru;
766 long ret;
767 mm_segment_t old_fs = get_fs();
768
769 info.si_signo = 0;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100770 set_fs(KERNEL_DS);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000771 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
772 uru ? (struct rusage __user *) &ru : NULL);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100773 set_fs(old_fs);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000774
775 if (ret < 0 || info.si_signo == 0)
776 return ret;
777
778 if (uru && (ret = put_compat_rusage(&ru, uru)))
779 return ret;
780
781 BUG_ON(info.si_code & __SI_MASK);
782 info.si_code |= __SI_CHLD;
783 return copy_siginfo_to_user32(uinfo, &info);
784}
Ralf Baechle137f6f32009-11-24 19:35:41 +0000785
786static int signal32_init(void)
787{
788 if (cpu_has_fpu) {
789 save_fp_context32 = _save_fp_context32;
790 restore_fp_context32 = _restore_fp_context32;
791 } else {
792 save_fp_context32 = fpu_emulator_save_context32;
793 restore_fp_context32 = fpu_emulator_restore_context32;
794 }
795
796 return 0;
797}
798
799arch_initcall(signal32_init);