blob: 3c9a6f7dcdce81662d31d59a2bcce6cc425b3bca [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Paul Mundta23ba432007-11-28 20:19:38 +09002 * arch/sh/kernel/signal_64.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 2000, 2001 Paolo Alberelli
Paul Mundt6ac03432008-12-10 19:26:44 +09005 * Copyright (C) 2003 - 2008 Paul Mundt
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Copyright (C) 2004 Richard Curnow
7 *
Paul Mundta23ba432007-11-28 20:19:38 +09008 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12#include <linux/rwsem.h>
13#include <linux/sched.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/kernel.h>
17#include <linux/signal.h>
18#include <linux/errno.h>
19#include <linux/wait.h>
20#include <linux/personality.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080021#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/ptrace.h>
23#include <linux/unistd.h>
24#include <linux/stddef.h>
Paul Mundtab99c732008-07-30 19:55:30 +090025#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/ucontext.h>
27#include <asm/uaccess.h>
28#include <asm/pgtable.h>
Paul Mundtf7a7b152007-11-10 20:07:57 +090029#include <asm/cacheflush.h>
Adrian Bunk50387b32008-04-13 21:15:38 +030030#include <asm/fpu.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#define REG_RET 9
33#define REG_ARG1 2
34#define REG_ARG2 3
35#define REG_ARG3 4
36#define REG_SP 15
37#define REG_PR 18
38#define REF_REG_RET regs->regs[REG_RET]
39#define REF_REG_SP regs->regs[REG_SP]
40#define DEREF_REG_PR regs->regs[REG_PR]
41
42#define DEBUG_SIG 0
43
44#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
45
Paul Mundt6ac03432008-12-10 19:26:44 +090046static int
Paul Mundt8a80a5e2008-09-17 23:14:36 +090047handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
48 sigset_t *oldset, struct pt_regs * regs);
49
Paul Mundt94e2fb32008-12-10 19:46:18 +090050static inline void
51handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
52{
53 /* If we're not from a syscall, bail out */
54 if (regs->syscall_nr < 0)
55 return;
56
57 /* check for system call restart.. */
58 switch (regs->regs[REG_RET]) {
59 case -ERESTART_RESTARTBLOCK:
60 case -ERESTARTNOHAND:
61 no_system_call_restart:
62 regs->regs[REG_RET] = -EINTR;
Paul Mundt94e2fb32008-12-10 19:46:18 +090063 break;
64
65 case -ERESTARTSYS:
66 if (!(sa->sa_flags & SA_RESTART))
67 goto no_system_call_restart;
68 /* fallthrough */
69 case -ERESTARTNOINTR:
70 /* Decode syscall # */
71 regs->regs[REG_RET] = regs->syscall_nr;
72 regs->pc -= 4;
73 break;
74 }
75}
76
Paul Mundtab99c732008-07-30 19:55:30 +090077/*
78 * Note that 'init' is a special process: it doesn't get signals it doesn't
79 * want to handle. Thus you cannot kill init even with a SIGKILL even by
80 * mistake.
81 *
82 * Note that we go through the signals twice: once to check the signals that
83 * the kernel can handle, and then we build all the user-level signal handling
84 * stack-frames in one go after that.
85 */
86static int do_signal(struct pt_regs *regs, sigset_t *oldset)
87{
88 siginfo_t info;
89 int signr;
90 struct k_sigaction ka;
91
92 /*
93 * We want the common case to go fast, which
94 * is why we may in certain cases get here from
95 * kernel mode. Just return without doing anything
96 * if so.
97 */
98 if (!user_mode(regs))
99 return 1;
100
Paul Mundt56bfc422009-10-14 16:05:42 +0900101 if (current_thread_info()->status & TS_RESTORE_SIGMASK)
Paul Mundtab99c732008-07-30 19:55:30 +0900102 oldset = &current->saved_sigmask;
103 else if (!oldset)
104 oldset = &current->blocked;
105
106 signr = get_signal_to_deliver(&info, &ka, regs, 0);
Paul Mundtab99c732008-07-30 19:55:30 +0900107 if (signr > 0) {
Paul Mundt03f07872009-01-29 11:21:38 +0900108 handle_syscall_restart(regs, &ka.sa);
Paul Mundt94e2fb32008-12-10 19:46:18 +0900109
Paul Mundtab99c732008-07-30 19:55:30 +0900110 /* Whee! Actually deliver the signal. */
Paul Mundt6ac03432008-12-10 19:26:44 +0900111 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
112 /*
113 * If a signal was successfully delivered, the
114 * saved sigmask is in its frame, and we can
Paul Mundt56bfc422009-10-14 16:05:42 +0900115 * clear the TS_RESTORE_SIGMASK flag.
Paul Mundt6ac03432008-12-10 19:26:44 +0900116 */
Paul Mundt56bfc422009-10-14 16:05:42 +0900117 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
Paul Mundt4b505db2010-02-15 14:17:45 +0900118
119 tracehook_signal_handler(signr, &info, &ka, regs,
120 test_thread_flag(TIF_SINGLESTEP));
Paul Mundt6ac03432008-12-10 19:26:44 +0900121 return 1;
122 }
Paul Mundtab99c732008-07-30 19:55:30 +0900123 }
124
Paul Mundtab99c732008-07-30 19:55:30 +0900125 /* Did we come from a system call? */
126 if (regs->syscall_nr >= 0) {
127 /* Restart the system call - no handlers present */
128 switch (regs->regs[REG_RET]) {
129 case -ERESTARTNOHAND:
130 case -ERESTARTSYS:
131 case -ERESTARTNOINTR:
132 /* Decode Syscall # */
133 regs->regs[REG_RET] = regs->syscall_nr;
134 regs->pc -= 4;
135 break;
136
137 case -ERESTART_RESTARTBLOCK:
138 regs->regs[REG_RET] = __NR_restart_syscall;
139 regs->pc -= 4;
140 break;
141 }
142 }
143
144 /* No signal to deliver -- put the saved sigmask back */
Paul Mundt56bfc422009-10-14 16:05:42 +0900145 if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
146 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
Paul Mundtab99c732008-07-30 19:55:30 +0900147 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
148 }
149
150 return 0;
151}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153/*
154 * Atomically swap in the new signal mask, and wait for a signal.
155 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156asmlinkage int
157sys_sigsuspend(old_sigset_t mask,
158 unsigned long r3, unsigned long r4, unsigned long r5,
159 unsigned long r6, unsigned long r7,
160 struct pt_regs * regs)
161{
Matt Fleming5e047fa2012-03-28 15:16:32 -0700162 sigset_t saveset, blocked;
163
164 saveset = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 mask &= _BLOCKABLE;
Matt Fleming5e047fa2012-03-28 15:16:32 -0700167 siginitset(&blocked, mask);
168 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170 REF_REG_RET = -EINTR;
171 while (1) {
172 current->state = TASK_INTERRUPTIBLE;
173 schedule();
Paul Mundt56bfc422009-10-14 16:05:42 +0900174 set_restore_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 regs->pc += 4; /* because sys_sigreturn decrements the pc */
176 if (do_signal(regs, &saveset)) {
177 /* pc now points at signal handler. Need to decrement
178 it because entry.S will increment it. */
179 regs->pc -= 4;
180 return -EINTR;
181 }
182 }
183}
184
185asmlinkage int
186sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
187 unsigned long r4, unsigned long r5, unsigned long r6,
188 unsigned long r7,
189 struct pt_regs * regs)
190{
191 sigset_t saveset, newset;
192
193 /* XXX: Don't preclude handling different sized sigset_t's. */
194 if (sigsetsize != sizeof(sigset_t))
195 return -EINVAL;
196
197 if (copy_from_user(&newset, unewset, sizeof(newset)))
198 return -EFAULT;
199 sigdelsetmask(&newset, ~_BLOCKABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 saveset = current->blocked;
Matt Fleming5e047fa2012-03-28 15:16:32 -0700201 set_current_blocked(&newset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 REF_REG_RET = -EINTR;
204 while (1) {
205 current->state = TASK_INTERRUPTIBLE;
206 schedule();
207 regs->pc += 4; /* because sys_sigreturn decrements the pc */
208 if (do_signal(regs, &saveset)) {
209 /* pc now points at signal handler. Need to decrement
210 it because entry.S will increment it. */
211 regs->pc -= 4;
212 return -EINTR;
213 }
214 }
215}
216
217asmlinkage int
218sys_sigaction(int sig, const struct old_sigaction __user *act,
219 struct old_sigaction __user *oact)
220{
221 struct k_sigaction new_ka, old_ka;
222 int ret;
223
224 if (act) {
225 old_sigset_t mask;
226 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
227 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
228 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
229 return -EFAULT;
230 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
231 __get_user(mask, &act->sa_mask);
232 siginitset(&new_ka.sa.sa_mask, mask);
233 }
234
235 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
236
237 if (!ret && oact) {
238 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
239 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
240 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
241 return -EFAULT;
242 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
243 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
244 }
245
246 return ret;
247}
248
249asmlinkage int
250sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
251 unsigned long r4, unsigned long r5, unsigned long r6,
252 unsigned long r7,
253 struct pt_regs * regs)
254{
255 return do_sigaltstack(uss, uoss, REF_REG_SP);
256}
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258/*
259 * Do a signal return; undo the signal stack.
260 */
Paul Mundt94e2fb32008-12-10 19:46:18 +0900261struct sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 struct sigcontext sc;
263 unsigned long extramask[_NSIG_WORDS-1];
264 long long retcode[2];
265};
266
Paul Mundt94e2fb32008-12-10 19:46:18 +0900267struct rt_sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 struct siginfo __user *pinfo;
269 void *puc;
270 struct siginfo info;
271 struct ucontext uc;
272 long long retcode[2];
273};
274
275#ifdef CONFIG_SH_FPU
276static inline int
277restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
278{
279 int err = 0;
280 int fpvalid;
281
282 err |= __get_user (fpvalid, &sc->sc_fpvalid);
283 conditional_used_math(fpvalid);
284 if (! fpvalid)
285 return err;
286
287 if (current == last_task_used_math) {
288 last_task_used_math = NULL;
289 regs->sr |= SR_FD;
290 }
291
Paul Mundt3ef29322010-01-19 15:40:03 +0900292 err |= __copy_from_user(&current->thread.xstate->hardfpu, &sc->sc_fpregs[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 (sizeof(long long) * 32) + (sizeof(int) * 1));
294
295 return err;
296}
297
298static inline int
299setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
300{
301 int err = 0;
302 int fpvalid;
303
304 fpvalid = !!used_math();
305 err |= __put_user(fpvalid, &sc->sc_fpvalid);
306 if (! fpvalid)
307 return err;
308
309 if (current == last_task_used_math) {
Paul Mundt600ee242007-11-19 19:13:38 +0900310 enable_fpu();
Matt Fleming61cc7b02009-12-14 20:12:04 +0000311 save_fpu(current);
Paul Mundt600ee242007-11-19 19:13:38 +0900312 disable_fpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 last_task_used_math = NULL;
314 regs->sr |= SR_FD;
315 }
316
Paul Mundt3ef29322010-01-19 15:40:03 +0900317 err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.xstate->hardfpu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 (sizeof(long long) * 32) + (sizeof(int) * 1));
319 clear_used_math();
320
321 return err;
322}
323#else
324static inline int
325restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900326{
327 return 0;
328}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static inline int
330setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900331{
332 return 0;
333}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334#endif
335
336static int
337restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
338{
339 unsigned int err = 0;
340 unsigned long long current_sr, new_sr;
341#define SR_MASK 0xffff8cfd
342
343#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
344
345 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
346 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
347 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
348 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
349 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
350 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
351 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
352 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
353 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
354 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
355 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
356 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
357 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
358 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
359 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
360 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
361 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
362 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
363
364 /* Prevent the signal handler manipulating SR in a way that can
365 crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
366 modified */
367 current_sr = regs->sr;
368 err |= __get_user(new_sr, &sc->sc_sr);
369 regs->sr &= SR_MASK;
370 regs->sr |= (new_sr & ~SR_MASK);
371
372 COPY(pc);
373
374#undef COPY
375
376 /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
377 * has been restored above.) */
378 err |= restore_sigcontext_fpu(regs, sc);
379
380 regs->syscall_nr = -1; /* disable syscall checks */
381 err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
382 return err;
383}
384
385asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
386 unsigned long r4, unsigned long r5,
387 unsigned long r6, unsigned long r7,
388 struct pt_regs * regs)
389{
390 struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
391 sigset_t set;
392 long long ret;
393
Paul Mundt1bec1572008-09-24 14:37:35 +0900394 /* Always make any pending restarted system calls return -EINTR */
395 current_thread_info()->restart_block.fn = do_no_restart_syscall;
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
398 goto badframe;
399
400 if (__get_user(set.sig[0], &frame->sc.oldmask)
401 || (_NSIG_WORDS > 1
402 && __copy_from_user(&set.sig[1], &frame->extramask,
403 sizeof(frame->extramask))))
404 goto badframe;
405
406 sigdelsetmask(&set, ~_BLOCKABLE);
Matt Fleming5e047fa2012-03-28 15:16:32 -0700407 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 if (restore_sigcontext(regs, &frame->sc, &ret))
410 goto badframe;
411 regs->pc -= 4;
412
413 return (int) ret;
414
415badframe:
416 force_sig(SIGSEGV, current);
417 return 0;
418}
419
420asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
421 unsigned long r4, unsigned long r5,
422 unsigned long r6, unsigned long r7,
423 struct pt_regs * regs)
424{
425 struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
426 sigset_t set;
427 stack_t __user st;
428 long long ret;
429
Paul Mundt1bec1572008-09-24 14:37:35 +0900430 /* Always make any pending restarted system calls return -EINTR */
431 current_thread_info()->restart_block.fn = do_no_restart_syscall;
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
434 goto badframe;
435
436 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
437 goto badframe;
438
439 sigdelsetmask(&set, ~_BLOCKABLE);
Matt Fleming5e047fa2012-03-28 15:16:32 -0700440 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
443 goto badframe;
444 regs->pc -= 4;
445
446 if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
447 goto badframe;
448 /* It is more difficult to avoid calling this function than to
449 call it and ignore errors. */
450 do_sigaltstack(&st, NULL, REF_REG_SP);
451
452 return (int) ret;
453
454badframe:
455 force_sig(SIGSEGV, current);
456 return 0;
457}
458
459/*
460 * Set up a signal frame.
461 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462static int
463setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
464 unsigned long mask)
465{
466 int err = 0;
467
468 /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
469 err |= setup_sigcontext_fpu(regs, sc);
470
471#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
472
473 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
474 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
475 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
476 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
477 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
478 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
479 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
480 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
481 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
482 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
483 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
484 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
485 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
486 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
487 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
488 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
489 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
490 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
491 COPY(sr); COPY(pc);
492
493#undef COPY
494
495 err |= __put_user(mask, &sc->oldmask);
496
497 return err;
498}
499
500/*
501 * Determine which stack to use..
502 */
503static inline void __user *
504get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
505{
Laurent MEYERd09042d2006-06-23 02:05:36 -0700506 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 sp = current->sas_ss_sp + current->sas_ss_size;
508
509 return (void __user *)((sp - frame_size) & -8ul);
510}
511
512void sa_default_restorer(void); /* See comments below */
513void sa_default_rt_restorer(void); /* See comments below */
514
Paul Mundt6ac03432008-12-10 19:26:44 +0900515static int setup_frame(int sig, struct k_sigaction *ka,
516 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 struct sigframe __user *frame;
519 int err = 0;
520 int signal;
521
522 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
523
524 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
525 goto give_sigsegv;
526
527 signal = current_thread_info()->exec_domain
528 && current_thread_info()->exec_domain->signal_invmap
529 && sig < 32
530 ? current_thread_info()->exec_domain->signal_invmap[sig]
531 : sig;
532
533 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
534
535 /* Give up earlier as i386, in case */
536 if (err)
537 goto give_sigsegv;
538
539 if (_NSIG_WORDS > 1) {
540 err |= __copy_to_user(frame->extramask, &set->sig[1],
541 sizeof(frame->extramask)); }
542
543 /* Give up earlier as i386, in case */
544 if (err)
545 goto give_sigsegv;
546
547 /* Set up to return from userspace. If provided, use a stub
548 already in userspace. */
549 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 /*
551 * On SH5 all edited pointers are subject to NEFF
552 */
Paul Mundtc7914832009-08-04 17:14:39 +0900553 DEREF_REG_PR = neff_sign_extend((unsigned long)
554 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 } else {
556 /*
557 * Different approach on SH5.
558 * . Endianness independent asm code gets placed in entry.S .
559 * This is limited to four ASM instructions corresponding
560 * to two long longs in size.
561 * . err checking is done on the else branch only
562 * . flush_icache_range() is called upon __put_user() only
563 * . all edited pointers are subject to NEFF
564 * . being code, linker turns ShMedia bit on, always
565 * dereference index -1.
566 */
Paul Mundtc7914832009-08-04 17:14:39 +0900567 DEREF_REG_PR = neff_sign_extend((unsigned long)
568 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900571 (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 goto give_sigsegv;
573
574 /* Cohere the trampoline with the I-cache. */
Paul Mundtb6138812007-11-11 15:53:51 +0900575 flush_cache_sigtramp(DEREF_REG_PR-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
577
578 /*
579 * Set up registers for signal handler.
580 * All edited pointers are subject to NEFF.
581 */
Paul Mundtc7914832009-08-04 17:14:39 +0900582 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
584
585 /* FIXME:
586 The glibc profiling support for SH-5 needs to be passed a sigcontext
587 so it can retrieve the PC. At some point during 2003 the glibc
588 support was changed to receive the sigcontext through the 2nd
589 argument, but there are still versions of libc.so in use that use
590 the 3rd argument. Until libc.so is stabilised, pass the sigcontext
591 through both 2nd and 3rd arguments.
592 */
593
594 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
595 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
596
Paul Mundtc7914832009-08-04 17:14:39 +0900597 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 set_fs(USER_DS);
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 /* Broken %016Lx */
Paul Mundt6ac03432008-12-10 19:26:44 +0900602 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
603 signal, current->comm, current->pid, frame,
604 regs->pc >> 32, regs->pc & 0xffffffff,
605 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Paul Mundt6ac03432008-12-10 19:26:44 +0900607 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609give_sigsegv:
610 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900611 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612}
613
Paul Mundt6ac03432008-12-10 19:26:44 +0900614static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
615 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 struct rt_sigframe __user *frame;
618 int err = 0;
619 int signal;
620
621 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
622
623 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
624 goto give_sigsegv;
625
626 signal = current_thread_info()->exec_domain
627 && current_thread_info()->exec_domain->signal_invmap
628 && sig < 32
629 ? current_thread_info()->exec_domain->signal_invmap[sig]
630 : sig;
631
632 err |= __put_user(&frame->info, &frame->pinfo);
633 err |= __put_user(&frame->uc, &frame->puc);
634 err |= copy_siginfo_to_user(&frame->info, info);
635
636 /* Give up earlier as i386, in case */
637 if (err)
638 goto give_sigsegv;
639
640 /* Create the ucontext. */
641 err |= __put_user(0, &frame->uc.uc_flags);
642 err |= __put_user(0, &frame->uc.uc_link);
643 err |= __put_user((void *)current->sas_ss_sp,
644 &frame->uc.uc_stack.ss_sp);
645 err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
646 &frame->uc.uc_stack.ss_flags);
647 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
648 err |= setup_sigcontext(&frame->uc.uc_mcontext,
649 regs, set->sig[0]);
650 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
651
652 /* Give up earlier as i386, in case */
653 if (err)
654 goto give_sigsegv;
655
656 /* Set up to return from userspace. If provided, use a stub
657 already in userspace. */
658 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 /*
660 * On SH5 all edited pointers are subject to NEFF
661 */
Paul Mundtc7914832009-08-04 17:14:39 +0900662 DEREF_REG_PR = neff_sign_extend((unsigned long)
663 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 } else {
665 /*
666 * Different approach on SH5.
667 * . Endianness independent asm code gets placed in entry.S .
668 * This is limited to four ASM instructions corresponding
669 * to two long longs in size.
670 * . err checking is done on the else branch only
671 * . flush_icache_range() is called upon __put_user() only
672 * . all edited pointers are subject to NEFF
673 * . being code, linker turns ShMedia bit on, always
674 * dereference index -1.
675 */
Paul Mundtc7914832009-08-04 17:14:39 +0900676 DEREF_REG_PR = neff_sign_extend((unsigned long)
677 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900680 (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 goto give_sigsegv;
682
Paul Mundtc7914832009-08-04 17:14:39 +0900683 /* Cohere the trampoline with the I-cache. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
685 }
686
687 /*
688 * Set up registers for signal handler.
689 * All edited pointers are subject to NEFF.
690 */
Paul Mundtc7914832009-08-04 17:14:39 +0900691 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
693 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
694 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
Paul Mundtc7914832009-08-04 17:14:39 +0900695 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 set_fs(USER_DS);
698
Paul Mundt6ac03432008-12-10 19:26:44 +0900699 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
700 signal, current->comm, current->pid, frame,
701 regs->pc >> 32, regs->pc & 0xffffffff,
702 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Paul Mundt6ac03432008-12-10 19:26:44 +0900704 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706give_sigsegv:
707 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900708 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
711/*
712 * OK, we're invoking a handler
713 */
Paul Mundt6ac03432008-12-10 19:26:44 +0900714static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
716 sigset_t *oldset, struct pt_regs * regs)
717{
Paul Mundt6ac03432008-12-10 19:26:44 +0900718 int ret;
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 /* Set up the stack frame */
721 if (ka->sa.sa_flags & SA_SIGINFO)
Paul Mundt6ac03432008-12-10 19:26:44 +0900722 ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 else
Paul Mundt6ac03432008-12-10 19:26:44 +0900724 ret = setup_frame(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Matt Fleming5e047fa2012-03-28 15:16:32 -0700726 if (ret == 0)
727 block_sigmask(ka, sig);
Paul Mundt6ac03432008-12-10 19:26:44 +0900728
729 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730}
731
Paul Mundtab99c732008-07-30 19:55:30 +0900732asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733{
Paul Mundtab99c732008-07-30 19:55:30 +0900734 if (thread_info_flags & _TIF_SIGPENDING)
735 do_signal(regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Paul Mundtab99c732008-07-30 19:55:30 +0900737 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
738 clear_thread_flag(TIF_NOTIFY_RESUME);
739 tracehook_notify_resume(regs);
David Howellsee18d642009-09-02 09:14:21 +0100740 if (current->replacement_session_keyring)
741 key_replace_session_keyring();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}