diff options
Diffstat (limited to 'arch/sh/kernel/signal.c')
-rw-r--r-- | arch/sh/kernel/signal.c | 158 |
1 files changed, 83 insertions, 75 deletions
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index b475c4d2405f..5213f5bc6ce0 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima | 8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | |||
12 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
13 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
14 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
@@ -21,6 +20,7 @@ | |||
21 | #include <linux/unistd.h> | 20 | #include <linux/unistd.h> |
22 | #include <linux/stddef.h> | 21 | #include <linux/stddef.h> |
23 | #include <linux/tty.h> | 22 | #include <linux/tty.h> |
23 | #include <linux/elf.h> | ||
24 | #include <linux/personality.h> | 24 | #include <linux/personality.h> |
25 | #include <linux/binfmts.h> | 25 | #include <linux/binfmts.h> |
26 | 26 | ||
@@ -29,12 +29,8 @@ | |||
29 | #include <asm/pgtable.h> | 29 | #include <asm/pgtable.h> |
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | 31 | ||
32 | #define DEBUG_SIG 0 | ||
33 | |||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 32 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
35 | 33 | ||
36 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | ||
37 | |||
38 | /* | 34 | /* |
39 | * Atomically swap in the new signal mask, and wait for a signal. | 35 | * Atomically swap in the new signal mask, and wait for a signal. |
40 | */ | 36 | */ |
@@ -43,51 +39,17 @@ sys_sigsuspend(old_sigset_t mask, | |||
43 | unsigned long r5, unsigned long r6, unsigned long r7, | 39 | unsigned long r5, unsigned long r6, unsigned long r7, |
44 | struct pt_regs regs) | 40 | struct pt_regs regs) |
45 | { | 41 | { |
46 | sigset_t saveset; | ||
47 | |||
48 | mask &= _BLOCKABLE; | 42 | mask &= _BLOCKABLE; |
49 | spin_lock_irq(¤t->sighand->siglock); | 43 | spin_lock_irq(¤t->sighand->siglock); |
50 | saveset = current->blocked; | 44 | current->saved_sigmask = current->blocked; |
51 | siginitset(¤t->blocked, mask); | 45 | siginitset(¤t->blocked, mask); |
52 | recalc_sigpending(); | 46 | recalc_sigpending(); |
53 | spin_unlock_irq(¤t->sighand->siglock); | 47 | spin_unlock_irq(¤t->sighand->siglock); |
54 | 48 | ||
55 | regs.regs[0] = -EINTR; | 49 | current->state = TASK_INTERRUPTIBLE; |
56 | while (1) { | 50 | schedule(); |
57 | current->state = TASK_INTERRUPTIBLE; | 51 | set_thread_flag(TIF_RESTORE_SIGMASK); |
58 | schedule(); | 52 | return -ERESTARTNOHAND; |
59 | if (do_signal(®s, &saveset)) | ||
60 | return -EINTR; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | asmlinkage int | ||
65 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, | ||
66 | unsigned long r6, unsigned long r7, | ||
67 | struct pt_regs regs) | ||
68 | { | ||
69 | sigset_t saveset, newset; | ||
70 | |||
71 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
72 | if (sigsetsize != sizeof(sigset_t)) | ||
73 | return -EINVAL; | ||
74 | |||
75 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
76 | return -EFAULT; | ||
77 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
78 | spin_lock_irq(¤t->sighand->siglock); | ||
79 | saveset = current->blocked; | ||
80 | current->blocked = newset; | ||
81 | recalc_sigpending(); | ||
82 | spin_unlock_irq(¤t->sighand->siglock); | ||
83 | |||
84 | regs.regs[0] = -EINTR; | ||
85 | while (1) { | ||
86 | current->state = TASK_INTERRUPTIBLE; | ||
87 | schedule(); | ||
88 | if (do_signal(®s, &saveset)) | ||
89 | return -EINTR; | ||
90 | } | ||
91 | } | 53 | } |
92 | 54 | ||
93 | asmlinkage int | 55 | asmlinkage int |
@@ -348,7 +310,12 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
348 | return (void __user *)((sp - frame_size) & -8ul); | 310 | return (void __user *)((sp - frame_size) & -8ul); |
349 | } | 311 | } |
350 | 312 | ||
351 | static void setup_frame(int sig, struct k_sigaction *ka, | 313 | /* These symbols are defined with the addresses in the vsyscall page. |
314 | See vsyscall-trapa.S. */ | ||
315 | extern void __user __kernel_sigreturn; | ||
316 | extern void __user __kernel_rt_sigreturn; | ||
317 | |||
318 | static int setup_frame(int sig, struct k_sigaction *ka, | ||
352 | sigset_t *set, struct pt_regs *regs) | 319 | sigset_t *set, struct pt_regs *regs) |
353 | { | 320 | { |
354 | struct sigframe __user *frame; | 321 | struct sigframe __user *frame; |
@@ -368,15 +335,18 @@ static void setup_frame(int sig, struct k_sigaction *ka, | |||
368 | 335 | ||
369 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | 336 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
370 | 337 | ||
371 | if (_NSIG_WORDS > 1) { | 338 | if (_NSIG_WORDS > 1) |
372 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 339 | err |= __copy_to_user(frame->extramask, &set->sig[1], |
373 | sizeof(frame->extramask)); | 340 | sizeof(frame->extramask)); |
374 | } | ||
375 | 341 | ||
376 | /* Set up to return from userspace. If provided, use a stub | 342 | /* Set up to return from userspace. If provided, use a stub |
377 | already in userspace. */ | 343 | already in userspace. */ |
378 | if (ka->sa.sa_flags & SA_RESTORER) { | 344 | if (ka->sa.sa_flags & SA_RESTORER) { |
379 | regs->pr = (unsigned long) ka->sa.sa_restorer; | 345 | regs->pr = (unsigned long) ka->sa.sa_restorer; |
346 | #ifdef CONFIG_VSYSCALL | ||
347 | } else if (likely(current->mm->context.vdso)) { | ||
348 | regs->pr = VDSO_SYM(&__kernel_sigreturn); | ||
349 | #endif | ||
380 | } else { | 350 | } else { |
381 | /* Generate return code (system call to sigreturn) */ | 351 | /* Generate return code (system call to sigreturn) */ |
382 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 352 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
@@ -402,21 +372,22 @@ static void setup_frame(int sig, struct k_sigaction *ka, | |||
402 | 372 | ||
403 | set_fs(USER_DS); | 373 | set_fs(USER_DS); |
404 | 374 | ||
405 | #if DEBUG_SIG | 375 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
406 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 376 | current->comm, current->pid, frame, regs->pc, regs->pr); |
407 | current->comm, current->pid, frame, regs->pc, regs->pr); | ||
408 | #endif | ||
409 | 377 | ||
410 | flush_cache_sigtramp(regs->pr); | 378 | flush_cache_sigtramp(regs->pr); |
379 | |||
411 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) | 380 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) |
412 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); | 381 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); |
413 | return; | 382 | |
383 | return 0; | ||
414 | 384 | ||
415 | give_sigsegv: | 385 | give_sigsegv: |
416 | force_sigsegv(sig, current); | 386 | force_sigsegv(sig, current); |
387 | return -EFAULT; | ||
417 | } | 388 | } |
418 | 389 | ||
419 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 390 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
420 | sigset_t *set, struct pt_regs *regs) | 391 | sigset_t *set, struct pt_regs *regs) |
421 | { | 392 | { |
422 | struct rt_sigframe __user *frame; | 393 | struct rt_sigframe __user *frame; |
@@ -452,6 +423,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
452 | already in userspace. */ | 423 | already in userspace. */ |
453 | if (ka->sa.sa_flags & SA_RESTORER) { | 424 | if (ka->sa.sa_flags & SA_RESTORER) { |
454 | regs->pr = (unsigned long) ka->sa.sa_restorer; | 425 | regs->pr = (unsigned long) ka->sa.sa_restorer; |
426 | #ifdef CONFIG_VSYSCALL | ||
427 | } else if (likely(current->mm->context.vdso)) { | ||
428 | regs->pr = VDSO_SYM(&__kernel_rt_sigreturn); | ||
429 | #endif | ||
455 | } else { | 430 | } else { |
456 | /* Generate return code (system call to rt_sigreturn) */ | 431 | /* Generate return code (system call to rt_sigreturn) */ |
457 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 432 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
@@ -477,28 +452,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
477 | 452 | ||
478 | set_fs(USER_DS); | 453 | set_fs(USER_DS); |
479 | 454 | ||
480 | #if DEBUG_SIG | 455 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
481 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 456 | current->comm, current->pid, frame, regs->pc, regs->pr); |
482 | current->comm, current->pid, frame, regs->pc, regs->pr); | ||
483 | #endif | ||
484 | 457 | ||
485 | flush_cache_sigtramp(regs->pr); | 458 | flush_cache_sigtramp(regs->pr); |
459 | |||
486 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) | 460 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) |
487 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); | 461 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); |
488 | return; | 462 | |
463 | return 0; | ||
489 | 464 | ||
490 | give_sigsegv: | 465 | give_sigsegv: |
491 | force_sigsegv(sig, current); | 466 | force_sigsegv(sig, current); |
467 | return -EFAULT; | ||
492 | } | 468 | } |
493 | 469 | ||
494 | /* | 470 | /* |
495 | * OK, we're invoking a handler | 471 | * OK, we're invoking a handler |
496 | */ | 472 | */ |
497 | 473 | ||
498 | static void | 474 | static int |
499 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 475 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, |
500 | sigset_t *oldset, struct pt_regs *regs) | 476 | sigset_t *oldset, struct pt_regs *regs) |
501 | { | 477 | { |
478 | int ret; | ||
479 | |||
502 | /* Are we from a system call? */ | 480 | /* Are we from a system call? */ |
503 | if (regs->tra >= 0) { | 481 | if (regs->tra >= 0) { |
504 | /* If so, check system call restarting.. */ | 482 | /* If so, check system call restarting.. */ |
@@ -539,19 +517,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
539 | 517 | ||
540 | /* Set up the stack frame */ | 518 | /* Set up the stack frame */ |
541 | if (ka->sa.sa_flags & SA_SIGINFO) | 519 | if (ka->sa.sa_flags & SA_SIGINFO) |
542 | setup_rt_frame(sig, ka, info, oldset, regs); | 520 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
543 | else | 521 | else |
544 | setup_frame(sig, ka, oldset, regs); | 522 | ret = setup_frame(sig, ka, oldset, regs); |
545 | 523 | ||
546 | if (ka->sa.sa_flags & SA_ONESHOT) | 524 | if (ka->sa.sa_flags & SA_ONESHOT) |
547 | ka->sa.sa_handler = SIG_DFL; | 525 | ka->sa.sa_handler = SIG_DFL; |
548 | 526 | ||
549 | spin_lock_irq(¤t->sighand->siglock); | 527 | if (ret == 0) { |
550 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 528 | spin_lock_irq(¤t->sighand->siglock); |
551 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 529 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
552 | sigaddset(¤t->blocked,sig); | 530 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
553 | recalc_sigpending(); | 531 | sigaddset(¤t->blocked,sig); |
554 | spin_unlock_irq(¤t->sighand->siglock); | 532 | recalc_sigpending(); |
533 | spin_unlock_irq(¤t->sighand->siglock); | ||
534 | } | ||
535 | |||
536 | return ret; | ||
555 | } | 537 | } |
556 | 538 | ||
557 | /* | 539 | /* |
@@ -563,11 +545,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
563 | * the kernel can handle, and then we build all the user-level signal handling | 545 | * the kernel can handle, and then we build all the user-level signal handling |
564 | * stack-frames in one go after that. | 546 | * stack-frames in one go after that. |
565 | */ | 547 | */ |
566 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 548 | static void do_signal(struct pt_regs *regs, unsigned int save_r0) |
567 | { | 549 | { |
568 | siginfo_t info; | 550 | siginfo_t info; |
569 | int signr; | 551 | int signr; |
570 | struct k_sigaction ka; | 552 | struct k_sigaction ka; |
553 | sigset_t *oldset; | ||
571 | 554 | ||
572 | /* | 555 | /* |
573 | * We want the common case to go fast, which | 556 | * We want the common case to go fast, which |
@@ -576,19 +559,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
576 | * if so. | 559 | * if so. |
577 | */ | 560 | */ |
578 | if (!user_mode(regs)) | 561 | if (!user_mode(regs)) |
579 | return 1; | 562 | return; |
580 | 563 | ||
581 | if (try_to_freeze()) | 564 | if (try_to_freeze()) |
582 | goto no_signal; | 565 | goto no_signal; |
583 | 566 | ||
584 | if (!oldset) | 567 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
568 | oldset = ¤t->saved_sigmask; | ||
569 | else | ||
585 | oldset = ¤t->blocked; | 570 | oldset = ¤t->blocked; |
586 | 571 | ||
587 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 572 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
588 | if (signr > 0) { | 573 | if (signr > 0) { |
589 | /* Whee! Actually deliver the signal. */ | 574 | /* Whee! Actually deliver the signal. */ |
590 | handle_signal(signr, &ka, &info, oldset, regs); | 575 | if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { |
591 | return 1; | 576 | /* a signal was successfully delivered; the saved |
577 | * sigmask will have been stored in the signal frame, | ||
578 | * and will be restored by sigreturn, so we can simply | ||
579 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
580 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
581 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
582 | } | ||
592 | } | 583 | } |
593 | 584 | ||
594 | no_signal: | 585 | no_signal: |
@@ -597,10 +588,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
597 | /* Restart the system call - no handlers present */ | 588 | /* Restart the system call - no handlers present */ |
598 | if (regs->regs[0] == -ERESTARTNOHAND || | 589 | if (regs->regs[0] == -ERESTARTNOHAND || |
599 | regs->regs[0] == -ERESTARTSYS || | 590 | regs->regs[0] == -ERESTARTSYS || |
600 | regs->regs[0] == -ERESTARTNOINTR || | 591 | regs->regs[0] == -ERESTARTNOINTR) { |
601 | regs->regs[0] == -ERESTART_RESTARTBLOCK) { | 592 | regs->regs[0] = save_r0; |
593 | regs->pc -= 2; | ||
594 | } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { | ||
602 | regs->pc -= 2; | 595 | regs->pc -= 2; |
596 | regs->regs[3] = __NR_restart_syscall; | ||
603 | } | 597 | } |
604 | } | 598 | } |
605 | return 0; | 599 | |
600 | /* if there's no signal to deliver, we just put the saved sigmask | ||
601 | * back */ | ||
602 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
603 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
604 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, | ||
609 | __u32 thread_info_flags) | ||
610 | { | ||
611 | /* deal with pending signal delivery */ | ||
612 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | ||
613 | do_signal(regs, save_r0); | ||
606 | } | 614 | } |