diff options
Diffstat (limited to 'arch/cris')
-rw-r--r-- | arch/cris/arch-v32/kernel/signal.c | 144 |
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 | ||
53 | int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs); | 53 | void do_signal(int restart, struct pt_regs *regs); |
54 | void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, | 54 | void 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 | |||
61 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, | 61 | sys_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(¤t->sighand->siglock); | 65 | spin_lock_irq(¤t->sighand->siglock); |
69 | 66 | current->saved_sigmask = current->blocked; | |
70 | saveset = current->blocked; | ||
71 | |||
72 | siginitset(¤t->blocked, mask); | 67 | siginitset(¤t->blocked, mask); |
73 | |||
74 | recalc_sigpending(); | ||
75 | spin_unlock_irq(¤t->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. */ | ||
99 | int | ||
100 | sys_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(¤t->sighand->siglock); | ||
114 | |||
115 | saveset = current->blocked; | ||
116 | current->blocked = newset; | ||
117 | |||
118 | recalc_sigpending(); | 68 | recalc_sigpending(); |
119 | spin_unlock_irq(¤t->sighand->siglock); | 69 | spin_unlock_irq(¤t->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 | ||
134 | int | 76 | int |
@@ -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 | */ |
354 | static void | 296 | static int |
355 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 297 | setup_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 | ||
422 | give_sigsegv: | 364 | give_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 | ||
429 | static void | 372 | static int |
430 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 373 | setup_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 | ||
508 | give_sigsegv: | 451 | give_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. */ |
516 | static inline void | 460 | static inline int |
517 | handle_signal(int canrestart, unsigned long sig, | 461 | handle_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(¤t->sighand->siglock); | 517 | if (ret == 0) { |
572 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 518 | spin_lock_irq(¤t->sighand->siglock); |
573 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 519 | sigorsets(¤t->blocked, ¤t->blocked, |
574 | sigaddset(¤t->blocked,sig); | 520 | &ka->sa.sa_mask); |
575 | recalc_sigpending(); | 521 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
576 | spin_unlock_irq(¤t->sighand->siglock); | 522 | sigaddset(¤t->blocked, sig); |
523 | recalc_sigpending(); | ||
524 | spin_unlock_irq(¤t->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 | */ |
590 | int | 541 | void |
591 | do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | 542 | do_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 = ¤t->saved_sigmask; | ||
559 | else | ||
606 | oldset = ¤t->blocked; | 560 | oldset = ¤t->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, ¤t->saved_sigmask, NULL); | ||
599 | } | ||
632 | } | 600 | } |
633 | 601 | ||
634 | asmlinkage void | 602 | asmlinkage 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. */ |