blob: 6b5603fe274bdbca92a94b15331553388dc2488a [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{
162 sigset_t saveset;
163
164 mask &= _BLOCKABLE;
165 spin_lock_irq(&current->sighand->siglock);
166 saveset = current->blocked;
167 siginitset(&current->blocked, mask);
168 recalc_sigpending();
169 spin_unlock_irq(&current->sighand->siglock);
170
171 REF_REG_RET = -EINTR;
172 while (1) {
173 current->state = TASK_INTERRUPTIBLE;
174 schedule();
Paul Mundt56bfc422009-10-14 16:05:42 +0900175 set_restore_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 regs->pc += 4; /* because sys_sigreturn decrements the pc */
177 if (do_signal(regs, &saveset)) {
178 /* pc now points at signal handler. Need to decrement
179 it because entry.S will increment it. */
180 regs->pc -= 4;
181 return -EINTR;
182 }
183 }
184}
185
186asmlinkage int
187sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
188 unsigned long r4, unsigned long r5, unsigned long r6,
189 unsigned long r7,
190 struct pt_regs * regs)
191{
192 sigset_t saveset, newset;
193
194 /* XXX: Don't preclude handling different sized sigset_t's. */
195 if (sigsetsize != sizeof(sigset_t))
196 return -EINVAL;
197
198 if (copy_from_user(&newset, unewset, sizeof(newset)))
199 return -EFAULT;
200 sigdelsetmask(&newset, ~_BLOCKABLE);
201 spin_lock_irq(&current->sighand->siglock);
202 saveset = current->blocked;
203 current->blocked = newset;
204 recalc_sigpending();
205 spin_unlock_irq(&current->sighand->siglock);
206
207 REF_REG_RET = -EINTR;
208 while (1) {
209 current->state = TASK_INTERRUPTIBLE;
210 schedule();
211 regs->pc += 4; /* because sys_sigreturn decrements the pc */
212 if (do_signal(regs, &saveset)) {
213 /* pc now points at signal handler. Need to decrement
214 it because entry.S will increment it. */
215 regs->pc -= 4;
216 return -EINTR;
217 }
218 }
219}
220
221asmlinkage int
222sys_sigaction(int sig, const struct old_sigaction __user *act,
223 struct old_sigaction __user *oact)
224{
225 struct k_sigaction new_ka, old_ka;
226 int ret;
227
228 if (act) {
229 old_sigset_t mask;
230 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
231 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
232 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
233 return -EFAULT;
234 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
235 __get_user(mask, &act->sa_mask);
236 siginitset(&new_ka.sa.sa_mask, mask);
237 }
238
239 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
240
241 if (!ret && oact) {
242 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
243 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
244 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
245 return -EFAULT;
246 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
247 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
248 }
249
250 return ret;
251}
252
253asmlinkage int
254sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
255 unsigned long r4, unsigned long r5, unsigned long r6,
256 unsigned long r7,
257 struct pt_regs * regs)
258{
259 return do_sigaltstack(uss, uoss, REF_REG_SP);
260}
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262/*
263 * Do a signal return; undo the signal stack.
264 */
Paul Mundt94e2fb32008-12-10 19:46:18 +0900265struct sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 struct sigcontext sc;
267 unsigned long extramask[_NSIG_WORDS-1];
268 long long retcode[2];
269};
270
Paul Mundt94e2fb32008-12-10 19:46:18 +0900271struct rt_sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 struct siginfo __user *pinfo;
273 void *puc;
274 struct siginfo info;
275 struct ucontext uc;
276 long long retcode[2];
277};
278
279#ifdef CONFIG_SH_FPU
280static inline int
281restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
282{
283 int err = 0;
284 int fpvalid;
285
286 err |= __get_user (fpvalid, &sc->sc_fpvalid);
287 conditional_used_math(fpvalid);
288 if (! fpvalid)
289 return err;
290
291 if (current == last_task_used_math) {
292 last_task_used_math = NULL;
293 regs->sr |= SR_FD;
294 }
295
Paul Mundt3ef29322010-01-19 15:40:03 +0900296 err |= __copy_from_user(&current->thread.xstate->hardfpu, &sc->sc_fpregs[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 (sizeof(long long) * 32) + (sizeof(int) * 1));
298
299 return err;
300}
301
302static inline int
303setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
304{
305 int err = 0;
306 int fpvalid;
307
308 fpvalid = !!used_math();
309 err |= __put_user(fpvalid, &sc->sc_fpvalid);
310 if (! fpvalid)
311 return err;
312
313 if (current == last_task_used_math) {
Paul Mundt600ee242007-11-19 19:13:38 +0900314 enable_fpu();
Matt Fleming61cc7b02009-12-14 20:12:04 +0000315 save_fpu(current);
Paul Mundt600ee242007-11-19 19:13:38 +0900316 disable_fpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 last_task_used_math = NULL;
318 regs->sr |= SR_FD;
319 }
320
Paul Mundt3ef29322010-01-19 15:40:03 +0900321 err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.xstate->hardfpu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 (sizeof(long long) * 32) + (sizeof(int) * 1));
323 clear_used_math();
324
325 return err;
326}
327#else
328static inline int
329restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900330{
331 return 0;
332}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333static inline int
334setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900335{
336 return 0;
337}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338#endif
339
340static int
341restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
342{
343 unsigned int err = 0;
344 unsigned long long current_sr, new_sr;
345#define SR_MASK 0xffff8cfd
346
347#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
348
349 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
350 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
351 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
352 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
353 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
354 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
355 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
356 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
357 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
358 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
359 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
360 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
361 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
362 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
363 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
364 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
365 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
366 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
367
368 /* Prevent the signal handler manipulating SR in a way that can
369 crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
370 modified */
371 current_sr = regs->sr;
372 err |= __get_user(new_sr, &sc->sc_sr);
373 regs->sr &= SR_MASK;
374 regs->sr |= (new_sr & ~SR_MASK);
375
376 COPY(pc);
377
378#undef COPY
379
380 /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
381 * has been restored above.) */
382 err |= restore_sigcontext_fpu(regs, sc);
383
384 regs->syscall_nr = -1; /* disable syscall checks */
385 err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
386 return err;
387}
388
389asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
390 unsigned long r4, unsigned long r5,
391 unsigned long r6, unsigned long r7,
392 struct pt_regs * regs)
393{
394 struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
395 sigset_t set;
396 long long ret;
397
Paul Mundt1bec1572008-09-24 14:37:35 +0900398 /* Always make any pending restarted system calls return -EINTR */
399 current_thread_info()->restart_block.fn = do_no_restart_syscall;
400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
402 goto badframe;
403
404 if (__get_user(set.sig[0], &frame->sc.oldmask)
405 || (_NSIG_WORDS > 1
406 && __copy_from_user(&set.sig[1], &frame->extramask,
407 sizeof(frame->extramask))))
408 goto badframe;
409
410 sigdelsetmask(&set, ~_BLOCKABLE);
411
412 spin_lock_irq(&current->sighand->siglock);
413 current->blocked = set;
414 recalc_sigpending();
415 spin_unlock_irq(&current->sighand->siglock);
416
417 if (restore_sigcontext(regs, &frame->sc, &ret))
418 goto badframe;
419 regs->pc -= 4;
420
421 return (int) ret;
422
423badframe:
424 force_sig(SIGSEGV, current);
425 return 0;
426}
427
428asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
429 unsigned long r4, unsigned long r5,
430 unsigned long r6, unsigned long r7,
431 struct pt_regs * regs)
432{
433 struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
434 sigset_t set;
435 stack_t __user st;
436 long long ret;
437
Paul Mundt1bec1572008-09-24 14:37:35 +0900438 /* Always make any pending restarted system calls return -EINTR */
439 current_thread_info()->restart_block.fn = do_no_restart_syscall;
440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
442 goto badframe;
443
444 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
445 goto badframe;
446
447 sigdelsetmask(&set, ~_BLOCKABLE);
448 spin_lock_irq(&current->sighand->siglock);
449 current->blocked = set;
450 recalc_sigpending();
451 spin_unlock_irq(&current->sighand->siglock);
452
453 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
454 goto badframe;
455 regs->pc -= 4;
456
457 if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
458 goto badframe;
459 /* It is more difficult to avoid calling this function than to
460 call it and ignore errors. */
461 do_sigaltstack(&st, NULL, REF_REG_SP);
462
463 return (int) ret;
464
465badframe:
466 force_sig(SIGSEGV, current);
467 return 0;
468}
469
470/*
471 * Set up a signal frame.
472 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473static int
474setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
475 unsigned long mask)
476{
477 int err = 0;
478
479 /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
480 err |= setup_sigcontext_fpu(regs, sc);
481
482#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
483
484 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
485 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
486 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
487 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
488 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
489 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
490 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
491 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
492 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
493 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
494 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
495 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
496 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
497 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
498 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
499 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
500 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
501 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
502 COPY(sr); COPY(pc);
503
504#undef COPY
505
506 err |= __put_user(mask, &sc->oldmask);
507
508 return err;
509}
510
511/*
512 * Determine which stack to use..
513 */
514static inline void __user *
515get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
516{
Laurent MEYERd09042d2006-06-23 02:05:36 -0700517 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 sp = current->sas_ss_sp + current->sas_ss_size;
519
520 return (void __user *)((sp - frame_size) & -8ul);
521}
522
523void sa_default_restorer(void); /* See comments below */
524void sa_default_rt_restorer(void); /* See comments below */
525
Paul Mundt6ac03432008-12-10 19:26:44 +0900526static int setup_frame(int sig, struct k_sigaction *ka,
527 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 struct sigframe __user *frame;
530 int err = 0;
531 int signal;
532
533 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
534
535 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
536 goto give_sigsegv;
537
538 signal = current_thread_info()->exec_domain
539 && current_thread_info()->exec_domain->signal_invmap
540 && sig < 32
541 ? current_thread_info()->exec_domain->signal_invmap[sig]
542 : sig;
543
544 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
545
546 /* Give up earlier as i386, in case */
547 if (err)
548 goto give_sigsegv;
549
550 if (_NSIG_WORDS > 1) {
551 err |= __copy_to_user(frame->extramask, &set->sig[1],
552 sizeof(frame->extramask)); }
553
554 /* Give up earlier as i386, in case */
555 if (err)
556 goto give_sigsegv;
557
558 /* Set up to return from userspace. If provided, use a stub
559 already in userspace. */
560 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 /*
562 * On SH5 all edited pointers are subject to NEFF
563 */
Paul Mundtc7914832009-08-04 17:14:39 +0900564 DEREF_REG_PR = neff_sign_extend((unsigned long)
565 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 } else {
567 /*
568 * Different approach on SH5.
569 * . Endianness independent asm code gets placed in entry.S .
570 * This is limited to four ASM instructions corresponding
571 * to two long longs in size.
572 * . err checking is done on the else branch only
573 * . flush_icache_range() is called upon __put_user() only
574 * . all edited pointers are subject to NEFF
575 * . being code, linker turns ShMedia bit on, always
576 * dereference index -1.
577 */
Paul Mundtc7914832009-08-04 17:14:39 +0900578 DEREF_REG_PR = neff_sign_extend((unsigned long)
579 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900582 (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 goto give_sigsegv;
584
585 /* Cohere the trampoline with the I-cache. */
Paul Mundtb6138812007-11-11 15:53:51 +0900586 flush_cache_sigtramp(DEREF_REG_PR-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 }
588
589 /*
590 * Set up registers for signal handler.
591 * All edited pointers are subject to NEFF.
592 */
Paul Mundtc7914832009-08-04 17:14:39 +0900593 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
595
596 /* FIXME:
597 The glibc profiling support for SH-5 needs to be passed a sigcontext
598 so it can retrieve the PC. At some point during 2003 the glibc
599 support was changed to receive the sigcontext through the 2nd
600 argument, but there are still versions of libc.so in use that use
601 the 3rd argument. Until libc.so is stabilised, pass the sigcontext
602 through both 2nd and 3rd arguments.
603 */
604
605 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
606 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
607
Paul Mundtc7914832009-08-04 17:14:39 +0900608 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 set_fs(USER_DS);
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 /* Broken %016Lx */
Paul Mundt6ac03432008-12-10 19:26:44 +0900613 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
614 signal, current->comm, current->pid, frame,
615 regs->pc >> 32, regs->pc & 0xffffffff,
616 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Paul Mundt6ac03432008-12-10 19:26:44 +0900618 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620give_sigsegv:
621 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900622 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
Paul Mundt6ac03432008-12-10 19:26:44 +0900625static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
626 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 struct rt_sigframe __user *frame;
629 int err = 0;
630 int signal;
631
632 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
633
634 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
635 goto give_sigsegv;
636
637 signal = current_thread_info()->exec_domain
638 && current_thread_info()->exec_domain->signal_invmap
639 && sig < 32
640 ? current_thread_info()->exec_domain->signal_invmap[sig]
641 : sig;
642
643 err |= __put_user(&frame->info, &frame->pinfo);
644 err |= __put_user(&frame->uc, &frame->puc);
645 err |= copy_siginfo_to_user(&frame->info, info);
646
647 /* Give up earlier as i386, in case */
648 if (err)
649 goto give_sigsegv;
650
651 /* Create the ucontext. */
652 err |= __put_user(0, &frame->uc.uc_flags);
653 err |= __put_user(0, &frame->uc.uc_link);
654 err |= __put_user((void *)current->sas_ss_sp,
655 &frame->uc.uc_stack.ss_sp);
656 err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
657 &frame->uc.uc_stack.ss_flags);
658 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
659 err |= setup_sigcontext(&frame->uc.uc_mcontext,
660 regs, set->sig[0]);
661 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
662
663 /* Give up earlier as i386, in case */
664 if (err)
665 goto give_sigsegv;
666
667 /* Set up to return from userspace. If provided, use a stub
668 already in userspace. */
669 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /*
671 * On SH5 all edited pointers are subject to NEFF
672 */
Paul Mundtc7914832009-08-04 17:14:39 +0900673 DEREF_REG_PR = neff_sign_extend((unsigned long)
674 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 } else {
676 /*
677 * Different approach on SH5.
678 * . Endianness independent asm code gets placed in entry.S .
679 * This is limited to four ASM instructions corresponding
680 * to two long longs in size.
681 * . err checking is done on the else branch only
682 * . flush_icache_range() is called upon __put_user() only
683 * . all edited pointers are subject to NEFF
684 * . being code, linker turns ShMedia bit on, always
685 * dereference index -1.
686 */
Paul Mundtc7914832009-08-04 17:14:39 +0900687 DEREF_REG_PR = neff_sign_extend((unsigned long)
688 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900691 (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 goto give_sigsegv;
693
Paul Mundtc7914832009-08-04 17:14:39 +0900694 /* Cohere the trampoline with the I-cache. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
696 }
697
698 /*
699 * Set up registers for signal handler.
700 * All edited pointers are subject to NEFF.
701 */
Paul Mundtc7914832009-08-04 17:14:39 +0900702 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
704 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
705 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
Paul Mundtc7914832009-08-04 17:14:39 +0900706 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 set_fs(USER_DS);
709
Paul Mundt6ac03432008-12-10 19:26:44 +0900710 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
711 signal, current->comm, current->pid, frame,
712 regs->pc >> 32, regs->pc & 0xffffffff,
713 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Paul Mundt6ac03432008-12-10 19:26:44 +0900715 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717give_sigsegv:
718 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900719 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
722/*
723 * OK, we're invoking a handler
724 */
Paul Mundt6ac03432008-12-10 19:26:44 +0900725static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
727 sigset_t *oldset, struct pt_regs * regs)
728{
Paul Mundt6ac03432008-12-10 19:26:44 +0900729 int ret;
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* Set up the stack frame */
732 if (ka->sa.sa_flags & SA_SIGINFO)
Paul Mundt6ac03432008-12-10 19:26:44 +0900733 ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 else
Paul Mundt6ac03432008-12-10 19:26:44 +0900735 ret = setup_frame(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Paul Mundt6ac03432008-12-10 19:26:44 +0900737 if (ka->sa.sa_flags & SA_ONESHOT)
738 ka->sa.sa_handler = SIG_DFL;
739
740 if (ret == 0) {
741 spin_lock_irq(&current->sighand->siglock);
742 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
743 if (!(ka->sa.sa_flags & SA_NODEFER))
744 sigaddset(&current->blocked,sig);
745 recalc_sigpending();
746 spin_unlock_irq(&current->sighand->siglock);
747 }
748
749 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
Paul Mundtab99c732008-07-30 19:55:30 +0900752asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Paul Mundtab99c732008-07-30 19:55:30 +0900754 if (thread_info_flags & _TIF_SIGPENDING)
755 do_signal(regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Paul Mundtab99c732008-07-30 19:55:30 +0900757 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
758 clear_thread_flag(TIF_NOTIFY_RESUME);
759 tracehook_notify_resume(regs);
David Howellsee18d642009-09-02 09:14:21 +0100760 if (current->replacement_session_keyring)
761 key_replace_session_keyring();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}