blob: ac3b8d89aae51a4a75f14249ddc5a4f894046087 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1991, 1992 Linus Torvalds
Martin Michlmayrdda73d02006-02-18 15:21:30 +00007 * Copyright (C) 1994 - 2000, 2006 Ralf Baechle
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9 */
Ralf Baechle02416dc2005-06-15 13:00:12 +000010#include <linux/cache.h>
Ralf Baechle431dc802007-02-13 00:05:11 +000011#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/sched.h>
13#include <linux/mm.h>
14#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/signal.h>
17#include <linux/syscalls.h>
18#include <linux/errno.h>
19#include <linux/wait.h>
20#include <linux/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/suspend.h>
22#include <linux/compiler.h>
Atsushi Nemotofaea6232007-04-16 23:19:44 +090023#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Ralf Baechlee50c0a8f2005-05-31 11:49:19 +000025#include <asm/abi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/asm.h>
Ralf Baechle431dc802007-02-13 00:05:11 +000027#include <asm/compat-signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/bitops.h>
29#include <asm/cacheflush.h>
30#include <asm/sim.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/ucontext.h>
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-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{
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;
291 sigdelsetmask(&newset, ~_BLOCKABLE);
292
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000293 current->saved_sigmask = current->blocked;
Matt Fleming8598f3c2012-02-14 11:40:52 +0000294 set_current_blocked(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000296 current->state = TASK_INTERRUPTIBLE;
297 schedule();
298 set_thread_flag(TIF_RESTORE_SIGMASK);
299 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100302asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900304 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000305 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000306 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 /* XXX Don't preclude handling different sized sigset_t's. */
309 sigsetsize = regs.regs[5];
310 if (sigsetsize != sizeof(compat_sigset_t))
311 return -EINVAL;
312
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900313 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (get_sigset(&newset, uset))
315 return -EFAULT;
316 sigdelsetmask(&newset, ~_BLOCKABLE);
317
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000318 current->saved_sigmask = current->blocked;
Matt Fleming8598f3c2012-02-14 11:40:52 +0000319 set_current_blocked(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000321 current->state = TASK_INTERRUPTIBLE;
322 schedule();
323 set_thread_flag(TIF_RESTORE_SIGMASK);
324 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325}
326
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000327SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
328 struct sigaction32 __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 struct k_sigaction new_ka, old_ka;
331 int ret;
332 int err = 0;
333
334 if (act) {
335 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000336 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
339 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000340 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900341 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
343 err |= __get_user(mask, &act->sa_mask.sig[0]);
344 if (err)
345 return -EFAULT;
346
347 siginitset(&new_ka.sa.sa_mask, mask);
348 }
349
350 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
351
352 if (!ret && oact) {
353 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000354 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
356 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
357 &oact->sa_handler);
358 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000359 err |= __put_user(0, &oact->sa_mask.sig[1]);
360 err |= __put_user(0, &oact->sa_mask.sig[2]);
361 err |= __put_user(0, &oact->sa_mask.sig[3]);
362 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return -EFAULT;
364 }
365
366 return ret;
367}
368
369asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
370{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900371 const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
372 stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 unsigned long usp = regs.regs[29];
374 stack_t kss, koss;
375 int ret, err = 0;
376 mm_segment_t old_fs = get_fs();
377 s32 sp;
378
379 if (uss) {
380 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
381 return -EFAULT;
382 err |= __get_user(sp, &uss->ss_sp);
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900383 kss.ss_sp = (void __user *) (long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 err |= __get_user(kss.ss_size, &uss->ss_size);
385 err |= __get_user(kss.ss_flags, &uss->ss_flags);
386 if (err)
387 return -EFAULT;
388 }
389
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100390 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900391 ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
392 uoss ? (stack_t __user *)&koss : NULL, usp);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100393 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
395 if (!ret && uoss) {
396 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
397 return -EFAULT;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900398 sp = (int) (unsigned long) koss.ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 err |= __put_user(sp, &uoss->ss_sp);
400 err |= __put_user(koss.ss_size, &uoss->ss_size);
401 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
402 if (err)
403 return -EFAULT;
404 }
405 return ret;
406}
407
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900408int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 int err;
411
412 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
413 return -EFAULT;
414
415 /* If you change siginfo_t structure, please be sure
416 this code is fixed accordingly.
417 It should never copy any pad contained in the structure
418 to avoid security leaks, but must copy the generic
419 3 ints plus the relevant union member.
420 This routine must convert siginfo from 64bit to 32bit as well
421 at the same time. */
422 err = __put_user(from->si_signo, &to->si_signo);
423 err |= __put_user(from->si_errno, &to->si_errno);
424 err |= __put_user((short)from->si_code, &to->si_code);
425 if (from->si_code < 0)
426 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
427 else {
428 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000429 case __SI_TIMER >> 16:
430 err |= __put_user(from->si_tid, &to->si_tid);
431 err |= __put_user(from->si_overrun, &to->si_overrun);
432 err |= __put_user(from->si_int, &to->si_int);
433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 case __SI_CHLD >> 16:
435 err |= __put_user(from->si_utime, &to->si_utime);
436 err |= __put_user(from->si_stime, &to->si_stime);
437 err |= __put_user(from->si_status, &to->si_status);
438 default:
439 err |= __put_user(from->si_pid, &to->si_pid);
440 err |= __put_user(from->si_uid, &to->si_uid);
441 break;
442 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900443 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445 case __SI_POLL >> 16:
446 err |= __put_user(from->si_band, &to->si_band);
447 err |= __put_user(from->si_fd, &to->si_fd);
448 break;
449 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
450 case __SI_MESGQ >> 16:
451 err |= __put_user(from->si_pid, &to->si_pid);
452 err |= __put_user(from->si_uid, &to->si_uid);
453 err |= __put_user(from->si_int, &to->si_int);
454 break;
455 }
456 }
457 return err;
458}
459
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200460int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
461{
462 memset(to, 0, sizeof *to);
463
464 if (copy_from_user(to, from, 3*sizeof(int)) ||
465 copy_from_user(to->_sifields._pad,
466 from->_sifields._pad, SI_PAD_SIZE32))
467 return -EFAULT;
468
469 return 0;
470}
471
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100472asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Ralf Baechledd02f062007-02-13 00:50:57 +0000474 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900476 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Ralf Baechledd02f062007-02-13 00:50:57 +0000478 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
480 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000481 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 goto badframe;
483
484 sigdelsetmask(&blocked, ~_BLOCKABLE);
Matt Fleming8598f3c2012-02-14 11:40:52 +0000485 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900487 sig = restore_sigcontext32(&regs, &frame->sf_sc);
488 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900490 else if (sig)
491 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 /*
494 * Don't let your children do this ...
495 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 __asm__ __volatile__(
497 "move\t$29, %0\n\t"
498 "j\tsyscall_exit"
499 :/* no outputs */
500 :"r" (&regs));
501 /* Unreached */
502
503badframe:
504 force_sig(SIGSEGV, current);
505}
506
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100507asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900509 struct rt_sigframe32 __user *frame;
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000510 mm_segment_t old_fs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 sigset_t set;
512 stack_t st;
513 s32 sp;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900514 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900516 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
518 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000519 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 goto badframe;
521
522 sigdelsetmask(&set, ~_BLOCKABLE);
Matt Fleming8598f3c2012-02-14 11:40:52 +0000523 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900525 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
526 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900528 else if (sig)
529 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 /* The ucontext contains a stack32_t, so we must convert! */
532 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
533 goto badframe;
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900534 st.ss_sp = (void __user *)(long) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
536 goto badframe;
537 if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
538 goto badframe;
539
540 /* It is more difficult to avoid calling this function than to
541 call it and ignore errors. */
Ralf Baechle1fcf1cc2005-04-13 18:18:04 +0000542 old_fs = get_fs();
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100543 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900544 do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100545 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 /*
548 * Don't let your children do this ...
549 */
550 __asm__ __volatile__(
551 "move\t$29, %0\n\t"
552 "j\tsyscall_exit"
553 :/* no outputs */
554 :"r" (&regs));
555 /* Unreached */
556
557badframe:
558 force_sig(SIGSEGV, current);
559}
560
David Daneyd814c282010-02-18 16:13:05 -0800561static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
562 struct pt_regs *regs, int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Ralf Baechledd02f062007-02-13 00:50:57 +0000564 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 int err = 0;
566
567 frame = get_sigframe(ka, regs, sizeof(*frame));
568 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
569 goto give_sigsegv;
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000572 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (err)
575 goto give_sigsegv;
576
577 /*
578 * Arguments to signal handler:
579 *
580 * a0 = signal number
581 * a1 = 0 (should be cause)
582 * a2 = pointer to struct sigcontext
583 *
584 * $25 and c0_epc point to the signal handler, $29 points to the
585 * struct sigframe.
586 */
587 regs->regs[ 4] = signr;
588 regs->regs[ 5] = 0;
589 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
590 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800591 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
593
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100594 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100596 frame, regs->cp0_epc, regs->regs[31]);
597
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000598 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600give_sigsegv:
601 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000602 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
David Daneyd814c282010-02-18 16:13:05 -0800605static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
606 struct pt_regs *regs, int signr, sigset_t *set,
607 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900609 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 int err = 0;
611 s32 sp;
612
613 frame = get_sigframe(ka, regs, sizeof(*frame));
614 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
615 goto give_sigsegv;
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
618 err |= copy_siginfo_to_user32(&frame->rs_info, info);
619
620 /* Create the ucontext. */
621 err |= __put_user(0, &frame->rs_uc.uc_flags);
622 err |= __put_user(0, &frame->rs_uc.uc_link);
623 sp = (int) (long) current->sas_ss_sp;
624 err |= __put_user(sp,
625 &frame->rs_uc.uc_stack.ss_sp);
626 err |= __put_user(sas_ss_flags(regs->regs[29]),
627 &frame->rs_uc.uc_stack.ss_flags);
628 err |= __put_user(current->sas_ss_size,
629 &frame->rs_uc.uc_stack.ss_size);
630 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000631 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 if (err)
634 goto give_sigsegv;
635
636 /*
637 * Arguments to signal handler:
638 *
639 * a0 = signal number
640 * a1 = 0 (should be cause)
641 * a2 = pointer to ucontext
642 *
643 * $25 and c0_epc point to the signal handler, $29 points to
644 * the struct rt_sigframe32.
645 */
646 regs->regs[ 4] = signr;
647 regs->regs[ 5] = (unsigned long) &frame->rs_info;
648 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
649 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800650 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
652
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100653 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100655 frame, regs->cp0_epc, regs->regs[31]);
656
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000657 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659give_sigsegv:
660 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000661 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000664/*
665 * o32 compatibility on 64-bit kernels, without DSP ASE
666 */
667struct mips_abi mips_abi_32 = {
668 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800669 .signal_return_offset =
670 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000671 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800672 .rt_signal_return_offset =
673 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000674 .restart = __NR_O32_restart_syscall
675};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000677SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
678 const struct sigaction32 __user *, act,
679 struct sigaction32 __user *, oact, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 struct k_sigaction new_sa, old_sa;
682 int ret = -EINVAL;
683
684 /* XXX: Don't preclude handling different sized sigset_t's. */
685 if (sigsetsize != sizeof(sigset_t))
686 goto out;
687
688 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000689 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 int err = 0;
691
692 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
693 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000694 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900695 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
697 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
698 if (err)
699 return -EFAULT;
700 }
701
702 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
703
704 if (!ret && oact) {
705 int err = 0;
706
707 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
708 return -EFAULT;
709
710 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
711 &oact->sa_handler);
712 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
713 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
714 if (err)
715 return -EFAULT;
716 }
717out:
718 return ret;
719}
720
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000721SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
722 compat_sigset_t __user *, oset, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
724 sigset_t old_set, new_set;
725 int ret;
726 mm_segment_t old_fs = get_fs();
727
728 if (set && get_sigset(&new_set, set))
729 return -EFAULT;
730
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100731 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900732 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
733 oset ? (sigset_t __user *)&old_set : NULL,
734 sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100735 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
737 if (!ret && oset && put_sigset(&old_set, oset))
738 return -EFAULT;
739
740 return ret;
741}
742
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000743SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
744 unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
746 int ret;
747 sigset_t set;
748 mm_segment_t old_fs = get_fs();
749
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100750 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900751 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100752 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754 if (!ret && put_sigset(&set, uset))
755 return -EFAULT;
756
757 return ret;
758}
759
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000760SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
761 compat_siginfo_t __user *, uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 siginfo_t info;
764 int ret;
765 mm_segment_t old_fs = get_fs();
766
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100767 if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
768 copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return -EFAULT;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100770 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900771 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100772 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return ret;
774}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000775
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000776SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
777 compat_siginfo_t __user *, uinfo, int, options,
778 struct compat_rusage __user *, uru)
Ralf Baechle54f2da72005-02-16 21:21:29 +0000779{
780 siginfo_t info;
781 struct rusage ru;
782 long ret;
783 mm_segment_t old_fs = get_fs();
784
785 info.si_signo = 0;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100786 set_fs(KERNEL_DS);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000787 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
788 uru ? (struct rusage __user *) &ru : NULL);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100789 set_fs(old_fs);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000790
791 if (ret < 0 || info.si_signo == 0)
792 return ret;
793
794 if (uru && (ret = put_compat_rusage(&ru, uru)))
795 return ret;
796
797 BUG_ON(info.si_code & __SI_MASK);
798 info.si_code |= __SI_CHLD;
799 return copy_siginfo_to_user32(uinfo, &info);
800}
Ralf Baechle137f6f32009-11-24 19:35:41 +0000801
802static int signal32_init(void)
803{
804 if (cpu_has_fpu) {
805 save_fp_context32 = _save_fp_context32;
806 restore_fp_context32 = _restore_fp_context32;
807 } else {
808 save_fp_context32 = fpu_emulator_save_context32;
809 restore_fp_context32 = fpu_emulator_restore_context32;
810 }
811
812 return 0;
813}
814
815arch_initcall(signal32_init);