blob: 0b1f57111eae9b9301f9b166388ca890fd23a6a2 [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
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
Al Viro1910f4a2012-12-25 16:25:18 -0500276asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
Al Viro1910f4a2012-12-25 16:25:18 -0500278 return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000281SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
282 struct sigaction32 __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
284 struct k_sigaction new_ka, old_ka;
285 int ret;
286 int err = 0;
287
288 if (act) {
289 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000290 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
293 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000294 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900295 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
297 err |= __get_user(mask, &act->sa_mask.sig[0]);
298 if (err)
299 return -EFAULT;
300
301 siginitset(&new_ka.sa.sa_mask, mask);
302 }
303
304 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
305
306 if (!ret && oact) {
307 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000308 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
310 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
311 &oact->sa_handler);
312 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000313 err |= __put_user(0, &oact->sa_mask.sig[1]);
314 err |= __put_user(0, &oact->sa_mask.sig[2]);
315 err |= __put_user(0, &oact->sa_mask.sig[3]);
316 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return -EFAULT;
318 }
319
320 return ret;
321}
322
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900323int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 int err;
326
327 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
328 return -EFAULT;
329
330 /* If you change siginfo_t structure, please be sure
331 this code is fixed accordingly.
332 It should never copy any pad contained in the structure
333 to avoid security leaks, but must copy the generic
334 3 ints plus the relevant union member.
335 This routine must convert siginfo from 64bit to 32bit as well
336 at the same time. */
337 err = __put_user(from->si_signo, &to->si_signo);
338 err |= __put_user(from->si_errno, &to->si_errno);
339 err |= __put_user((short)from->si_code, &to->si_code);
340 if (from->si_code < 0)
341 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
342 else {
343 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000344 case __SI_TIMER >> 16:
345 err |= __put_user(from->si_tid, &to->si_tid);
346 err |= __put_user(from->si_overrun, &to->si_overrun);
347 err |= __put_user(from->si_int, &to->si_int);
348 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 case __SI_CHLD >> 16:
350 err |= __put_user(from->si_utime, &to->si_utime);
351 err |= __put_user(from->si_stime, &to->si_stime);
352 err |= __put_user(from->si_status, &to->si_status);
353 default:
354 err |= __put_user(from->si_pid, &to->si_pid);
355 err |= __put_user(from->si_uid, &to->si_uid);
356 break;
357 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900358 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 break;
360 case __SI_POLL >> 16:
361 err |= __put_user(from->si_band, &to->si_band);
362 err |= __put_user(from->si_fd, &to->si_fd);
363 break;
364 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
365 case __SI_MESGQ >> 16:
366 err |= __put_user(from->si_pid, &to->si_pid);
367 err |= __put_user(from->si_uid, &to->si_uid);
368 err |= __put_user(from->si_int, &to->si_int);
369 break;
370 }
371 }
372 return err;
373}
374
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200375int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
376{
377 memset(to, 0, sizeof *to);
378
379 if (copy_from_user(to, from, 3*sizeof(int)) ||
380 copy_from_user(to->_sifields._pad,
381 from->_sifields._pad, SI_PAD_SIZE32))
382 return -EFAULT;
383
384 return 0;
385}
386
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100387asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
Ralf Baechledd02f062007-02-13 00:50:57 +0000389 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900391 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Ralf Baechledd02f062007-02-13 00:50:57 +0000393 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
395 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000396 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 goto badframe;
398
Matt Fleming8598f3c2012-02-14 11:40:52 +0000399 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900401 sig = restore_sigcontext32(&regs, &frame->sf_sc);
402 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900404 else if (sig)
405 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 /*
408 * Don't let your children do this ...
409 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 __asm__ __volatile__(
411 "move\t$29, %0\n\t"
412 "j\tsyscall_exit"
413 :/* no outputs */
414 :"r" (&regs));
415 /* Unreached */
416
417badframe:
418 force_sig(SIGSEGV, current);
419}
420
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100421asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900423 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 sigset_t set;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900425 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900427 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
429 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000430 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 goto badframe;
432
Matt Fleming8598f3c2012-02-14 11:40:52 +0000433 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900435 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
436 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900438 else if (sig)
439 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Al Viroea536ad2012-12-23 03:13:40 -0500441 if (compat_restore_altstack(&frame->rs_uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 /*
445 * Don't let your children do this ...
446 */
447 __asm__ __volatile__(
448 "move\t$29, %0\n\t"
449 "j\tsyscall_exit"
450 :/* no outputs */
451 :"r" (&regs));
452 /* Unreached */
453
454badframe:
455 force_sig(SIGSEGV, current);
456}
457
David Daneyd814c282010-02-18 16:13:05 -0800458static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
459 struct pt_regs *regs, int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
Ralf Baechledd02f062007-02-13 00:50:57 +0000461 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 int err = 0;
463
464 frame = get_sigframe(ka, regs, sizeof(*frame));
465 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
466 goto give_sigsegv;
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000469 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (err)
472 goto give_sigsegv;
473
474 /*
475 * Arguments to signal handler:
476 *
477 * a0 = signal number
478 * a1 = 0 (should be cause)
479 * a2 = pointer to struct sigcontext
480 *
481 * $25 and c0_epc point to the signal handler, $29 points to the
482 * struct sigframe.
483 */
484 regs->regs[ 4] = signr;
485 regs->regs[ 5] = 0;
486 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
487 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800488 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
490
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100491 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100493 frame, regs->cp0_epc, regs->regs[31]);
494
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000495 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497give_sigsegv:
498 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000499 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
David Daneyd814c282010-02-18 16:13:05 -0800502static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
503 struct pt_regs *regs, int signr, sigset_t *set,
504 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900506 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 frame = get_sigframe(ka, regs, sizeof(*frame));
510 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
511 goto give_sigsegv;
512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
514 err |= copy_siginfo_to_user32(&frame->rs_info, info);
515
516 /* Create the ucontext. */
517 err |= __put_user(0, &frame->rs_uc.uc_flags);
518 err |= __put_user(0, &frame->rs_uc.uc_link);
Al Viroea536ad2012-12-23 03:13:40 -0500519 err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000521 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523 if (err)
524 goto give_sigsegv;
525
526 /*
527 * Arguments to signal handler:
528 *
529 * a0 = signal number
530 * a1 = 0 (should be cause)
531 * a2 = pointer to ucontext
532 *
533 * $25 and c0_epc point to the signal handler, $29 points to
534 * the struct rt_sigframe32.
535 */
536 regs->regs[ 4] = signr;
537 regs->regs[ 5] = (unsigned long) &frame->rs_info;
538 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
539 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800540 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
542
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100543 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100545 frame, regs->cp0_epc, regs->regs[31]);
546
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000547 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549give_sigsegv:
550 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000551 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000554/*
555 * o32 compatibility on 64-bit kernels, without DSP ASE
556 */
557struct mips_abi mips_abi_32 = {
558 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800559 .signal_return_offset =
560 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000561 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800562 .rt_signal_return_offset =
563 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000564 .restart = __NR_O32_restart_syscall
565};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Ralf Baechledbda6ac2009-02-08 16:00:26 +0000567SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
568 const struct sigaction32 __user *, act,
569 struct sigaction32 __user *, oact, unsigned int, sigsetsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 struct k_sigaction new_sa, old_sa;
572 int ret = -EINVAL;
573
574 /* XXX: Don't preclude handling different sized sigset_t's. */
575 if (sigsetsize != sizeof(sigset_t))
576 goto out;
577
578 if (act) {
Ralf Baechle77c728c2005-03-04 19:36:51 +0000579 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 int err = 0;
581
582 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
583 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000584 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900585 new_sa.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
587 err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
588 if (err)
589 return -EFAULT;
590 }
591
592 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
593
594 if (!ret && oact) {
595 int err = 0;
596
597 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
598 return -EFAULT;
599
600 err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
601 &oact->sa_handler);
602 err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
603 err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
604 if (err)
605 return -EFAULT;
606 }
607out:
608 return ret;
609}
610
Ralf Baechle137f6f32009-11-24 19:35:41 +0000611static int signal32_init(void)
612{
613 if (cpu_has_fpu) {
614 save_fp_context32 = _save_fp_context32;
615 restore_fp_context32 = _restore_fp_context32;
616 } else {
617 save_fp_context32 = fpu_emulator_save_context32;
618 restore_fp_context32 = fpu_emulator_restore_context32;
619 }
620
621 return 0;
622}
623
624arch_initcall(signal32_init);