blob: ad7c2be0c33dfee94565743e222e6a5d57dd6e65 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070058struct ucontext32 {
59 u32 uc_flags;
60 s32 uc_link;
Al Viroea536ad2012-12-23 03:13:40 -050061 compat_stack_t uc_stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 struct sigcontext32 uc_mcontext;
Ralf Baechle01ee6032007-02-11 18:22:36 +000063 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064};
65
Ralf Baechledd02f062007-02-13 00:50:57 +000066struct sigframe32 {
67 u32 sf_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080068 u32 sf_pad[2]; /* Was: signal trampoline */
Ralf Baechledd02f062007-02-13 00:50:57 +000069 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090070 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000071};
72
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010073struct rt_sigframe32 {
74 u32 rs_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080075 u32 rs_pad[2]; /* Was: signal trampoline */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010076 compat_siginfo_t rs_info;
77 struct ucontext32 rs_uc;
78};
79
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +010080/*
81 * sigcontext handlers
82 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +090083static int protected_save_fp_context32(struct sigcontext32 __user *sc)
84{
85 int err;
86 while (1) {
87 lock_fpu_owner();
88 own_fpu_inatomic(1);
89 err = save_fp_context32(sc); /* this might fail */
90 unlock_fpu_owner();
91 if (likely(!err))
92 break;
93 /* touch the sigcontext and try again */
94 err = __put_user(0, &sc->sc_fpregs[0]) |
95 __put_user(0, &sc->sc_fpregs[31]) |
96 __put_user(0, &sc->sc_fpc_csr);
97 if (err)
98 break; /* really bad sigcontext */
99 }
100 return err;
101}
102
103static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
104{
David Daneyc726b822011-01-24 14:51:34 -0800105 int err, tmp __maybe_unused;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900106 while (1) {
107 lock_fpu_owner();
108 own_fpu_inatomic(0);
109 err = restore_fp_context32(sc); /* this might fail */
110 unlock_fpu_owner();
111 if (likely(!err))
112 break;
113 /* touch the sigcontext and try again */
114 err = __get_user(tmp, &sc->sc_fpregs[0]) |
115 __get_user(tmp, &sc->sc_fpregs[31]) |
116 __get_user(tmp, &sc->sc_fpc_csr);
117 if (err)
118 break; /* really bad sigcontext */
119 }
120 return err;
121}
122
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100123static int setup_sigcontext32(struct pt_regs *regs,
124 struct sigcontext32 __user *sc)
125{
126 int err = 0;
127 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900128 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100129
130 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100131
132 err |= __put_user(0, &sc->sc_regs[0]);
133 for (i = 1; i < 32; i++)
134 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
135
136 err |= __put_user(regs->hi, &sc->sc_mdhi);
137 err |= __put_user(regs->lo, &sc->sc_mdlo);
138 if (cpu_has_dsp) {
139 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
140 err |= __put_user(mfhi1(), &sc->sc_hi1);
141 err |= __put_user(mflo1(), &sc->sc_lo1);
142 err |= __put_user(mfhi2(), &sc->sc_hi2);
143 err |= __put_user(mflo2(), &sc->sc_lo2);
144 err |= __put_user(mfhi3(), &sc->sc_hi3);
145 err |= __put_user(mflo3(), &sc->sc_lo3);
146 }
147
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900148 used_math = !!used_math();
149 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100150
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900151 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100152 /*
153 * Save FPU state to signal context. Signal handler
154 * will "inherit" current FPU state.
155 */
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900156 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100157 }
158 return err;
159}
160
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900161static int
162check_and_restore_fp_context32(struct sigcontext32 __user *sc)
163{
164 int err, sig;
165
166 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
167 if (err > 0)
168 err = 0;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900169 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900170 return err ?: sig;
171}
172
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100173static int restore_sigcontext32(struct pt_regs *regs,
174 struct sigcontext32 __user *sc)
175{
176 u32 used_math;
177 int err = 0;
178 s32 treg;
179 int i;
180
181 /* Always make any pending restarted system calls return -EINTR */
182 current_thread_info()->restart_block.fn = do_no_restart_syscall;
183
184 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
185 err |= __get_user(regs->hi, &sc->sc_mdhi);
186 err |= __get_user(regs->lo, &sc->sc_mdlo);
187 if (cpu_has_dsp) {
188 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
189 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
190 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
191 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
192 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
193 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
194 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
195 }
196
197 for (i = 1; i < 32; i++)
198 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
199
200 err |= __get_user(used_math, &sc->sc_used_math);
201 conditional_used_math(used_math);
202
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900203 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100204 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900205 if (!err)
206 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100207 } else {
208 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900209 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100210 }
211
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100212 return err;
213}
214
215/*
216 *
217 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218extern void __put_sigset_unknown_nsig(void);
219extern void __get_sigset_unknown_nsig(void);
220
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900221static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
223 int err = 0;
224
225 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
226 return -EFAULT;
227
228 switch (_NSIG_WORDS) {
229 default:
230 __put_sigset_unknown_nsig();
231 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100232 err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
233 err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100235 err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
236 err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238
239 return err;
240}
241
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900242static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
244 int err = 0;
245 unsigned long sig[4];
246
247 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
248 return -EFAULT;
249
250 switch (_NSIG_WORDS) {
251 default:
252 __get_sigset_unknown_nsig();
253 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100254 err |= __get_user(sig[3], &ubuf->sig[3]);
255 err |= __get_user(sig[2], &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 kbuf->sig[1] = sig[2] | (sig[3] << 32);
257 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100258 err |= __get_user(sig[1], &ubuf->sig[1]);
259 err |= __get_user(sig[0], &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 kbuf->sig[0] = sig[0] | (sig[1] << 32);
261 }
262
263 return err;
264}
265
266/*
267 * Atomically swap in the new signal mask, and wait for a signal.
268 */
269
Al Viro1910f4a2012-12-25 16:25:18 -0500270asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
Al Viro1910f4a2012-12-25 16:25:18 -0500272 return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273}
274
Al Viroaa584802012-12-25 18:55:27 -0500275SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
276 struct compat_sigaction __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct k_sigaction new_ka, old_ka;
279 int ret;
280 int err = 0;
281
282 if (act) {
283 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000284 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
287 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000288 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900289 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
291 err |= __get_user(mask, &act->sa_mask.sig[0]);
292 if (err)
293 return -EFAULT;
294
295 siginitset(&new_ka.sa.sa_mask, mask);
296 }
297
298 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
299
300 if (!ret && oact) {
301 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000302 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
304 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
305 &oact->sa_handler);
306 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000307 err |= __put_user(0, &oact->sa_mask.sig[1]);
308 err |= __put_user(0, &oact->sa_mask.sig[2]);
309 err |= __put_user(0, &oact->sa_mask.sig[3]);
310 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 return -EFAULT;
312 }
313
314 return ret;
315}
316
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900317int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 int err;
320
321 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
322 return -EFAULT;
323
324 /* If you change siginfo_t structure, please be sure
325 this code is fixed accordingly.
326 It should never copy any pad contained in the structure
327 to avoid security leaks, but must copy the generic
328 3 ints plus the relevant union member.
329 This routine must convert siginfo from 64bit to 32bit as well
330 at the same time. */
331 err = __put_user(from->si_signo, &to->si_signo);
332 err |= __put_user(from->si_errno, &to->si_errno);
333 err |= __put_user((short)from->si_code, &to->si_code);
334 if (from->si_code < 0)
335 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
336 else {
337 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000338 case __SI_TIMER >> 16:
339 err |= __put_user(from->si_tid, &to->si_tid);
340 err |= __put_user(from->si_overrun, &to->si_overrun);
341 err |= __put_user(from->si_int, &to->si_int);
342 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 case __SI_CHLD >> 16:
344 err |= __put_user(from->si_utime, &to->si_utime);
345 err |= __put_user(from->si_stime, &to->si_stime);
346 err |= __put_user(from->si_status, &to->si_status);
347 default:
348 err |= __put_user(from->si_pid, &to->si_pid);
349 err |= __put_user(from->si_uid, &to->si_uid);
350 break;
351 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900352 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 break;
354 case __SI_POLL >> 16:
355 err |= __put_user(from->si_band, &to->si_band);
356 err |= __put_user(from->si_fd, &to->si_fd);
357 break;
358 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
359 case __SI_MESGQ >> 16:
360 err |= __put_user(from->si_pid, &to->si_pid);
361 err |= __put_user(from->si_uid, &to->si_uid);
362 err |= __put_user(from->si_int, &to->si_int);
363 break;
364 }
365 }
366 return err;
367}
368
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200369int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
370{
371 memset(to, 0, sizeof *to);
372
373 if (copy_from_user(to, from, 3*sizeof(int)) ||
374 copy_from_user(to->_sifields._pad,
375 from->_sifields._pad, SI_PAD_SIZE32))
376 return -EFAULT;
377
378 return 0;
379}
380
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100381asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
Ralf Baechledd02f062007-02-13 00:50:57 +0000383 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900385 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Ralf Baechledd02f062007-02-13 00:50:57 +0000387 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
389 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000390 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 goto badframe;
392
Matt Fleming8598f3c2012-02-14 11:40:52 +0000393 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900395 sig = restore_sigcontext32(&regs, &frame->sf_sc);
396 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900398 else if (sig)
399 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 /*
402 * Don't let your children do this ...
403 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 __asm__ __volatile__(
405 "move\t$29, %0\n\t"
406 "j\tsyscall_exit"
407 :/* no outputs */
408 :"r" (&regs));
409 /* Unreached */
410
411badframe:
412 force_sig(SIGSEGV, current);
413}
414
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100415asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900417 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 sigset_t set;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900419 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900421 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
423 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000424 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 goto badframe;
426
Matt Fleming8598f3c2012-02-14 11:40:52 +0000427 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900429 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
430 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900432 else if (sig)
433 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Al Viroea536ad2012-12-23 03:13:40 -0500435 if (compat_restore_altstack(&frame->rs_uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 /*
439 * Don't let your children do this ...
440 */
441 __asm__ __volatile__(
442 "move\t$29, %0\n\t"
443 "j\tsyscall_exit"
444 :/* no outputs */
445 :"r" (&regs));
446 /* Unreached */
447
448badframe:
449 force_sig(SIGSEGV, current);
450}
451
David Daneyd814c282010-02-18 16:13:05 -0800452static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
453 struct pt_regs *regs, int signr, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454{
Ralf Baechledd02f062007-02-13 00:50:57 +0000455 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 int err = 0;
457
458 frame = get_sigframe(ka, regs, sizeof(*frame));
459 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
460 goto give_sigsegv;
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000463 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (err)
466 goto give_sigsegv;
467
468 /*
469 * Arguments to signal handler:
470 *
471 * a0 = signal number
472 * a1 = 0 (should be cause)
473 * a2 = pointer to struct sigcontext
474 *
475 * $25 and c0_epc point to the signal handler, $29 points to the
476 * struct sigframe.
477 */
478 regs->regs[ 4] = signr;
479 regs->regs[ 5] = 0;
480 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
481 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800482 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
484
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100485 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100487 frame, regs->cp0_epc, regs->regs[31]);
488
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000489 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491give_sigsegv:
492 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000493 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
David Daneyd814c282010-02-18 16:13:05 -0800496static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
497 struct pt_regs *regs, int signr, sigset_t *set,
498 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900500 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 frame = get_sigframe(ka, regs, sizeof(*frame));
504 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
505 goto give_sigsegv;
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
508 err |= copy_siginfo_to_user32(&frame->rs_info, info);
509
510 /* Create the ucontext. */
511 err |= __put_user(0, &frame->rs_uc.uc_flags);
512 err |= __put_user(0, &frame->rs_uc.uc_link);
Al Viroea536ad2012-12-23 03:13:40 -0500513 err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000515 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517 if (err)
518 goto give_sigsegv;
519
520 /*
521 * Arguments to signal handler:
522 *
523 * a0 = signal number
524 * a1 = 0 (should be cause)
525 * a2 = pointer to ucontext
526 *
527 * $25 and c0_epc point to the signal handler, $29 points to
528 * the struct rt_sigframe32.
529 */
530 regs->regs[ 4] = signr;
531 regs->regs[ 5] = (unsigned long) &frame->rs_info;
532 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
533 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800534 regs->regs[31] = (unsigned long) sig_return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
536
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100537 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100539 frame, regs->cp0_epc, regs->regs[31]);
540
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000541 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543give_sigsegv:
544 force_sigsegv(signr, current);
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000545 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000548/*
549 * o32 compatibility on 64-bit kernels, without DSP ASE
550 */
551struct mips_abi mips_abi_32 = {
552 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800553 .signal_return_offset =
554 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000555 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800556 .rt_signal_return_offset =
557 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000558 .restart = __NR_O32_restart_syscall
559};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Ralf Baechle137f6f32009-11-24 19:35:41 +0000561static int signal32_init(void)
562{
563 if (cpu_has_fpu) {
564 save_fp_context32 = _save_fp_context32;
565 restore_fp_context32 = _restore_fp_context32;
566 } else {
567 save_fp_context32 = fpu_emulator_save_context32;
568 restore_fp_context32 = fpu_emulator_restore_context32;
569 }
570
571 return 0;
572}
573
574arch_initcall(signal32_init);