aboutsummaryrefslogtreecommitdiffstats
path: root/arch/cris
diff options
context:
space:
mode:
authorJesper Nilsson <jesper.nilsson@axis.com>2008-01-25 10:10:02 -0500
committerJesper Nilsson <jesper.nilsson@axis.com>2008-02-08 05:06:35 -0500
commit574852a2a5cb603708133ade9896c9bc77a68c46 (patch)
tree36159733de5d9a4d05ed1df6a3df3e427bf5eb48 /arch/cris
parent14e61bebb45acabcba2c3b7c4ff529fd646bd3f6 (diff)
CRIS v32: Update signal handling in kernel/signal.c
- do_signal now returns void, and does not have the previous signal set as a parameter. - Remove sys_rt_sigsuspend, we can use the common one instead. - Change sys_sigsuspend to be more like x86, don't call do_signal here. - handle_signal, setup_frame and setup_rt_frame now return -EFAULT if we've delivered a segfault, which is used by callers to perform necessary cleanup. - Break long lines, correct whitespace and formatting errors.
Diffstat (limited to 'arch/cris')
-rw-r--r--arch/cris/arch-v32/kernel/signal.c144
1 files changed, 56 insertions, 88 deletions
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index 024cc6901974..58c1866804e3 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -50,7 +50,7 @@ struct rt_signal_frame {
50 unsigned char retcode[8]; /* Trampoline code. */ 50 unsigned char retcode[8]; /* Trampoline code. */
51}; 51};
52 52
53int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs); 53void do_signal(int restart, struct pt_regs *regs);
54void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, 54void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
55 struct pt_regs *regs); 55 struct pt_regs *regs);
56/* 56/*
@@ -61,74 +61,16 @@ int
61sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, 61sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
62 long srp, struct pt_regs *regs) 62 long srp, struct pt_regs *regs)
63{ 63{
64 sigset_t saveset;
65
66 mask &= _BLOCKABLE; 64 mask &= _BLOCKABLE;
67
68 spin_lock_irq(&current->sighand->siglock); 65 spin_lock_irq(&current->sighand->siglock);
69 66 current->saved_sigmask = current->blocked;
70 saveset = current->blocked;
71
72 siginitset(&current->blocked, mask); 67 siginitset(&current->blocked, mask);
73
74 recalc_sigpending();
75 spin_unlock_irq(&current->sighand->siglock);
76
77 regs->r10 = -EINTR;
78
79 while (1) {
80 current->state = TASK_INTERRUPTIBLE;
81 schedule();
82
83 if (do_signal(0, &saveset, regs)) {
84 /*
85 * This point is reached twice: once to call
86 * the signal handler, then again to return
87 * from the sigsuspend system call. When
88 * calling the signal handler, R10 hold the
89 * signal number as set by do_signal(). The
90 * sigsuspend call will always return with
91 * the restored value above; -EINTR.
92 */
93 return regs->r10;
94 }
95 }
96}
97
98/* Define some dummy arguments to be able to reach the regs argument. */
99int
100sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13,
101 long mof, long srp, struct pt_regs *regs)
102{
103 sigset_t saveset;
104 sigset_t newset;
105
106 if (sigsetsize != sizeof(sigset_t))
107 return -EINVAL;
108
109 if (copy_from_user(&newset, unewset, sizeof(newset)))
110 return -EFAULT;
111
112 sigdelsetmask(&newset, ~_BLOCKABLE);
113 spin_lock_irq(&current->sighand->siglock);
114
115 saveset = current->blocked;
116 current->blocked = newset;
117
118 recalc_sigpending(); 68 recalc_sigpending();
119 spin_unlock_irq(&current->sighand->siglock); 69 spin_unlock_irq(&current->sighand->siglock);
120 70 current->state = TASK_INTERRUPTIBLE;
121 regs->r10 = -EINTR; 71 schedule();
122 72 set_thread_flag(TIF_RESTORE_SIGMASK);
123 while (1) { 73 return -ERESTARTNOHAND;
124 current->state = TASK_INTERRUPTIBLE;
125 schedule();
126
127 if (do_signal(0, &saveset, regs)) {
128 /* See comment in function above. */
129 return regs->r10;
130 }
131 }
132} 74}
133 75
134int 76int
@@ -290,7 +232,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
290 goto badframe; 232 goto badframe;
291 233
292 if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) 234 if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
293 goto badframe; 235 goto badframe;
294 236
295 keep_debug_flags(oldccs, oldspc, regs); 237 keep_debug_flags(oldccs, oldspc, regs);
296 238
@@ -347,11 +289,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
347/* Grab and setup a signal frame. 289/* Grab and setup a signal frame.
348 * 290 *
349 * Basically a lot of state-info is stacked, and arranged for the 291 * Basically a lot of state-info is stacked, and arranged for the
350 * user-mode program to return to the kernel using either a trampoline 292 * user-mode program to return to the kernel using either a trampiline
351 * which performs the syscall sigreturn(), or a provided user-mode 293 * which performs the syscall sigreturn(), or a provided user-mode
352 * trampoline. 294 * trampoline.
353 */ 295 */
354static void 296static int
355setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, 297setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
356 struct pt_regs * regs) 298 struct pt_regs * regs)
357{ 299{
@@ -417,16 +359,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
417 /* Actually move the USP to reflect the stacked frame. */ 359 /* Actually move the USP to reflect the stacked frame. */
418 wrusp((unsigned long)frame); 360 wrusp((unsigned long)frame);
419 361
420 return; 362 return 0;
421 363
422give_sigsegv: 364give_sigsegv:
423 if (sig == SIGSEGV) 365 if (sig == SIGSEGV)
424 ka->sa.sa_handler = SIG_DFL; 366 ka->sa.sa_handler = SIG_DFL;
425 367
426 force_sig(SIGSEGV, current); 368 force_sig(SIGSEGV, current);
369 return -EFAULT;
427} 370}
428 371
429static void 372static int
430setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 373setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
431 sigset_t *set, struct pt_regs * regs) 374 sigset_t *set, struct pt_regs * regs)
432{ 375{
@@ -503,21 +446,24 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
503 /* Actually move the usp to reflect the stacked frame. */ 446 /* Actually move the usp to reflect the stacked frame. */
504 wrusp((unsigned long)frame); 447 wrusp((unsigned long)frame);
505 448
506 return; 449 return 0;
507 450
508give_sigsegv: 451give_sigsegv:
509 if (sig == SIGSEGV) 452 if (sig == SIGSEGV)
510 ka->sa.sa_handler = SIG_DFL; 453 ka->sa.sa_handler = SIG_DFL;
511 454
512 force_sig(SIGSEGV, current); 455 force_sig(SIGSEGV, current);
456 return -EFAULT;
513} 457}
514 458
515/* Invoke a singal handler to, well, handle the signal. */ 459/* Invoke a singal handler to, well, handle the signal. */
516static inline void 460static inline int
517handle_signal(int canrestart, unsigned long sig, 461handle_signal(int canrestart, unsigned long sig,
518 siginfo_t *info, struct k_sigaction *ka, 462 siginfo_t *info, struct k_sigaction *ka,
519 sigset_t *oldset, struct pt_regs * regs) 463 sigset_t *oldset, struct pt_regs * regs)
520{ 464{
465 int ret;
466
521 /* Check if this got called from a system call. */ 467 /* Check if this got called from a system call. */
522 if (canrestart) { 468 if (canrestart) {
523 /* If so, check system call restarting. */ 469 /* If so, check system call restarting. */
@@ -561,19 +507,24 @@ handle_signal(int canrestart, unsigned long sig,
561 507
562 /* Set up the stack frame. */ 508 /* Set up the stack frame. */
563 if (ka->sa.sa_flags & SA_SIGINFO) 509 if (ka->sa.sa_flags & SA_SIGINFO)
564 setup_rt_frame(sig, ka, info, oldset, regs); 510 ret = setup_rt_frame(sig, ka, info, oldset, regs);
565 else 511 else
566 setup_frame(sig, ka, oldset, regs); 512 ret = setup_frame(sig, ka, oldset, regs);
567 513
568 if (ka->sa.sa_flags & SA_ONESHOT) 514 if (ka->sa.sa_flags & SA_ONESHOT)
569 ka->sa.sa_handler = SIG_DFL; 515 ka->sa.sa_handler = SIG_DFL;
570 516
571 spin_lock_irq(&current->sighand->siglock); 517 if (ret == 0) {
572 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 518 spin_lock_irq(&current->sighand->siglock);
573 if (!(ka->sa.sa_flags & SA_NODEFER)) 519 sigorsets(&current->blocked, &current->blocked,
574 sigaddset(&current->blocked,sig); 520 &ka->sa.sa_mask);
575 recalc_sigpending(); 521 if (!(ka->sa.sa_flags & SA_NODEFER))
576 spin_unlock_irq(&current->sighand->siglock); 522 sigaddset(&current->blocked, sig);
523 recalc_sigpending();
524 spin_unlock_irq(&current->sighand->siglock);
525 }
526
527 return ret;
577} 528}
578 529
579/* 530/*
@@ -587,12 +538,13 @@ handle_signal(int canrestart, unsigned long sig,
587 * we can use user_mode(regs) to see if we came directly from kernel or user 538 * we can use user_mode(regs) to see if we came directly from kernel or user
588 * mode below. 539 * mode below.
589 */ 540 */
590int 541void
591do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) 542do_signal(int canrestart, struct pt_regs *regs)
592{ 543{
593 int signr; 544 int signr;
594 siginfo_t info; 545 siginfo_t info;
595 struct k_sigaction ka; 546 struct k_sigaction ka;
547 sigset_t *oldset;
596 548
597 /* 549 /*
598 * The common case should go fast, which is why this point is 550 * The common case should go fast, which is why this point is
@@ -600,17 +552,28 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
600 * without doing anything. 552 * without doing anything.
601 */ 553 */
602 if (!user_mode(regs)) 554 if (!user_mode(regs))
603 return 1; 555 return;
604 556
605 if (!oldset) 557 if (test_thread_flag(TIF_RESTORE_SIGMASK))
558 oldset = &current->saved_sigmask;
559 else
606 oldset = &current->blocked; 560 oldset = &current->blocked;
607 561
608 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 562 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
609 563
610 if (signr > 0) { 564 if (signr > 0) {
611 /* Deliver the signal. */ 565 /* Whee! Actually deliver the signal. */
612 handle_signal(canrestart, signr, &info, &ka, oldset, regs); 566 if (handle_signal(canrestart, signr, &info, &ka,
613 return 1; 567 oldset, regs)) {
568 /* a signal was successfully delivered; the saved
569 * sigmask will have been stored in the signal frame,
570 * and will be restored by sigreturn, so we can simply
571 * clear the TIF_RESTORE_SIGMASK flag */
572 if (test_thread_flag(TIF_RESTORE_SIGMASK))
573 clear_thread_flag(TIF_RESTORE_SIGMASK);
574 }
575
576 return;
614 } 577 }
615 578
616 /* Got here from a system call? */ 579 /* Got here from a system call? */
@@ -628,7 +591,12 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
628 } 591 }
629 } 592 }
630 593
631 return 0; 594 /* if there's no signal to deliver, we just put the saved sigmask
595 * back */
596 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
597 clear_thread_flag(TIF_RESTORE_SIGMASK);
598 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
599 }
632} 600}
633 601
634asmlinkage void 602asmlinkage void
@@ -641,7 +609,7 @@ ugdb_trap_user(struct thread_info *ti, int sig)
641 user_regs(ti)->spc = 0; 609 user_regs(ti)->spc = 0;
642 } 610 }
643 /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA 611 /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
644 not within any configured h/w breakpoint range). Synchronize with 612 not withing any configured h/w breakpoint range). Synchronize with
645 what already exists for kernel debugging. */ 613 what already exists for kernel debugging. */
646 if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { 614 if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
647 /* Break 8: subtract 2 from ERP unless in a delay slot. */ 615 /* Break 8: subtract 2 from ERP unless in a delay slot. */