aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/frv/kernel/signal.c')
-rw-r--r--arch/frv/kernel/signal.c111
1 files changed, 90 insertions, 21 deletions
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 535810a3217..bab01298b58 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -20,6 +20,7 @@
20#include <linux/ptrace.h> 20#include <linux/ptrace.h>
21#include <linux/unistd.h> 21#include <linux/unistd.h>
22#include <linux/personality.h> 22#include <linux/personality.h>
23#include <linux/freezer.h>
23#include <linux/tracehook.h> 24#include <linux/tracehook.h>
24#include <asm/ucontext.h> 25#include <asm/ucontext.h>
25#include <asm/uaccess.h> 26#include <asm/uaccess.h>
@@ -27,6 +28,8 @@
27 28
28#define DEBUG_SIG 0 29#define DEBUG_SIG 0
29 30
31#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
32
30struct fdpic_func_descriptor { 33struct fdpic_func_descriptor {
31 unsigned long text; 34 unsigned long text;
32 unsigned long GOT; 35 unsigned long GOT;
@@ -37,9 +40,17 @@ struct fdpic_func_descriptor {
37 */ 40 */
38asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) 41asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
39{ 42{
40 sigset_t blocked; 43 mask &= _BLOCKABLE;
41 siginitset(&blocked, mask); 44 spin_lock_irq(&current->sighand->siglock);
42 return sigsuspend(&blocked); 45 current->saved_sigmask = current->blocked;
46 siginitset(&current->blocked, mask);
47 recalc_sigpending();
48 spin_unlock_irq(&current->sighand->siglock);
49
50 current->state = TASK_INTERRUPTIBLE;
51 schedule();
52 set_thread_flag(TIF_RESTORE_SIGMASK);
53 return -ERESTARTNOHAND;
43} 54}
44 55
45asmlinkage int sys_sigaction(int sig, 56asmlinkage int sys_sigaction(int sig,
@@ -53,10 +64,10 @@ asmlinkage int sys_sigaction(int sig,
53 old_sigset_t mask; 64 old_sigset_t mask;
54 if (!access_ok(VERIFY_READ, act, sizeof(*act)) || 65 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
55 __get_user(new_ka.sa.sa_handler, &act->sa_handler) || 66 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
56 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || 67 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
57 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
58 __get_user(mask, &act->sa_mask))
59 return -EFAULT; 68 return -EFAULT;
69 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
70 __get_user(mask, &act->sa_mask);
60 siginitset(&new_ka.sa.sa_mask, mask); 71 siginitset(&new_ka.sa.sa_mask, mask);
61 } 72 }
62 73
@@ -65,10 +76,10 @@ asmlinkage int sys_sigaction(int sig,
65 if (!ret && oact) { 76 if (!ret && oact) {
66 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || 77 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
67 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || 78 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
68 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || 79 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
69 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
70 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
71 return -EFAULT; 80 return -EFAULT;
81 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
82 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
72 } 83 }
73 84
74 return ret; 85 return ret;
@@ -146,7 +157,11 @@ asmlinkage int sys_sigreturn(void)
146 __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) 157 __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))
147 goto badframe; 158 goto badframe;
148 159
149 set_current_blocked(&set); 160 sigdelsetmask(&set, ~_BLOCKABLE);
161 spin_lock_irq(&current->sighand->siglock);
162 current->blocked = set;
163 recalc_sigpending();
164 spin_unlock_irq(&current->sighand->siglock);
150 165
151 if (restore_sigcontext(&frame->sc, &gr8)) 166 if (restore_sigcontext(&frame->sc, &gr8))
152 goto badframe; 167 goto badframe;
@@ -168,7 +183,11 @@ asmlinkage int sys_rt_sigreturn(void)
168 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 183 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
169 goto badframe; 184 goto badframe;
170 185
171 set_current_blocked(&set); 186 sigdelsetmask(&set, ~_BLOCKABLE);
187 spin_lock_irq(&current->sighand->siglock);
188 current->blocked = set;
189 recalc_sigpending();
190 spin_unlock_irq(&current->sighand->siglock);
172 191
173 if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) 192 if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8))
174 goto badframe; 193 goto badframe;
@@ -297,6 +316,10 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set)
297 __frame->lr = (unsigned long) &frame->retcode; 316 __frame->lr = (unsigned long) &frame->retcode;
298 __frame->gr8 = sig; 317 __frame->gr8 = sig;
299 318
319 /* the tracer may want to single-step inside the handler */
320 if (test_thread_flag(TIF_SINGLESTEP))
321 ptrace_notify(SIGTRAP);
322
300#if DEBUG_SIG 323#if DEBUG_SIG
301 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", 324 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
302 sig, current->comm, current->pid, frame, __frame->pc, 325 sig, current->comm, current->pid, frame, __frame->pc,
@@ -395,6 +418,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
395 __frame->gr8 = sig; 418 __frame->gr8 = sig;
396 __frame->gr9 = (unsigned long) &frame->info; 419 __frame->gr9 = (unsigned long) &frame->info;
397 420
421 /* the tracer may want to single-step inside the handler */
422 if (test_thread_flag(TIF_SINGLESTEP))
423 ptrace_notify(SIGTRAP);
424
398#if DEBUG_SIG 425#if DEBUG_SIG
399 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", 426 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
400 sig, current->comm, current->pid, frame, __frame->pc, 427 sig, current->comm, current->pid, frame, __frame->pc,
@@ -413,10 +440,9 @@ give_sigsegv:
413/* 440/*
414 * OK, we're invoking a handler 441 * OK, we're invoking a handler
415 */ 442 */
416static void handle_signal(unsigned long sig, siginfo_t *info, 443static int handle_signal(unsigned long sig, siginfo_t *info,
417 struct k_sigaction *ka) 444 struct k_sigaction *ka, sigset_t *oldset)
418{ 445{
419 sigset_t *oldset = sigmask_to_save();
420 int ret; 446 int ret;
421 447
422 /* Are we from a system call? */ 448 /* Are we from a system call? */
@@ -448,11 +474,18 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
448 else 474 else
449 ret = setup_frame(sig, ka, oldset); 475 ret = setup_frame(sig, ka, oldset);
450 476
451 if (ret) 477 if (ret == 0) {
452 return; 478 spin_lock_irq(&current->sighand->siglock);
479 sigorsets(&current->blocked, &current->blocked,
480 &ka->sa.sa_mask);
481 if (!(ka->sa.sa_flags & SA_NODEFER))
482 sigaddset(&current->blocked, sig);
483 recalc_sigpending();
484 spin_unlock_irq(&current->sighand->siglock);
485 }
486
487 return ret;
453 488
454 signal_delivered(sig, info, ka, __frame,
455 test_thread_flag(TIF_SINGLESTEP));
456} /* end handle_signal() */ 489} /* end handle_signal() */
457 490
458/*****************************************************************************/ 491/*****************************************************************************/
@@ -465,14 +498,44 @@ static void do_signal(void)
465{ 498{
466 struct k_sigaction ka; 499 struct k_sigaction ka;
467 siginfo_t info; 500 siginfo_t info;
501 sigset_t *oldset;
468 int signr; 502 int signr;
469 503
504 /*
505 * We want the common case to go fast, which
506 * is why we may in certain cases get here from
507 * kernel mode. Just return without doing anything
508 * if so.
509 */
510 if (!user_mode(__frame))
511 return;
512
513 if (try_to_freeze())
514 goto no_signal;
515
516 if (test_thread_flag(TIF_RESTORE_SIGMASK))
517 oldset = &current->saved_sigmask;
518 else
519 oldset = &current->blocked;
520
470 signr = get_signal_to_deliver(&info, &ka, __frame, NULL); 521 signr = get_signal_to_deliver(&info, &ka, __frame, NULL);
471 if (signr > 0) { 522 if (signr > 0) {
472 handle_signal(signr, &info, &ka); 523 if (handle_signal(signr, &info, &ka, oldset) == 0) {
524 /* a signal was successfully delivered; the saved
525 * sigmask will have been stored in the signal frame,
526 * and will be restored by sigreturn, so we can simply
527 * clear the TIF_RESTORE_SIGMASK flag */
528 if (test_thread_flag(TIF_RESTORE_SIGMASK))
529 clear_thread_flag(TIF_RESTORE_SIGMASK);
530
531 tracehook_signal_handler(signr, &info, &ka, __frame,
532 test_thread_flag(TIF_SINGLESTEP));
533 }
534
473 return; 535 return;
474 } 536 }
475 537
538no_signal:
476 /* Did we come from a system call? */ 539 /* Did we come from a system call? */
477 if (__frame->syscallno != -1) { 540 if (__frame->syscallno != -1) {
478 /* Restart the system call - no handlers present */ 541 /* Restart the system call - no handlers present */
@@ -494,7 +557,11 @@ static void do_signal(void)
494 557
495 /* if there's no signal to deliver, we just put the saved sigmask 558 /* if there's no signal to deliver, we just put the saved sigmask
496 * back */ 559 * back */
497 restore_saved_sigmask(); 560 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
561 clear_thread_flag(TIF_RESTORE_SIGMASK);
562 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
563 }
564
498} /* end do_signal() */ 565} /* end do_signal() */
499 566
500/*****************************************************************************/ 567/*****************************************************************************/
@@ -509,13 +576,15 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
509 clear_thread_flag(TIF_SINGLESTEP); 576 clear_thread_flag(TIF_SINGLESTEP);
510 577
511 /* deal with pending signal delivery */ 578 /* deal with pending signal delivery */
512 if (thread_info_flags & _TIF_SIGPENDING) 579 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
513 do_signal(); 580 do_signal();
514 581
515 /* deal with notification on about to resume userspace execution */ 582 /* deal with notification on about to resume userspace execution */
516 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 583 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
517 clear_thread_flag(TIF_NOTIFY_RESUME); 584 clear_thread_flag(TIF_NOTIFY_RESUME);
518 tracehook_notify_resume(__frame); 585 tracehook_notify_resume(__frame);
586 if (current->replacement_session_keyring)
587 key_replace_session_keyring();
519 } 588 }
520 589
521} /* end do_notify_resume() */ 590} /* end do_notify_resume() */