blob: ce76dbdef2940fa8e920dcbc8f4bc265a0607b5f [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
101 if (try_to_freeze())
102 goto no_signal;
103
Paul Mundt56bfc422009-10-14 16:05:42 +0900104 if (current_thread_info()->status & TS_RESTORE_SIGMASK)
Paul Mundtab99c732008-07-30 19:55:30 +0900105 oldset = &current->saved_sigmask;
106 else if (!oldset)
107 oldset = &current->blocked;
108
109 signr = get_signal_to_deliver(&info, &ka, regs, 0);
Paul Mundtab99c732008-07-30 19:55:30 +0900110 if (signr > 0) {
Paul Mundt03f07872009-01-29 11:21:38 +0900111 handle_syscall_restart(regs, &ka.sa);
Paul Mundt94e2fb32008-12-10 19:46:18 +0900112
Paul Mundtab99c732008-07-30 19:55:30 +0900113 /* Whee! Actually deliver the signal. */
Paul Mundt6ac03432008-12-10 19:26:44 +0900114 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
115 /*
116 * If a signal was successfully delivered, the
117 * saved sigmask is in its frame, and we can
Paul Mundt56bfc422009-10-14 16:05:42 +0900118 * clear the TS_RESTORE_SIGMASK flag.
Paul Mundt6ac03432008-12-10 19:26:44 +0900119 */
Paul Mundt56bfc422009-10-14 16:05:42 +0900120 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
Paul Mundt6ac03432008-12-10 19:26:44 +0900121 tracehook_signal_handler(signr, &info, &ka, regs, 0);
122 return 1;
123 }
Paul Mundtab99c732008-07-30 19:55:30 +0900124 }
125
126no_signal:
127 /* Did we come from a system call? */
128 if (regs->syscall_nr >= 0) {
129 /* Restart the system call - no handlers present */
130 switch (regs->regs[REG_RET]) {
131 case -ERESTARTNOHAND:
132 case -ERESTARTSYS:
133 case -ERESTARTNOINTR:
134 /* Decode Syscall # */
135 regs->regs[REG_RET] = regs->syscall_nr;
136 regs->pc -= 4;
137 break;
138
139 case -ERESTART_RESTARTBLOCK:
140 regs->regs[REG_RET] = __NR_restart_syscall;
141 regs->pc -= 4;
142 break;
143 }
144 }
145
146 /* No signal to deliver -- put the saved sigmask back */
Paul Mundt56bfc422009-10-14 16:05:42 +0900147 if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
148 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
Paul Mundtab99c732008-07-30 19:55:30 +0900149 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
150 }
151
152 return 0;
153}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155/*
156 * Atomically swap in the new signal mask, and wait for a signal.
157 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158asmlinkage int
159sys_sigsuspend(old_sigset_t mask,
160 unsigned long r3, unsigned long r4, unsigned long r5,
161 unsigned long r6, unsigned long r7,
162 struct pt_regs * regs)
163{
164 sigset_t saveset;
165
166 mask &= _BLOCKABLE;
167 spin_lock_irq(&current->sighand->siglock);
168 saveset = current->blocked;
169 siginitset(&current->blocked, mask);
170 recalc_sigpending();
171 spin_unlock_irq(&current->sighand->siglock);
172
173 REF_REG_RET = -EINTR;
174 while (1) {
175 current->state = TASK_INTERRUPTIBLE;
176 schedule();
Paul Mundt56bfc422009-10-14 16:05:42 +0900177 set_restore_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 regs->pc += 4; /* because sys_sigreturn decrements the pc */
179 if (do_signal(regs, &saveset)) {
180 /* pc now points at signal handler. Need to decrement
181 it because entry.S will increment it. */
182 regs->pc -= 4;
183 return -EINTR;
184 }
185 }
186}
187
188asmlinkage int
189sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
190 unsigned long r4, unsigned long r5, unsigned long r6,
191 unsigned long r7,
192 struct pt_regs * regs)
193{
194 sigset_t saveset, newset;
195
196 /* XXX: Don't preclude handling different sized sigset_t's. */
197 if (sigsetsize != sizeof(sigset_t))
198 return -EINVAL;
199
200 if (copy_from_user(&newset, unewset, sizeof(newset)))
201 return -EFAULT;
202 sigdelsetmask(&newset, ~_BLOCKABLE);
203 spin_lock_irq(&current->sighand->siglock);
204 saveset = current->blocked;
205 current->blocked = newset;
206 recalc_sigpending();
207 spin_unlock_irq(&current->sighand->siglock);
208
209 REF_REG_RET = -EINTR;
210 while (1) {
211 current->state = TASK_INTERRUPTIBLE;
212 schedule();
213 regs->pc += 4; /* because sys_sigreturn decrements the pc */
214 if (do_signal(regs, &saveset)) {
215 /* pc now points at signal handler. Need to decrement
216 it because entry.S will increment it. */
217 regs->pc -= 4;
218 return -EINTR;
219 }
220 }
221}
222
223asmlinkage int
224sys_sigaction(int sig, const struct old_sigaction __user *act,
225 struct old_sigaction __user *oact)
226{
227 struct k_sigaction new_ka, old_ka;
228 int ret;
229
230 if (act) {
231 old_sigset_t mask;
232 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
233 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
234 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
235 return -EFAULT;
236 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
237 __get_user(mask, &act->sa_mask);
238 siginitset(&new_ka.sa.sa_mask, mask);
239 }
240
241 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
242
243 if (!ret && oact) {
244 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
245 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
246 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
247 return -EFAULT;
248 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
249 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
250 }
251
252 return ret;
253}
254
255asmlinkage int
256sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
257 unsigned long r4, unsigned long r5, unsigned long r6,
258 unsigned long r7,
259 struct pt_regs * regs)
260{
261 return do_sigaltstack(uss, uoss, REF_REG_SP);
262}
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264/*
265 * Do a signal return; undo the signal stack.
266 */
Paul Mundt94e2fb32008-12-10 19:46:18 +0900267struct sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 struct sigcontext sc;
269 unsigned long extramask[_NSIG_WORDS-1];
270 long long retcode[2];
271};
272
Paul Mundt94e2fb32008-12-10 19:46:18 +0900273struct rt_sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 struct siginfo __user *pinfo;
275 void *puc;
276 struct siginfo info;
277 struct ucontext uc;
278 long long retcode[2];
279};
280
281#ifdef CONFIG_SH_FPU
282static inline int
283restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
284{
285 int err = 0;
286 int fpvalid;
287
288 err |= __get_user (fpvalid, &sc->sc_fpvalid);
289 conditional_used_math(fpvalid);
290 if (! fpvalid)
291 return err;
292
293 if (current == last_task_used_math) {
294 last_task_used_math = NULL;
295 regs->sr |= SR_FD;
296 }
297
298 err |= __copy_from_user(&current->thread.fpu.hard, &sc->sc_fpregs[0],
299 (sizeof(long long) * 32) + (sizeof(int) * 1));
300
301 return err;
302}
303
304static inline int
305setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
306{
307 int err = 0;
308 int fpvalid;
309
310 fpvalid = !!used_math();
311 err |= __put_user(fpvalid, &sc->sc_fpvalid);
312 if (! fpvalid)
313 return err;
314
315 if (current == last_task_used_math) {
Paul Mundt600ee242007-11-19 19:13:38 +0900316 enable_fpu();
Matt Fleming61cc7b02009-12-14 20:12:04 +0000317 save_fpu(current);
Paul Mundt600ee242007-11-19 19:13:38 +0900318 disable_fpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 last_task_used_math = NULL;
320 regs->sr |= SR_FD;
321 }
322
323 err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.fpu.hard,
324 (sizeof(long long) * 32) + (sizeof(int) * 1));
325 clear_used_math();
326
327 return err;
328}
329#else
330static inline int
331restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900332{
333 return 0;
334}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335static inline int
336setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900337{
338 return 0;
339}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340#endif
341
342static int
343restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
344{
345 unsigned int err = 0;
346 unsigned long long current_sr, new_sr;
347#define SR_MASK 0xffff8cfd
348
349#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
350
351 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
352 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
353 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
354 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
355 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
356 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
357 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
358 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
359 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
360 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
361 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
362 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
363 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
364 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
365 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
366 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
367 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
368 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
369
370 /* Prevent the signal handler manipulating SR in a way that can
371 crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
372 modified */
373 current_sr = regs->sr;
374 err |= __get_user(new_sr, &sc->sc_sr);
375 regs->sr &= SR_MASK;
376 regs->sr |= (new_sr & ~SR_MASK);
377
378 COPY(pc);
379
380#undef COPY
381
382 /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
383 * has been restored above.) */
384 err |= restore_sigcontext_fpu(regs, sc);
385
386 regs->syscall_nr = -1; /* disable syscall checks */
387 err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
388 return err;
389}
390
391asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
392 unsigned long r4, unsigned long r5,
393 unsigned long r6, unsigned long r7,
394 struct pt_regs * regs)
395{
396 struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
397 sigset_t set;
398 long long ret;
399
Paul Mundt1bec1572008-09-24 14:37:35 +0900400 /* Always make any pending restarted system calls return -EINTR */
401 current_thread_info()->restart_block.fn = do_no_restart_syscall;
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
404 goto badframe;
405
406 if (__get_user(set.sig[0], &frame->sc.oldmask)
407 || (_NSIG_WORDS > 1
408 && __copy_from_user(&set.sig[1], &frame->extramask,
409 sizeof(frame->extramask))))
410 goto badframe;
411
412 sigdelsetmask(&set, ~_BLOCKABLE);
413
414 spin_lock_irq(&current->sighand->siglock);
415 current->blocked = set;
416 recalc_sigpending();
417 spin_unlock_irq(&current->sighand->siglock);
418
419 if (restore_sigcontext(regs, &frame->sc, &ret))
420 goto badframe;
421 regs->pc -= 4;
422
423 return (int) ret;
424
425badframe:
426 force_sig(SIGSEGV, current);
427 return 0;
428}
429
430asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
431 unsigned long r4, unsigned long r5,
432 unsigned long r6, unsigned long r7,
433 struct pt_regs * regs)
434{
435 struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
436 sigset_t set;
437 stack_t __user st;
438 long long ret;
439
Paul Mundt1bec1572008-09-24 14:37:35 +0900440 /* Always make any pending restarted system calls return -EINTR */
441 current_thread_info()->restart_block.fn = do_no_restart_syscall;
442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
444 goto badframe;
445
446 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
447 goto badframe;
448
449 sigdelsetmask(&set, ~_BLOCKABLE);
450 spin_lock_irq(&current->sighand->siglock);
451 current->blocked = set;
452 recalc_sigpending();
453 spin_unlock_irq(&current->sighand->siglock);
454
455 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
456 goto badframe;
457 regs->pc -= 4;
458
459 if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
460 goto badframe;
461 /* It is more difficult to avoid calling this function than to
462 call it and ignore errors. */
463 do_sigaltstack(&st, NULL, REF_REG_SP);
464
465 return (int) ret;
466
467badframe:
468 force_sig(SIGSEGV, current);
469 return 0;
470}
471
472/*
473 * Set up a signal frame.
474 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475static int
476setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
477 unsigned long mask)
478{
479 int err = 0;
480
481 /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
482 err |= setup_sigcontext_fpu(regs, sc);
483
484#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
485
486 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
487 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
488 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
489 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
490 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
491 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
492 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
493 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
494 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
495 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
496 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
497 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
498 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
499 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
500 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
501 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
502 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
503 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
504 COPY(sr); COPY(pc);
505
506#undef COPY
507
508 err |= __put_user(mask, &sc->oldmask);
509
510 return err;
511}
512
513/*
514 * Determine which stack to use..
515 */
516static inline void __user *
517get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
518{
Laurent MEYERd09042d2006-06-23 02:05:36 -0700519 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 sp = current->sas_ss_sp + current->sas_ss_size;
521
522 return (void __user *)((sp - frame_size) & -8ul);
523}
524
525void sa_default_restorer(void); /* See comments below */
526void sa_default_rt_restorer(void); /* See comments below */
527
Paul Mundt6ac03432008-12-10 19:26:44 +0900528static int setup_frame(int sig, struct k_sigaction *ka,
529 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
531 struct sigframe __user *frame;
532 int err = 0;
533 int signal;
534
535 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
536
537 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
538 goto give_sigsegv;
539
540 signal = current_thread_info()->exec_domain
541 && current_thread_info()->exec_domain->signal_invmap
542 && sig < 32
543 ? current_thread_info()->exec_domain->signal_invmap[sig]
544 : sig;
545
546 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
547
548 /* Give up earlier as i386, in case */
549 if (err)
550 goto give_sigsegv;
551
552 if (_NSIG_WORDS > 1) {
553 err |= __copy_to_user(frame->extramask, &set->sig[1],
554 sizeof(frame->extramask)); }
555
556 /* Give up earlier as i386, in case */
557 if (err)
558 goto give_sigsegv;
559
560 /* Set up to return from userspace. If provided, use a stub
561 already in userspace. */
562 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 /*
564 * On SH5 all edited pointers are subject to NEFF
565 */
Paul Mundtc7914832009-08-04 17:14:39 +0900566 DEREF_REG_PR = neff_sign_extend((unsigned long)
567 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 } else {
569 /*
570 * Different approach on SH5.
571 * . Endianness independent asm code gets placed in entry.S .
572 * This is limited to four ASM instructions corresponding
573 * to two long longs in size.
574 * . err checking is done on the else branch only
575 * . flush_icache_range() is called upon __put_user() only
576 * . all edited pointers are subject to NEFF
577 * . being code, linker turns ShMedia bit on, always
578 * dereference index -1.
579 */
Paul Mundtc7914832009-08-04 17:14:39 +0900580 DEREF_REG_PR = neff_sign_extend((unsigned long)
581 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900584 (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 goto give_sigsegv;
586
587 /* Cohere the trampoline with the I-cache. */
Paul Mundtb6138812007-11-11 15:53:51 +0900588 flush_cache_sigtramp(DEREF_REG_PR-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
590
591 /*
592 * Set up registers for signal handler.
593 * All edited pointers are subject to NEFF.
594 */
Paul Mundtc7914832009-08-04 17:14:39 +0900595 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
597
598 /* FIXME:
599 The glibc profiling support for SH-5 needs to be passed a sigcontext
600 so it can retrieve the PC. At some point during 2003 the glibc
601 support was changed to receive the sigcontext through the 2nd
602 argument, but there are still versions of libc.so in use that use
603 the 3rd argument. Until libc.so is stabilised, pass the sigcontext
604 through both 2nd and 3rd arguments.
605 */
606
607 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
608 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
609
Paul Mundtc7914832009-08-04 17:14:39 +0900610 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 set_fs(USER_DS);
613
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 /* Broken %016Lx */
Paul Mundt6ac03432008-12-10 19:26:44 +0900615 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
616 signal, current->comm, current->pid, frame,
617 regs->pc >> 32, regs->pc & 0xffffffff,
618 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Paul Mundt6ac03432008-12-10 19:26:44 +0900620 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622give_sigsegv:
623 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900624 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625}
626
Paul Mundt6ac03432008-12-10 19:26:44 +0900627static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
628 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 struct rt_sigframe __user *frame;
631 int err = 0;
632 int signal;
633
634 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
635
636 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
637 goto give_sigsegv;
638
639 signal = current_thread_info()->exec_domain
640 && current_thread_info()->exec_domain->signal_invmap
641 && sig < 32
642 ? current_thread_info()->exec_domain->signal_invmap[sig]
643 : sig;
644
645 err |= __put_user(&frame->info, &frame->pinfo);
646 err |= __put_user(&frame->uc, &frame->puc);
647 err |= copy_siginfo_to_user(&frame->info, info);
648
649 /* Give up earlier as i386, in case */
650 if (err)
651 goto give_sigsegv;
652
653 /* Create the ucontext. */
654 err |= __put_user(0, &frame->uc.uc_flags);
655 err |= __put_user(0, &frame->uc.uc_link);
656 err |= __put_user((void *)current->sas_ss_sp,
657 &frame->uc.uc_stack.ss_sp);
658 err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
659 &frame->uc.uc_stack.ss_flags);
660 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
661 err |= setup_sigcontext(&frame->uc.uc_mcontext,
662 regs, set->sig[0]);
663 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
664
665 /* Give up earlier as i386, in case */
666 if (err)
667 goto give_sigsegv;
668
669 /* Set up to return from userspace. If provided, use a stub
670 already in userspace. */
671 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 /*
673 * On SH5 all edited pointers are subject to NEFF
674 */
Paul Mundtc7914832009-08-04 17:14:39 +0900675 DEREF_REG_PR = neff_sign_extend((unsigned long)
676 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 } else {
678 /*
679 * Different approach on SH5.
680 * . Endianness independent asm code gets placed in entry.S .
681 * This is limited to four ASM instructions corresponding
682 * to two long longs in size.
683 * . err checking is done on the else branch only
684 * . flush_icache_range() is called upon __put_user() only
685 * . all edited pointers are subject to NEFF
686 * . being code, linker turns ShMedia bit on, always
687 * dereference index -1.
688 */
Paul Mundtc7914832009-08-04 17:14:39 +0900689 DEREF_REG_PR = neff_sign_extend((unsigned long)
690 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900693 (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 goto give_sigsegv;
695
Paul Mundtc7914832009-08-04 17:14:39 +0900696 /* Cohere the trampoline with the I-cache. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
698 }
699
700 /*
701 * Set up registers for signal handler.
702 * All edited pointers are subject to NEFF.
703 */
Paul Mundtc7914832009-08-04 17:14:39 +0900704 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
706 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
707 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
Paul Mundtc7914832009-08-04 17:14:39 +0900708 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 set_fs(USER_DS);
711
Paul Mundt6ac03432008-12-10 19:26:44 +0900712 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
713 signal, current->comm, current->pid, frame,
714 regs->pc >> 32, regs->pc & 0xffffffff,
715 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Paul Mundt6ac03432008-12-10 19:26:44 +0900717 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719give_sigsegv:
720 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900721 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722}
723
724/*
725 * OK, we're invoking a handler
726 */
Paul Mundt6ac03432008-12-10 19:26:44 +0900727static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
729 sigset_t *oldset, struct pt_regs * regs)
730{
Paul Mundt6ac03432008-12-10 19:26:44 +0900731 int ret;
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 /* Set up the stack frame */
734 if (ka->sa.sa_flags & SA_SIGINFO)
Paul Mundt6ac03432008-12-10 19:26:44 +0900735 ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 else
Paul Mundt6ac03432008-12-10 19:26:44 +0900737 ret = setup_frame(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Paul Mundt6ac03432008-12-10 19:26:44 +0900739 if (ka->sa.sa_flags & SA_ONESHOT)
740 ka->sa.sa_handler = SIG_DFL;
741
742 if (ret == 0) {
743 spin_lock_irq(&current->sighand->siglock);
744 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
745 if (!(ka->sa.sa_flags & SA_NODEFER))
746 sigaddset(&current->blocked,sig);
747 recalc_sigpending();
748 spin_unlock_irq(&current->sighand->siglock);
749 }
750
751 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
Paul Mundtab99c732008-07-30 19:55:30 +0900754asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755{
Paul Mundtab99c732008-07-30 19:55:30 +0900756 if (thread_info_flags & _TIF_SIGPENDING)
757 do_signal(regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Paul Mundtab99c732008-07-30 19:55:30 +0900759 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
760 clear_thread_flag(TIF_NOTIFY_RESUME);
761 tracehook_notify_resume(regs);
David Howellsee18d642009-09-02 09:14:21 +0100762 if (current->replacement_session_keyring)
763 key_replace_session_keyring();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765}