blob: c51e5df4297bf4b655aa0970c90bc7ade353d920 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070064struct ucontext32 {
65 u32 uc_flags;
66 s32 uc_link;
Al Viroea536ad2012-12-23 03:13:40 -050067 compat_stack_t uc_stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +000069 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070};
71
Ralf Baechledd02f062007-02-13 00:50:57 +000072struct sigframe32 {
73 u32 sf_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080074 u32 sf_pad[2]; /* Was: signal trampoline */
Ralf Baechledd02f062007-02-13 00:50:57 +000075 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090076 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000077};
78
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010079struct rt_sigframe32 {
80 u32 rs_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080081 u32 rs_pad[2]; /* Was: signal trampoline */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010082 compat_siginfo_t rs_info;
83 struct ucontext32 rs_uc;
84};
85
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +010086/*
87 * sigcontext handlers
88 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +090089static int protected_save_fp_context32(struct sigcontext32 __user *sc)
90{
91 int err;
92 while (1) {
93 lock_fpu_owner();
94 own_fpu_inatomic(1);
95 err = save_fp_context32(sc); /* this might fail */
96 unlock_fpu_owner();
97 if (likely(!err))
98 break;
99 /* touch the sigcontext and try again */
100 err = __put_user(0, &sc->sc_fpregs[0]) |
101 __put_user(0, &sc->sc_fpregs[31]) |
102 __put_user(0, &sc->sc_fpc_csr);
103 if (err)
104 break; /* really bad sigcontext */
105 }
106 return err;
107}
108
109static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
110{
David Daneyc726b822011-01-24 14:51:34 -0800111 int err, tmp __maybe_unused;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900112 while (1) {
113 lock_fpu_owner();
114 own_fpu_inatomic(0);
115 err = restore_fp_context32(sc); /* this might fail */
116 unlock_fpu_owner();
117 if (likely(!err))
118 break;
119 /* touch the sigcontext and try again */
120 err = __get_user(tmp, &sc->sc_fpregs[0]) |
121 __get_user(tmp, &sc->sc_fpregs[31]) |
122 __get_user(tmp, &sc->sc_fpc_csr);
123 if (err)
124 break; /* really bad sigcontext */
125 }
126 return err;
127}
128
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100129static int setup_sigcontext32(struct pt_regs *regs,
130 struct sigcontext32 __user *sc)
131{
132 int err = 0;
133 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900134 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100135
136 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100137
138 err |= __put_user(0, &sc->sc_regs[0]);
139 for (i = 1; i < 32; i++)
140 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
141
142 err |= __put_user(regs->hi, &sc->sc_mdhi);
143 err |= __put_user(regs->lo, &sc->sc_mdlo);
144 if (cpu_has_dsp) {
145 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
146 err |= __put_user(mfhi1(), &sc->sc_hi1);
147 err |= __put_user(mflo1(), &sc->sc_lo1);
148 err |= __put_user(mfhi2(), &sc->sc_hi2);
149 err |= __put_user(mflo2(), &sc->sc_lo2);
150 err |= __put_user(mfhi3(), &sc->sc_hi3);
151 err |= __put_user(mflo3(), &sc->sc_lo3);
152 }
153
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900154 used_math = !!used_math();
155 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100156
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900157 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100158 /*
159 * Save FPU state to signal context. Signal handler
160 * will "inherit" current FPU state.
161 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900162 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100163 }
164 return err;
165}
166
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900167static int
168check_and_restore_fp_context32(struct sigcontext32 __user *sc)
169{
170 int err, sig;
171
172 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
173 if (err > 0)
174 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900175 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900176 return err ?: sig;
177}
178
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100179static int restore_sigcontext32(struct pt_regs *regs,
180 struct sigcontext32 __user *sc)
181{
182 u32 used_math;
183 int err = 0;
184 s32 treg;
185 int i;
186
187 /* Always make any pending restarted system calls return -EINTR */
188 current_thread_info()->restart_block.fn = do_no_restart_syscall;
189
190 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
191 err |= __get_user(regs->hi, &sc->sc_mdhi);
192 err |= __get_user(regs->lo, &sc->sc_mdlo);
193 if (cpu_has_dsp) {
194 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
195 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
196 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
197 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
198 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
199 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
200 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
201 }
202
203 for (i = 1; i < 32; i++)
204 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
205
206 err |= __get_user(used_math, &sc->sc_used_math);
207 conditional_used_math(used_math);
208
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900209 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100210 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900211 if (!err)
212 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100213 } else {
214 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900215 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100216 }
217
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100218 return err;
219}
220
221/*
222 *
223 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224extern void __put_sigset_unknown_nsig(void);
225extern void __get_sigset_unknown_nsig(void);
226
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900227static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 int err = 0;
230
231 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
232 return -EFAULT;
233
234 switch (_NSIG_WORDS) {
235 default:
236 __put_sigset_unknown_nsig();
237 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100238 err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
239 err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100241 err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
242 err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 }
244
245 return err;
246}
247
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900248static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
250 int err = 0;
251 unsigned long sig[4];
252
253 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
254 return -EFAULT;
255
256 switch (_NSIG_WORDS) {
257 default:
258 __get_sigset_unknown_nsig();
259 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100260 err |= __get_user(sig[3], &ubuf->sig[3]);
261 err |= __get_user(sig[2], &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 kbuf->sig[1] = sig[2] | (sig[3] << 32);
263 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100264 err |= __get_user(sig[1], &ubuf->sig[1]);
265 err |= __get_user(sig[0], &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 kbuf->sig[0] = sig[0] | (sig[1] << 32);
267 }
268
269 return err;
270}
271
272/*
273 * Atomically swap in the new signal mask, and wait for a signal.
274 */
275
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100276asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900278 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000279 sigset_t newset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900281 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (get_sigset(&newset, uset))
283 return -EFAULT;
Al Viro68f3f162012-05-21 21:42:32 -0400284 return sigsuspend(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285}
286
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100287asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900289 compat_sigset_t __user *uset;
Martin Michlmayr68fa3832006-02-18 14:55:45 +0000290 sigset_t newset;
Ralf Baechle304416d2006-02-18 18:20:47 +0000291 size_t sigsetsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293 /* XXX Don't preclude handling different sized sigset_t's. */
294 sigsetsize = regs.regs[5];
295 if (sigsetsize != sizeof(compat_sigset_t))
296 return -EINVAL;
297
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900298 uset = (compat_sigset_t __user *) regs.regs[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 if (get_sigset(&newset, uset))
300 return -EFAULT;
Al Viro68f3f162012-05-21 21:42:32 -0400301 return sigsuspend(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000304SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
305 struct sigaction32 __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
307 struct k_sigaction new_ka, old_ka;
308 int ret;
309 int err = 0;
310
311 if (act) {
312 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000313 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
316 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000317 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900318 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
320 err |= __get_user(mask, &act->sa_mask.sig[0]);
321 if (err)
322 return -EFAULT;
323
324 siginitset(&new_ka.sa.sa_mask, mask);
325 }
326
327 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
328
329 if (!ret && oact) {
330 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000331 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
333 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
334 &oact->sa_handler);
335 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000336 err |= __put_user(0, &oact->sa_mask.sig[1]);
337 err |= __put_user(0, &oact->sa_mask.sig[2]);
338 err |= __put_user(0, &oact->sa_mask.sig[3]);
339 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return -EFAULT;
341 }
342
343 return ret;
344}
345
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900346int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 int err;
349
350 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
351 return -EFAULT;
352
353 /* If you change siginfo_t structure, please be sure
354 this code is fixed accordingly.
355 It should never copy any pad contained in the structure
356 to avoid security leaks, but must copy the generic
357 3 ints plus the relevant union member.
358 This routine must convert siginfo from 64bit to 32bit as well
359 at the same time. */
360 err = __put_user(from->si_signo, &to->si_signo);
361 err |= __put_user(from->si_errno, &to->si_errno);
362 err |= __put_user((short)from->si_code, &to->si_code);
363 if (from->si_code < 0)
364 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
365 else {
366 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000367 case __SI_TIMER >> 16:
368 err |= __put_user(from->si_tid, &to->si_tid);
369 err |= __put_user(from->si_overrun, &to->si_overrun);
370 err |= __put_user(from->si_int, &to->si_int);
371 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 case __SI_CHLD >> 16:
373 err |= __put_user(from->si_utime, &to->si_utime);
374 err |= __put_user(from->si_stime, &to->si_stime);
375 err |= __put_user(from->si_status, &to->si_status);
376 default:
377 err |= __put_user(from->si_pid, &to->si_pid);
378 err |= __put_user(from->si_uid, &to->si_uid);
379 break;
380 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900381 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 break;
383 case __SI_POLL >> 16:
384 err |= __put_user(from->si_band, &to->si_band);
385 err |= __put_user(from->si_fd, &to->si_fd);
386 break;
387 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
388 case __SI_MESGQ >> 16:
389 err |= __put_user(from->si_pid, &to->si_pid);
390 err |= __put_user(from->si_uid, &to->si_uid);
391 err |= __put_user(from->si_int, &to->si_int);
392 break;
393 }
394 }
395 return err;
396}
397
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200398int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
399{
400 memset(to, 0, sizeof *to);
401
402 if (copy_from_user(to, from, 3*sizeof(int)) ||
403 copy_from_user(to->_sifields._pad,
404 from->_sifields._pad, SI_PAD_SIZE32))
405 return -EFAULT;
406
407 return 0;
408}
409
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100410asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Ralf Baechledd02f062007-02-13 00:50:57 +0000412 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900414 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Ralf Baechledd02f062007-02-13 00:50:57 +0000416 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
418 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000419 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 goto badframe;
421
Matt Fleming8598f3c2012-02-14 11:40:52 +0000422 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900424 sig = restore_sigcontext32(&regs, &frame->sf_sc);
425 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900427 else if (sig)
428 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
430 /*
431 * Don't let your children do this ...
432 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 __asm__ __volatile__(
434 "move\t$29, %0\n\t"
435 "j\tsyscall_exit"
436 :/* no outputs */
437 :"r" (&regs));
438 /* Unreached */
439
440badframe:
441 force_sig(SIGSEGV, current);
442}
443
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100444asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900446 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 sigset_t set;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900448 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900450 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
452 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000453 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 goto badframe;
455
Matt Fleming8598f3c2012-02-14 11:40:52 +0000456 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900458 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
459 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900461 else if (sig)
462 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Al Viroea536ad2012-12-23 03:13:40 -0500464 if (compat_restore_altstack(&frame->rs_uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 /*
468 * Don't let your children do this ...
469 */
470 __asm__ __volatile__(
471 "move\t$29, %0\n\t"
472 "j\tsyscall_exit"
473 :/* no outputs */
474 :"r" (&regs));
475 /* Unreached */
476
477badframe:
478 force_sig(SIGSEGV, current);
479}
480
David Daneyd814c282010-02-18 16:13:05 -0800481static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
482 struct pt_regs *regs, int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Ralf Baechledd02f062007-02-13 00:50:57 +0000484 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 int err = 0;
486
487 frame = get_sigframe(ka, regs, sizeof(*frame));
488 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
489 goto give_sigsegv;
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000492 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (err)
495 goto give_sigsegv;
496
497 /*
498 * Arguments to signal handler:
499 *
500 * a0 = signal number
501 * a1 = 0 (should be cause)
502 * a2 = pointer to struct sigcontext
503 *
504 * $25 and c0_epc point to the signal handler, $29 points to the
505 * struct sigframe.
506 */
507 regs->regs[ 4] = signr;
508 regs->regs[ 5] = 0;
509 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
510 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800511 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
513
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100514 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100516 frame, regs->cp0_epc, regs->regs[31]);
517
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000518 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520give_sigsegv:
521 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000522 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
David Daneyd814c282010-02-18 16:13:05 -0800525static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
526 struct pt_regs *regs, int signr, sigset_t *set,
527 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900529 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 frame = get_sigframe(ka, regs, sizeof(*frame));
533 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
534 goto give_sigsegv;
535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
537 err |= copy_siginfo_to_user32(&frame->rs_info, info);
538
539 /* Create the ucontext. */
540 err |= __put_user(0, &frame->rs_uc.uc_flags);
541 err |= __put_user(0, &frame->rs_uc.uc_link);
Al Viroea536ad2012-12-23 03:13:40 -0500542 err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000544 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 if (err)
547 goto give_sigsegv;
548
549 /*
550 * Arguments to signal handler:
551 *
552 * a0 = signal number
553 * a1 = 0 (should be cause)
554 * a2 = pointer to ucontext
555 *
556 * $25 and c0_epc point to the signal handler, $29 points to
557 * the struct rt_sigframe32.
558 */
559 regs->regs[ 4] = signr;
560 regs->regs[ 5] = (unsigned long) &frame->rs_info;
561 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
562 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800563 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
565
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100566 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100568 frame, regs->cp0_epc, regs->regs[31]);
569
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000570 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572give_sigsegv:
573 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000574 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000577/*
578 * o32 compatibility on 64-bit kernels, without DSP ASE
579 */
580struct mips_abi mips_abi_32 = {
581 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800582 .signal_return_offset =
583 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000584 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800585 .rt_signal_return_offset =
586 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000587 .restart = __NR_O32_restart_syscall
588};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000590SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
591 const struct sigaction32 __user *, act,
592 struct sigaction32 __user *, oact, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 struct k_sigaction new_sa, old_sa;
595 int ret = -EINVAL;
596
597 /* XXX: Don't preclude handling different sized sigset_t's. */
598 if (sigsetsize != sizeof(sigset_t))
599 goto out;
600
601 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000602 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 int err = 0;
604
605 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
606 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000607 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900608 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
610 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
611 if (err)
612 return -EFAULT;
613 }
614
615 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
616
617 if (!ret && oact) {
618 int err = 0;
619
620 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
621 return -EFAULT;
622
623 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
624 &oact->sa_handler);
625 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
626 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
627 if (err)
628 return -EFAULT;
629 }
630out:
631 return ret;
632}
633
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000634SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
635 compat_sigset_t __user *, oset, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
637 sigset_t old_set, new_set;
638 int ret;
639 mm_segment_t old_fs = get_fs();
640
641 if (set && get_sigset(&new_set, set))
642 return -EFAULT;
643
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100644 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900645 ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
646 oset ? (sigset_t __user *)&old_set : NULL,
647 sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100648 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 if (!ret && oset && put_sigset(&old_set, oset))
651 return -EFAULT;
652
653 return ret;
654}
655
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000656SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
657 unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
659 int ret;
660 sigset_t set;
661 mm_segment_t old_fs = get_fs();
662
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100663 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900664 ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100665 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 if (!ret && put_sigset(&set, uset))
668 return -EFAULT;
669
670 return ret;
671}
672
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000673SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
674 compat_siginfo_t __user *, uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 siginfo_t info;
677 int ret;
678 mm_segment_t old_fs = get_fs();
679
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100680 if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
681 copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 return -EFAULT;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100683 set_fs(KERNEL_DS);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900684 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100685 set_fs(old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return ret;
687}
Ralf Baechle54f2da72005-02-16 21:21:29 +0000688
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000689SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
690 compat_siginfo_t __user *, uinfo, int, options,
691 struct compat_rusage __user *, uru)
Ralf Baechle54f2da72005-02-16 21:21:29 +0000692{
693 siginfo_t info;
694 struct rusage ru;
695 long ret;
696 mm_segment_t old_fs = get_fs();
697
698 info.si_signo = 0;
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100699 set_fs(KERNEL_DS);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000700 ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
701 uru ? (struct rusage __user *) &ru : NULL);
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100702 set_fs(old_fs);
Ralf Baechle54f2da72005-02-16 21:21:29 +0000703
704 if (ret < 0 || info.si_signo == 0)
705 return ret;
706
707 if (uru && (ret = put_compat_rusage(&ru, uru)))
708 return ret;
709
710 BUG_ON(info.si_code & __SI_MASK);
711 info.si_code |= __SI_CHLD;
712 return copy_siginfo_to_user32(uinfo, &info);
713}
Ralf Baechle137f6f32009-11-24 19:35:41 +0000714
715static int signal32_init(void)
716{
717 if (cpu_has_fpu) {
718 save_fp_context32 = _save_fp_context32;
719 restore_fp_context32 = _restore_fp_context32;
720 } else {
721 save_fp_context32 = fpu_emulator_save_context32;
722 restore_fp_context32 = fpu_emulator_restore_context32;
723 }
724
725 return 0;
726}
727
728arch_initcall(signal32_init);