blob: 19a7705f2a015ef4b38e1cd0a16eb22c2a2d3ca3 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/*
46 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
47 */
Ralf Baechle70342282013-01-22 12:59:30 +010048#define __NR_O32_restart_syscall 4253
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Linus Torvalds1da177e2005-04-16 15:20:36 -070050/* 32-bit compatibility types */
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052typedef unsigned int __sighandler32_t;
53typedef void (*vfptr_t)(void);
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055struct ucontext32 {
Ralf Baechle70342282013-01-22 12:59:30 +010056 u32 uc_flags;
57 s32 uc_link;
Al Viroea536ad2012-12-23 03:13:40 -050058 compat_stack_t uc_stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 struct sigcontext32 uc_mcontext;
Ralf Baechle70342282013-01-22 12:59:30 +010060 compat_sigset_t uc_sigmask; /* mask last for extensibility */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061};
62
Ralf Baechledd02f062007-02-13 00:50:57 +000063struct sigframe32 {
64 u32 sf_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080065 u32 sf_pad[2]; /* Was: signal trampoline */
Ralf Baechledd02f062007-02-13 00:50:57 +000066 struct sigcontext32 sf_sc;
Atsushi Nemoto755f21b2007-02-14 14:41:01 +090067 compat_sigset_t sf_mask;
Ralf Baechledd02f062007-02-13 00:50:57 +000068};
69
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010070struct rt_sigframe32 {
71 u32 rs_ass[4]; /* argument save space for o32 */
David Daneyd814c282010-02-18 16:13:05 -080072 u32 rs_pad[2]; /* Was: signal trampoline */
Franck Bui-Huuc0b9bae2007-02-05 15:24:21 +010073 compat_siginfo_t rs_info;
74 struct ucontext32 rs_uc;
75};
76
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +010077/*
Paul Burtonb2ead522014-01-27 15:23:02 +000078 * Thread saved context copy to/from a signal context presumed to be on the
79 * user stack, and therefore accessed with appropriate macros from uaccess.h.
80 */
81static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc)
82{
83 int i;
84 int err = 0;
85 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
86
Paul Burton6bbfd652014-01-27 15:23:04 +000087 for (i = 0; i < NUM_FPU_REGS; i += inc) {
Paul Burtonb2ead522014-01-27 15:23:02 +000088 err |=
89 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
90 &sc->sc_fpregs[i]);
91 }
92 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
93
94 return err;
95}
96
97static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc)
98{
99 int i;
100 int err = 0;
101 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
102 u64 fpr_val;
103
Paul Burton6bbfd652014-01-27 15:23:04 +0000104 for (i = 0; i < NUM_FPU_REGS; i += inc) {
Paul Burtonb2ead522014-01-27 15:23:02 +0000105 err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
106 set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
107 }
108 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
109
110 return err;
111}
112
113/*
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100114 * sigcontext handlers
115 */
Paul Burton16f77de2014-06-18 15:00:46 +0100116static int protected_save_fp_context32(struct sigcontext32 __user *sc)
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900117{
118 int err;
119 while (1) {
120 lock_fpu_owner();
Paul Burtonff3aa5f2014-01-27 15:23:03 +0000121 if (is_fpu_owner()) {
122 err = save_fp_context32(sc);
123 unlock_fpu_owner();
124 } else {
125 unlock_fpu_owner();
126 err = copy_fp_to_sigcontext32(sc);
127 }
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900128 if (likely(!err))
129 break;
130 /* touch the sigcontext and try again */
131 err = __put_user(0, &sc->sc_fpregs[0]) |
132 __put_user(0, &sc->sc_fpregs[31]) |
133 __put_user(0, &sc->sc_fpc_csr);
134 if (err)
135 break; /* really bad sigcontext */
136 }
137 return err;
138}
139
Paul Burton16f77de2014-06-18 15:00:46 +0100140static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900141{
David Daneyc726b822011-01-24 14:51:34 -0800142 int err, tmp __maybe_unused;
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900143 while (1) {
144 lock_fpu_owner();
Paul Burtonff3aa5f2014-01-27 15:23:03 +0000145 if (is_fpu_owner()) {
146 err = restore_fp_context32(sc);
147 unlock_fpu_owner();
148 } else {
149 unlock_fpu_owner();
150 err = copy_fp_from_sigcontext32(sc);
151 }
Atsushi Nemotofaea6232007-04-16 23:19:44 +0900152 if (likely(!err))
153 break;
154 /* touch the sigcontext and try again */
155 err = __get_user(tmp, &sc->sc_fpregs[0]) |
156 __get_user(tmp, &sc->sc_fpregs[31]) |
157 __get_user(tmp, &sc->sc_fpc_csr);
158 if (err)
159 break; /* really bad sigcontext */
160 }
161 return err;
162}
163
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100164static int setup_sigcontext32(struct pt_regs *regs,
165 struct sigcontext32 __user *sc)
166{
167 int err = 0;
168 int i;
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900169 u32 used_math;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100170
171 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100172
173 err |= __put_user(0, &sc->sc_regs[0]);
174 for (i = 1; i < 32; i++)
175 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
176
177 err |= __put_user(regs->hi, &sc->sc_mdhi);
178 err |= __put_user(regs->lo, &sc->sc_mdlo);
179 if (cpu_has_dsp) {
180 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
181 err |= __put_user(mfhi1(), &sc->sc_hi1);
182 err |= __put_user(mflo1(), &sc->sc_lo1);
183 err |= __put_user(mfhi2(), &sc->sc_hi2);
184 err |= __put_user(mflo2(), &sc->sc_lo2);
185 err |= __put_user(mfhi3(), &sc->sc_hi3);
186 err |= __put_user(mflo3(), &sc->sc_lo3);
187 }
188
Paul Burton16f77de2014-06-18 15:00:46 +0100189 used_math = !!used_math();
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900190 err |= __put_user(used_math, &sc->sc_used_math);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100191
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900192 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100193 /*
194 * Save FPU state to signal context. Signal handler
195 * will "inherit" current FPU state.
196 */
Paul Burton16f77de2014-06-18 15:00:46 +0100197 err |= protected_save_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100198 }
199 return err;
200}
201
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900202static int
Paul Burton16f77de2014-06-18 15:00:46 +0100203check_and_restore_fp_context32(struct sigcontext32 __user *sc)
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900204{
205 int err, sig;
206
207 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
208 if (err > 0)
209 err = 0;
Paul Burton16f77de2014-06-18 15:00:46 +0100210 err |= protected_restore_fp_context32(sc);
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900211 return err ?: sig;
212}
213
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100214static int restore_sigcontext32(struct pt_regs *regs,
215 struct sigcontext32 __user *sc)
216{
217 u32 used_math;
218 int err = 0;
219 s32 treg;
220 int i;
221
222 /* Always make any pending restarted system calls return -EINTR */
Andy Lutomirskif56141e2015-02-12 15:01:14 -0800223 current->restart_block.fn = do_no_restart_syscall;
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100224
225 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
226 err |= __get_user(regs->hi, &sc->sc_mdhi);
227 err |= __get_user(regs->lo, &sc->sc_mdlo);
228 if (cpu_has_dsp) {
229 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
230 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
231 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
232 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
233 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
234 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
235 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
236 }
237
238 for (i = 1; i < 32; i++)
239 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
240
241 err |= __get_user(used_math, &sc->sc_used_math);
242 conditional_used_math(used_math);
243
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900244 if (used_math) {
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100245 /* restore fpu context if we have used it before */
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900246 if (!err)
Paul Burton16f77de2014-06-18 15:00:46 +0100247 err = check_and_restore_fp_context32(sc);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100248 } else {
Paul Burton16f77de2014-06-18 15:00:46 +0100249 /* signal handler may have used FPU. Give it up. */
Atsushi Nemoto53dc8022007-03-10 01:07:45 +0900250 lose_fpu(0);
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100251 }
252
Franck Bui-Huu9432a9b2007-02-05 15:24:25 +0100253 return err;
254}
255
256/*
257 *
258 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259extern void __put_sigset_unknown_nsig(void);
260extern void __get_sigset_unknown_nsig(void);
261
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900262static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
264 int err = 0;
265
266 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
267 return -EFAULT;
268
269 switch (_NSIG_WORDS) {
270 default:
271 __put_sigset_unknown_nsig();
272 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100273 err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]);
274 err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100276 err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]);
277 err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 }
279
280 return err;
281}
282
Atsushi Nemoto9c6031c2006-02-19 23:46:44 +0900283static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 int err = 0;
286 unsigned long sig[4];
287
288 if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
289 return -EFAULT;
290
291 switch (_NSIG_WORDS) {
292 default:
293 __get_sigset_unknown_nsig();
294 case 2:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100295 err |= __get_user(sig[3], &ubuf->sig[3]);
296 err |= __get_user(sig[2], &ubuf->sig[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 kbuf->sig[1] = sig[2] | (sig[3] << 32);
298 case 1:
Ralf Baechle49a89ef2007-10-11 23:46:15 +0100299 err |= __get_user(sig[1], &ubuf->sig[1]);
300 err |= __get_user(sig[0], &ubuf->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 kbuf->sig[0] = sig[0] | (sig[1] << 32);
302 }
303
304 return err;
305}
306
307/*
308 * Atomically swap in the new signal mask, and wait for a signal.
309 */
310
Al Viro1910f4a2012-12-25 16:25:18 -0500311asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Al Viro1910f4a2012-12-25 16:25:18 -0500313 return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315
Al Viroaa584802012-12-25 18:55:27 -0500316SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
317 struct compat_sigaction __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 struct k_sigaction new_ka, old_ka;
320 int ret;
321 int err = 0;
322
323 if (act) {
324 old_sigset_t mask;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000325 s32 handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
328 return -EFAULT;
Ralf Baechle77c728c2005-03-04 19:36:51 +0000329 err |= __get_user(handler, &act->sa_handler);
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900330 new_ka.sa.sa_handler = (void __user *)(s64)handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
332 err |= __get_user(mask, &act->sa_mask.sig[0]);
333 if (err)
334 return -EFAULT;
335
336 siginitset(&new_ka.sa.sa_mask, mask);
337 }
338
339 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
340
341 if (!ret && oact) {
342 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
Martin Michlmayr62549442006-02-18 20:06:32 +0000343 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
345 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
Ralf Baechle70342282013-01-22 12:59:30 +0100346 &oact->sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
Martin Michlmayr62549442006-02-18 20:06:32 +0000348 err |= __put_user(0, &oact->sa_mask.sig[1]);
349 err |= __put_user(0, &oact->sa_mask.sig[2]);
350 err |= __put_user(0, &oact->sa_mask.sig[3]);
351 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return -EFAULT;
353 }
354
355 return ret;
356}
357
Al Viroce395962013-10-13 17:23:53 -0400358int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
360 int err;
361
362 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
363 return -EFAULT;
364
365 /* If you change siginfo_t structure, please be sure
366 this code is fixed accordingly.
367 It should never copy any pad contained in the structure
368 to avoid security leaks, but must copy the generic
369 3 ints plus the relevant union member.
370 This routine must convert siginfo from 64bit to 32bit as well
371 at the same time. */
372 err = __put_user(from->si_signo, &to->si_signo);
373 err |= __put_user(from->si_errno, &to->si_errno);
374 err |= __put_user((short)from->si_code, &to->si_code);
375 if (from->si_code < 0)
376 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
377 else {
378 switch (from->si_code >> 16) {
Ralf Baechlea9820992005-02-16 21:24:16 +0000379 case __SI_TIMER >> 16:
380 err |= __put_user(from->si_tid, &to->si_tid);
381 err |= __put_user(from->si_overrun, &to->si_overrun);
382 err |= __put_user(from->si_int, &to->si_int);
383 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 case __SI_CHLD >> 16:
385 err |= __put_user(from->si_utime, &to->si_utime);
386 err |= __put_user(from->si_stime, &to->si_stime);
387 err |= __put_user(from->si_status, &to->si_status);
388 default:
389 err |= __put_user(from->si_pid, &to->si_pid);
390 err |= __put_user(from->si_uid, &to->si_uid);
391 break;
392 case __SI_FAULT >> 16:
Atsushi Nemoto5665a0a2006-02-02 01:26:34 +0900393 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 break;
395 case __SI_POLL >> 16:
396 err |= __put_user(from->si_band, &to->si_band);
397 err |= __put_user(from->si_fd, &to->si_fd);
398 break;
399 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
400 case __SI_MESGQ >> 16:
401 err |= __put_user(from->si_pid, &to->si_pid);
402 err |= __put_user(from->si_uid, &to->si_uid);
403 err |= __put_user(from->si_int, &to->si_int);
404 break;
405 }
406 }
407 return err;
408}
409
Thomas Bogendoerfer5d9a76c2008-08-17 16:49:25 +0200410int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
411{
412 memset(to, 0, sizeof *to);
413
414 if (copy_from_user(to, from, 3*sizeof(int)) ||
415 copy_from_user(to->_sifields._pad,
416 from->_sifields._pad, SI_PAD_SIZE32))
417 return -EFAULT;
418
419 return 0;
420}
421
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100422asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
Ralf Baechledd02f062007-02-13 00:50:57 +0000424 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 sigset_t blocked;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900426 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Ralf Baechledd02f062007-02-13 00:50:57 +0000428 frame = (struct sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
430 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000431 if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 goto badframe;
433
Matt Fleming8598f3c2012-02-14 11:40:52 +0000434 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900436 sig = restore_sigcontext32(&regs, &frame->sf_sc);
437 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900439 else if (sig)
440 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 /*
443 * Don't let your children do this ...
444 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 __asm__ __volatile__(
446 "move\t$29, %0\n\t"
447 "j\tsyscall_exit"
448 :/* no outputs */
449 :"r" (&regs));
450 /* Unreached */
451
452badframe:
453 force_sig(SIGSEGV, current);
454}
455
Franck Bui-Huuf90080a2007-02-05 15:24:27 +0100456asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900458 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 sigset_t set;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900460 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900462 frame = (struct rt_sigframe32 __user *) regs.regs[29];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
464 goto badframe;
Ralf Baechle431dc802007-02-13 00:05:11 +0000465 if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 goto badframe;
467
Matt Fleming8598f3c2012-02-14 11:40:52 +0000468 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900470 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
471 if (sig < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 goto badframe;
Atsushi Nemotoc6a2f462007-03-10 01:03:48 +0900473 else if (sig)
474 force_sig(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Al Viroea536ad2012-12-23 03:13:40 -0500476 if (compat_restore_altstack(&frame->rs_uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 /*
480 * Don't let your children do this ...
481 */
482 __asm__ __volatile__(
483 "move\t$29, %0\n\t"
484 "j\tsyscall_exit"
485 :/* no outputs */
486 :"r" (&regs));
487 /* Unreached */
488
489badframe:
490 force_sig(SIGSEGV, current);
491}
492
Richard Weinberger81d103b2013-10-06 22:25:42 +0200493static int setup_frame_32(void *sig_return, struct ksignal *ksig,
494 struct pt_regs *regs, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Ralf Baechledd02f062007-02-13 00:50:57 +0000496 struct sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 int err = 0;
498
Richard Weinberger7c4f5632014-03-05 15:35:41 +0100499 frame = get_sigframe(ksig, regs, sizeof(*frame));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
Richard Weinberger81d103b2013-10-06 22:25:42 +0200501 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 err |= setup_sigcontext32(regs, &frame->sf_sc);
Ralf Baechle431dc802007-02-13 00:05:11 +0000504 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (err)
Richard Weinberger81d103b2013-10-06 22:25:42 +0200507 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 /*
510 * Arguments to signal handler:
511 *
512 * a0 = signal number
513 * a1 = 0 (should be cause)
514 * a2 = pointer to struct sigcontext
515 *
516 * $25 and c0_epc point to the signal handler, $29 points to the
517 * struct sigframe.
518 */
Richard Weinberger81d103b2013-10-06 22:25:42 +0200519 regs->regs[ 4] = ksig->sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 regs->regs[ 5] = 0;
521 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
522 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800523 regs->regs[31] = (unsigned long) sig_return;
Richard Weinberger81d103b2013-10-06 22:25:42 +0200524 regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100526 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100528 frame, regs->cp0_epc, regs->regs[31]);
529
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000530 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531}
532
Richard Weinberger81d103b2013-10-06 22:25:42 +0200533static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
534 struct pt_regs *regs, sigset_t *set)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
Atsushi Nemoto9bbf28a32006-02-01 01:41:09 +0900536 struct rt_sigframe32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Richard Weinberger7c4f5632014-03-05 15:35:41 +0100539 frame = get_sigframe(ksig, regs, sizeof(*frame));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
Richard Weinberger81d103b2013-10-06 22:25:42 +0200541 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
Richard Weinberger81d103b2013-10-06 22:25:42 +0200544 err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Ralf Baechle70342282013-01-22 12:59:30 +0100546 /* Create the ucontext. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 err |= __put_user(0, &frame->rs_uc.uc_flags);
548 err |= __put_user(0, &frame->rs_uc.uc_link);
Al Viroea536ad2012-12-23 03:13:40 -0500549 err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
Ralf Baechle431dc802007-02-13 00:05:11 +0000551 err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 if (err)
Richard Weinberger81d103b2013-10-06 22:25:42 +0200554 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 /*
557 * Arguments to signal handler:
558 *
559 * a0 = signal number
560 * a1 = 0 (should be cause)
561 * a2 = pointer to ucontext
562 *
563 * $25 and c0_epc point to the signal handler, $29 points to
564 * the struct rt_sigframe32.
565 */
Richard Weinberger81d103b2013-10-06 22:25:42 +0200566 regs->regs[ 4] = ksig->sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 regs->regs[ 5] = (unsigned long) &frame->rs_info;
568 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
569 regs->regs[29] = (unsigned long) frame;
David Daneyd814c282010-02-18 16:13:05 -0800570 regs->regs[31] = (unsigned long) sig_return;
Richard Weinberger81d103b2013-10-06 22:25:42 +0200571 regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100573 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 current->comm, current->pid,
Franck Bui-Huu722bb632007-02-05 15:24:24 +0100575 frame, regs->cp0_epc, regs->regs[31]);
576
Ralf Baechle7b3e2fc2006-02-08 12:58:41 +0000577 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578}
579
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000580/*
581 * o32 compatibility on 64-bit kernels, without DSP ASE
582 */
583struct mips_abi mips_abi_32 = {
584 .setup_frame = setup_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800585 .signal_return_offset =
586 offsetof(struct mips_vdso, o32_signal_trampoline),
Ralf Baechle70342282013-01-22 12:59:30 +0100587 .setup_rt_frame = setup_rt_frame_32,
David Daneyd814c282010-02-18 16:13:05 -0800588 .rt_signal_return_offset =
589 offsetof(struct mips_vdso, o32_rt_signal_trampoline),
Ralf Baechle151fd6a2007-02-15 11:40:37 +0000590 .restart = __NR_O32_restart_syscall
591};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Ralf Baechle137f6f32009-11-24 19:35:41 +0000593static int signal32_init(void)
594{
595 if (cpu_has_fpu) {
596 save_fp_context32 = _save_fp_context32;
597 restore_fp_context32 = _restore_fp_context32;
598 } else {
Paul Burtonb2ead522014-01-27 15:23:02 +0000599 save_fp_context32 = copy_fp_to_sigcontext32;
600 restore_fp_context32 = copy_fp_from_sigcontext32;
Ralf Baechle137f6f32009-11-24 19:35:41 +0000601 }
602
603 return 0;
604}
605
606arch_initcall(signal32_init);