blob: e5b1b3c79ff3f8172d686554666a753c6e4d6a26 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/alpha/kernel/signal.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 *
6 * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson
7 */
8
9#include <linux/sched.h>
10#include <linux/kernel.h>
11#include <linux/signal.h>
12#include <linux/errno.h>
13#include <linux/wait.h>
14#include <linux/ptrace.h>
15#include <linux/unistd.h>
16#include <linux/mm.h>
17#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/stddef.h>
19#include <linux/tty.h>
20#include <linux/binfmts.h>
21#include <linux/bitops.h>
Ivan Kokshayskye5d9a902009-01-29 14:25:18 -080022#include <linux/syscalls.h>
David Howells733e5e42009-09-09 08:30:21 +010023#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#include <asm/uaccess.h>
26#include <asm/sigcontext.h>
27#include <asm/ucontext.h>
28
29#include "proto.h"
30
31
32#define DEBUG_SIG 0
33
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35
36asmlinkage void ret_from_sys_call(void);
Richard Hendersonb927b3e2007-05-29 16:03:28 -070037static void do_signal(struct pt_regs *, struct switch_stack *,
38 unsigned long, unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40
41/*
42 * The OSF/1 sigprocmask calling sequence is different from the
43 * C sigprocmask() sequence..
44 *
45 * how:
46 * 1 - SIG_BLOCK
47 * 2 - SIG_UNBLOCK
48 * 3 - SIG_SETMASK
49 *
50 * We change the range to -1 .. 1 in order to let gcc easily
51 * use the conditional move instructions.
52 *
53 * Note that we don't need to acquire the kernel lock for SMP
54 * operation, as all of this is local to this thread.
55 */
Ivan Kokshayskye5d9a902009-01-29 14:25:18 -080056SYSCALL_DEFINE3(osf_sigprocmask, int, how, unsigned long, newmask,
57 struct pt_regs *, regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058{
59 unsigned long oldmask = -EINVAL;
60
61 if ((unsigned long)how-1 <= 2) {
62 long sign = how-2; /* -1 .. 1 */
63 unsigned long block, unblock;
64
65 newmask &= _BLOCKABLE;
66 spin_lock_irq(&current->sighand->siglock);
67 oldmask = current->blocked.sig[0];
68
69 unblock = oldmask & ~newmask;
70 block = oldmask | newmask;
71 if (!sign)
72 block = unblock;
73 if (sign <= 0)
74 newmask = block;
75 if (_NSIG_WORDS > 1 && sign > 0)
76 sigemptyset(&current->blocked);
77 current->blocked.sig[0] = newmask;
78 recalc_sigpending();
79 spin_unlock_irq(&current->sighand->siglock);
80
81 regs->r0 = 0; /* special no error return */
82 }
83 return oldmask;
84}
85
Ivan Kokshayskye5d9a902009-01-29 14:25:18 -080086SYSCALL_DEFINE3(osf_sigaction, int, sig,
87 const struct osf_sigaction __user *, act,
88 struct osf_sigaction __user *, oact)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 struct k_sigaction new_ka, old_ka;
91 int ret;
92
93 if (act) {
94 old_sigset_t mask;
95 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
96 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
97 __get_user(new_ka.sa.sa_flags, &act->sa_flags))
98 return -EFAULT;
99 __get_user(mask, &act->sa_mask);
100 siginitset(&new_ka.sa.sa_mask, mask);
101 new_ka.ka_restorer = NULL;
102 }
103
104 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
105
106 if (!ret && oact) {
107 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
108 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
109 __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
110 return -EFAULT;
111 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
112 }
113
114 return ret;
115}
116
Ivan Kokshayskye5d9a902009-01-29 14:25:18 -0800117SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
118 struct sigaction __user *, oact,
119 size_t, sigsetsize, void __user *, restorer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
121 struct k_sigaction new_ka, old_ka;
122 int ret;
123
124 /* XXX: Don't preclude handling different sized sigset_t's. */
125 if (sigsetsize != sizeof(sigset_t))
126 return -EINVAL;
127
128 if (act) {
129 new_ka.ka_restorer = restorer;
130 if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
131 return -EFAULT;
132 }
133
134 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
135
136 if (!ret && oact) {
137 if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
138 return -EFAULT;
139 }
140
141 return ret;
142}
143
144/*
145 * Atomically swap in the new signal mask, and wait for a signal.
146 */
147asmlinkage int
148do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
149{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 mask &= _BLOCKABLE;
151 spin_lock_irq(&current->sighand->siglock);
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700152 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 siginitset(&current->blocked, mask);
154 recalc_sigpending();
155 spin_unlock_irq(&current->sighand->siglock);
156
157 /* Indicate EINTR on return from any possible signal handler,
158 which will not come back through here, but via sigreturn. */
159 regs->r0 = EINTR;
160 regs->r19 = 1;
161
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700162 current->state = TASK_INTERRUPTIBLE;
163 schedule();
164 set_thread_flag(TIF_RESTORE_SIGMASK);
165 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166}
167
168asmlinkage int
169do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
170 struct pt_regs *regs, struct switch_stack *sw)
171{
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700172 sigset_t set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174 /* XXX: Don't preclude handling different sized sigset_t's. */
175 if (sigsetsize != sizeof(sigset_t))
176 return -EINVAL;
177 if (copy_from_user(&set, uset, sizeof(set)))
178 return -EFAULT;
179
180 sigdelsetmask(&set, ~_BLOCKABLE);
181 spin_lock_irq(&current->sighand->siglock);
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700182 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 current->blocked = set;
184 recalc_sigpending();
185 spin_unlock_irq(&current->sighand->siglock);
186
187 /* Indicate EINTR on return from any possible signal handler,
188 which will not come back through here, but via sigreturn. */
189 regs->r0 = EINTR;
190 regs->r19 = 1;
191
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700192 current->state = TASK_INTERRUPTIBLE;
193 schedule();
194 set_thread_flag(TIF_RESTORE_SIGMASK);
195 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
198asmlinkage int
199sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
200{
201 return do_sigaltstack(uss, uoss, rdusp());
202}
203
204/*
205 * Do a signal return; undo the signal stack.
206 */
207
208#if _NSIG_WORDS > 1
209# error "Non SA_SIGINFO frame needs rearranging"
210#endif
211
212struct sigframe
213{
214 struct sigcontext sc;
215 unsigned int retcode[3];
216};
217
218struct rt_sigframe
219{
220 struct siginfo info;
221 struct ucontext uc;
222 unsigned int retcode[3];
223};
224
225/* If this changes, userland unwinders that Know Things about our signal
226 frame will break. Do not undertake lightly. It also implies an ABI
227 change wrt the size of siginfo_t, which may cause some pain. */
228extern char compile_time_assert
229 [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1];
230
231#define INSN_MOV_R30_R16 0x47fe0410
232#define INSN_LDI_R0 0x201f0000
233#define INSN_CALLSYS 0x00000083
234
235static long
236restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
237 struct switch_stack *sw)
238{
239 unsigned long usp;
240 long i, err = __get_user(regs->pc, &sc->sc_pc);
241
Al Viro2deba1b2010-09-18 08:38:47 -0400242 current_thread_info()->restart_block.fn = do_no_restart_syscall;
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 sw->r26 = (unsigned long) ret_from_sys_call;
245
246 err |= __get_user(regs->r0, sc->sc_regs+0);
247 err |= __get_user(regs->r1, sc->sc_regs+1);
248 err |= __get_user(regs->r2, sc->sc_regs+2);
249 err |= __get_user(regs->r3, sc->sc_regs+3);
250 err |= __get_user(regs->r4, sc->sc_regs+4);
251 err |= __get_user(regs->r5, sc->sc_regs+5);
252 err |= __get_user(regs->r6, sc->sc_regs+6);
253 err |= __get_user(regs->r7, sc->sc_regs+7);
254 err |= __get_user(regs->r8, sc->sc_regs+8);
255 err |= __get_user(sw->r9, sc->sc_regs+9);
256 err |= __get_user(sw->r10, sc->sc_regs+10);
257 err |= __get_user(sw->r11, sc->sc_regs+11);
258 err |= __get_user(sw->r12, sc->sc_regs+12);
259 err |= __get_user(sw->r13, sc->sc_regs+13);
260 err |= __get_user(sw->r14, sc->sc_regs+14);
261 err |= __get_user(sw->r15, sc->sc_regs+15);
262 err |= __get_user(regs->r16, sc->sc_regs+16);
263 err |= __get_user(regs->r17, sc->sc_regs+17);
264 err |= __get_user(regs->r18, sc->sc_regs+18);
265 err |= __get_user(regs->r19, sc->sc_regs+19);
266 err |= __get_user(regs->r20, sc->sc_regs+20);
267 err |= __get_user(regs->r21, sc->sc_regs+21);
268 err |= __get_user(regs->r22, sc->sc_regs+22);
269 err |= __get_user(regs->r23, sc->sc_regs+23);
270 err |= __get_user(regs->r24, sc->sc_regs+24);
271 err |= __get_user(regs->r25, sc->sc_regs+25);
272 err |= __get_user(regs->r26, sc->sc_regs+26);
273 err |= __get_user(regs->r27, sc->sc_regs+27);
274 err |= __get_user(regs->r28, sc->sc_regs+28);
275 err |= __get_user(regs->gp, sc->sc_regs+29);
276 err |= __get_user(usp, sc->sc_regs+30);
277 wrusp(usp);
278
279 for (i = 0; i < 31; i++)
280 err |= __get_user(sw->fp[i], sc->sc_fpregs+i);
281 err |= __get_user(sw->fp[31], &sc->sc_fpcr);
282
283 return err;
284}
285
286/* Note that this syscall is also used by setcontext(3) to install
287 a given sigcontext. This because it's impossible to set *all*
288 registers and transfer control from userland. */
289
290asmlinkage void
291do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs,
292 struct switch_stack *sw)
293{
294 sigset_t set;
295
296 /* Verify that it's a good sigcontext before using it */
297 if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
298 goto give_sigsegv;
299 if (__get_user(set.sig[0], &sc->sc_mask))
300 goto give_sigsegv;
301
302 sigdelsetmask(&set, ~_BLOCKABLE);
303 spin_lock_irq(&current->sighand->siglock);
304 current->blocked = set;
305 recalc_sigpending();
306 spin_unlock_irq(&current->sighand->siglock);
307
308 if (restore_sigcontext(sc, regs, sw))
309 goto give_sigsegv;
310
311 /* Send SIGTRAP if we're single-stepping: */
312 if (ptrace_cancel_bpt (current)) {
313 siginfo_t info;
314
315 info.si_signo = SIGTRAP;
316 info.si_errno = 0;
317 info.si_code = TRAP_BRKPT;
318 info.si_addr = (void __user *) regs->pc;
319 info.si_trapno = 0;
320 send_sig_info(SIGTRAP, &info, current);
321 }
322 return;
323
324give_sigsegv:
325 force_sig(SIGSEGV, current);
326}
327
328asmlinkage void
329do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs,
330 struct switch_stack *sw)
331{
332 sigset_t set;
333
334 /* Verify that it's a good ucontext_t before using it */
335 if (!access_ok(VERIFY_READ, &frame->uc, sizeof(frame->uc)))
336 goto give_sigsegv;
337 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
338 goto give_sigsegv;
339
340 sigdelsetmask(&set, ~_BLOCKABLE);
341 spin_lock_irq(&current->sighand->siglock);
342 current->blocked = set;
343 recalc_sigpending();
344 spin_unlock_irq(&current->sighand->siglock);
345
346 if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
347 goto give_sigsegv;
348
349 /* Send SIGTRAP if we're single-stepping: */
350 if (ptrace_cancel_bpt (current)) {
351 siginfo_t info;
352
353 info.si_signo = SIGTRAP;
354 info.si_errno = 0;
355 info.si_code = TRAP_BRKPT;
356 info.si_addr = (void __user *) regs->pc;
357 info.si_trapno = 0;
358 send_sig_info(SIGTRAP, &info, current);
359 }
360 return;
361
362give_sigsegv:
363 force_sig(SIGSEGV, current);
364}
365
366
367/*
368 * Set up a signal frame.
369 */
370
371static inline void __user *
372get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
373{
Laurent MEYERd09042d2006-06-23 02:05:36 -0700374 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 sp = current->sas_ss_sp + current->sas_ss_size;
376
377 return (void __user *)((sp - frame_size) & -32ul);
378}
379
380static long
381setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
382 struct switch_stack *sw, unsigned long mask, unsigned long sp)
383{
384 long i, err = 0;
385
386 err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
387 err |= __put_user(mask, &sc->sc_mask);
388 err |= __put_user(regs->pc, &sc->sc_pc);
389 err |= __put_user(8, &sc->sc_ps);
390
391 err |= __put_user(regs->r0 , sc->sc_regs+0);
392 err |= __put_user(regs->r1 , sc->sc_regs+1);
393 err |= __put_user(regs->r2 , sc->sc_regs+2);
394 err |= __put_user(regs->r3 , sc->sc_regs+3);
395 err |= __put_user(regs->r4 , sc->sc_regs+4);
396 err |= __put_user(regs->r5 , sc->sc_regs+5);
397 err |= __put_user(regs->r6 , sc->sc_regs+6);
398 err |= __put_user(regs->r7 , sc->sc_regs+7);
399 err |= __put_user(regs->r8 , sc->sc_regs+8);
400 err |= __put_user(sw->r9 , sc->sc_regs+9);
401 err |= __put_user(sw->r10 , sc->sc_regs+10);
402 err |= __put_user(sw->r11 , sc->sc_regs+11);
403 err |= __put_user(sw->r12 , sc->sc_regs+12);
404 err |= __put_user(sw->r13 , sc->sc_regs+13);
405 err |= __put_user(sw->r14 , sc->sc_regs+14);
406 err |= __put_user(sw->r15 , sc->sc_regs+15);
407 err |= __put_user(regs->r16, sc->sc_regs+16);
408 err |= __put_user(regs->r17, sc->sc_regs+17);
409 err |= __put_user(regs->r18, sc->sc_regs+18);
410 err |= __put_user(regs->r19, sc->sc_regs+19);
411 err |= __put_user(regs->r20, sc->sc_regs+20);
412 err |= __put_user(regs->r21, sc->sc_regs+21);
413 err |= __put_user(regs->r22, sc->sc_regs+22);
414 err |= __put_user(regs->r23, sc->sc_regs+23);
415 err |= __put_user(regs->r24, sc->sc_regs+24);
416 err |= __put_user(regs->r25, sc->sc_regs+25);
417 err |= __put_user(regs->r26, sc->sc_regs+26);
418 err |= __put_user(regs->r27, sc->sc_regs+27);
419 err |= __put_user(regs->r28, sc->sc_regs+28);
420 err |= __put_user(regs->gp , sc->sc_regs+29);
421 err |= __put_user(sp, sc->sc_regs+30);
422 err |= __put_user(0, sc->sc_regs+31);
423
424 for (i = 0; i < 31; i++)
425 err |= __put_user(sw->fp[i], sc->sc_fpregs+i);
426 err |= __put_user(0, sc->sc_fpregs+31);
427 err |= __put_user(sw->fp[31], &sc->sc_fpcr);
428
429 err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0);
430 err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1);
431 err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2);
432
433 return err;
434}
435
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700436static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
438 struct pt_regs *regs, struct switch_stack * sw)
439{
440 unsigned long oldsp, r26, err = 0;
441 struct sigframe __user *frame;
442
443 oldsp = rdusp();
444 frame = get_sigframe(ka, oldsp, sizeof(*frame));
445 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
446 goto give_sigsegv;
447
448 err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
449 if (err)
450 goto give_sigsegv;
451
452 /* Set up to return from userspace. If provided, use a stub
453 already in userspace. */
454 if (ka->ka_restorer) {
455 r26 = (unsigned long) ka->ka_restorer;
456 } else {
457 err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
458 err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
459 err |= __put_user(INSN_CALLSYS, frame->retcode+2);
460 imb();
461 r26 = (unsigned long) frame->retcode;
462 }
463
464 /* Check that everything was written properly. */
465 if (err)
466 goto give_sigsegv;
467
468 /* "Return" to the handler */
469 regs->r26 = r26;
470 regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
471 regs->r16 = sig; /* a0: signal number */
472 regs->r17 = 0; /* a1: exception code */
473 regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
474 wrusp((unsigned long) frame);
475
476#if DEBUG_SIG
477 printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
478 current->comm, current->pid, frame, regs->pc, regs->r26);
479#endif
480
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700481 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483give_sigsegv:
484 force_sigsegv(sig, current);
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700485 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700488static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
490 sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
491{
492 unsigned long oldsp, r26, err = 0;
493 struct rt_sigframe __user *frame;
494
495 oldsp = rdusp();
496 frame = get_sigframe(ka, oldsp, sizeof(*frame));
497 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
498 goto give_sigsegv;
499
500 err |= copy_siginfo_to_user(&frame->info, info);
501
502 /* Create the ucontext. */
503 err |= __put_user(0, &frame->uc.uc_flags);
504 err |= __put_user(0, &frame->uc.uc_link);
505 err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
506 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
507 err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags);
508 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
509 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw,
510 set->sig[0], oldsp);
511 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
512 if (err)
513 goto give_sigsegv;
514
515 /* Set up to return from userspace. If provided, use a stub
516 already in userspace. */
517 if (ka->ka_restorer) {
518 r26 = (unsigned long) ka->ka_restorer;
519 } else {
520 err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
521 err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
522 frame->retcode+1);
523 err |= __put_user(INSN_CALLSYS, frame->retcode+2);
524 imb();
525 r26 = (unsigned long) frame->retcode;
526 }
527
528 if (err)
529 goto give_sigsegv;
530
531 /* "Return" to the handler */
532 regs->r26 = r26;
533 regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
534 regs->r16 = sig; /* a0: signal number */
535 regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
536 regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */
537 wrusp((unsigned long) frame);
538
539#if DEBUG_SIG
540 printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
541 current->comm, current->pid, frame, regs->pc, regs->r26);
542#endif
543
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700544 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546give_sigsegv:
547 force_sigsegv(sig, current);
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700548 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
551
552/*
553 * OK, we're invoking a handler.
554 */
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700555static inline int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
557 sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
558{
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700559 int ret;
560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 if (ka->sa.sa_flags & SA_SIGINFO)
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700562 ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 else
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700564 ret = setup_frame(sig, ka, oldset, regs, sw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700566 if (ret == 0) {
567 spin_lock_irq(&current->sighand->siglock);
568 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
569 if (!(ka->sa.sa_flags & SA_NODEFER))
570 sigaddset(&current->blocked,sig);
571 recalc_sigpending();
572 spin_unlock_irq(&current->sighand->siglock);
573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700575 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576}
577
578static inline void
579syscall_restart(unsigned long r0, unsigned long r19,
580 struct pt_regs *regs, struct k_sigaction *ka)
581{
582 switch (regs->r0) {
583 case ERESTARTSYS:
584 if (!(ka->sa.sa_flags & SA_RESTART)) {
585 case ERESTARTNOHAND:
586 regs->r0 = EINTR;
587 break;
588 }
589 /* fallthrough */
590 case ERESTARTNOINTR:
591 regs->r0 = r0; /* reset v0 and a3 and replay syscall */
592 regs->r19 = r19;
593 regs->pc -= 4;
594 break;
595 case ERESTART_RESTARTBLOCK:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 regs->r0 = EINTR;
597 break;
598 }
599}
600
601
602/*
603 * Note that 'init' is a special process: it doesn't get signals it doesn't
604 * want to handle. Thus you cannot kill init even with a SIGKILL even by
605 * mistake.
606 *
607 * Note that we go through the signals twice: once to check the signals that
608 * the kernel can handle, and then we build all the user-level signal handling
609 * stack-frames in one go after that.
610 *
611 * "r0" and "r19" are the registers we need to restore for system call
612 * restart. "r0" is also used as an indicator whether we can restart at
613 * all (if we get here from anything but a syscall return, it will be 0)
614 */
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700615static void
616do_signal(struct pt_regs * regs, struct switch_stack * sw,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 unsigned long r0, unsigned long r19)
618{
619 siginfo_t info;
620 int signr;
621 unsigned long single_stepping = ptrace_cancel_bpt(current);
622 struct k_sigaction ka;
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700623 sigset_t *oldset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700625 if (test_thread_flag(TIF_RESTORE_SIGMASK))
626 oldset = &current->saved_sigmask;
627 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 oldset = &current->blocked;
629
630 /* This lets the debugger run, ... */
631 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 /* ... so re-check the single stepping. */
634 single_stepping |= ptrace_cancel_bpt(current);
635
636 if (signr > 0) {
637 /* Whee! Actually deliver the signal. */
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700638 if (r0)
639 syscall_restart(r0, r19, regs, &ka);
640 if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
641 /* A signal was successfully delivered, and the
642 saved sigmask was stored on the signal frame,
643 and will be restored by sigreturn. So we can
644 simply clear the restore sigmask flag. */
645 if (test_thread_flag(TIF_RESTORE_SIGMASK))
646 clear_thread_flag(TIF_RESTORE_SIGMASK);
647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 if (single_stepping)
649 ptrace_set_bpt(current); /* re-set bpt */
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700650 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
652
653 if (r0) {
654 switch (regs->r0) {
655 case ERESTARTNOHAND:
656 case ERESTARTSYS:
657 case ERESTARTNOINTR:
658 /* Reset v0 and a3 and replay syscall. */
659 regs->r0 = r0;
660 regs->r19 = r19;
661 regs->pc -= 4;
662 break;
663 case ERESTART_RESTARTBLOCK:
664 /* Force v0 to the restart syscall and reply. */
665 regs->r0 = __NR_restart_syscall;
666 regs->pc -= 4;
667 break;
668 }
669 }
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700670
671 /* If there's no signal to deliver, we just restore the saved mask. */
672 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
673 clear_thread_flag(TIF_RESTORE_SIGMASK);
674 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
675 }
676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (single_stepping)
678 ptrace_set_bpt(current); /* re-set breakpoint */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681void
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700682do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
683 unsigned long thread_info_flags,
684 unsigned long r0, unsigned long r19)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
Richard Hendersonb927b3e2007-05-29 16:03:28 -0700686 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
687 do_signal(regs, sw, r0, r19);
David Howellsd0420c82009-09-02 09:14:16 +0100688
689 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
690 clear_thread_flag(TIF_NOTIFY_RESUME);
691 tracehook_notify_resume(regs);
David Howellsee18d642009-09-02 09:14:21 +0100692 if (current->replacement_session_keyring)
693 key_replace_session_keyring();
David Howellsd0420c82009-09-02 09:14:16 +0100694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}