diff options
-rw-r--r-- | arch/powerpc/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.c | 65 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.h | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 28 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 59 |
5 files changed, 94 insertions, 77 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 08ce7de7c768..eb6a33e90d7e 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -12,7 +12,8 @@ endif | |||
12 | 12 | ||
13 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ | 13 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ |
14 | irq.o align.o signal_32.o pmc.o vdso.o \ | 14 | irq.o align.o signal_32.o pmc.o vdso.o \ |
15 | init_task.o process.o systbl.o idle.o | 15 | init_task.o process.o systbl.o idle.o \ |
16 | signal.o | ||
16 | obj-y += vdso32/ | 17 | obj-y += vdso32/ |
17 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ | 18 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ |
18 | signal_64.o ptrace32.o \ | 19 | signal_64.o ptrace32.o \ |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c new file mode 100644 index 000000000000..88a12544e8b1 --- /dev/null +++ b/arch/powerpc/kernel/signal.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Common signal handling code for both 32 and 64 bits | ||
3 | * | ||
4 | * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration | ||
5 | * Extracted from signal_32.c and signal_64.c | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file README.legal in the main directory of | ||
9 | * this archive for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/signal.h> | ||
14 | #include <asm/unistd.h> | ||
15 | |||
16 | void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, | ||
17 | int has_handler) | ||
18 | { | ||
19 | unsigned long ret = regs->gpr[3]; | ||
20 | int restart = 1; | ||
21 | |||
22 | /* syscall ? */ | ||
23 | if (TRAP(regs) != 0x0C00) | ||
24 | return; | ||
25 | |||
26 | /* error signalled ? */ | ||
27 | if (!(regs->ccr & 0x10000000)) | ||
28 | return; | ||
29 | |||
30 | switch (ret) { | ||
31 | case ERESTART_RESTARTBLOCK: | ||
32 | case ERESTARTNOHAND: | ||
33 | /* ERESTARTNOHAND means that the syscall should only be | ||
34 | * restarted if there was no handler for the signal, and since | ||
35 | * we only get here if there is a handler, we dont restart. | ||
36 | */ | ||
37 | restart = !has_handler; | ||
38 | break; | ||
39 | case ERESTARTSYS: | ||
40 | /* ERESTARTSYS means to restart the syscall if there is no | ||
41 | * handler or the handler was registered with SA_RESTART | ||
42 | */ | ||
43 | restart = !has_handler || (ka->sa.sa_flags & SA_RESTART) != 0; | ||
44 | break; | ||
45 | case ERESTARTNOINTR: | ||
46 | /* ERESTARTNOINTR means that the syscall should be | ||
47 | * called again after the signal handler returns. | ||
48 | */ | ||
49 | break; | ||
50 | default: | ||
51 | return; | ||
52 | } | ||
53 | if (restart) { | ||
54 | if (ret == ERESTART_RESTARTBLOCK) | ||
55 | regs->gpr[0] = __NR_restart_syscall; | ||
56 | else | ||
57 | regs->gpr[3] = regs->orig_gpr3; | ||
58 | regs->nip -= 4; | ||
59 | regs->result = 0; | ||
60 | } else { | ||
61 | regs->result = -EINTR; | ||
62 | regs->gpr[3] = EINTR; | ||
63 | regs->ccr |= 0x10000000; | ||
64 | } | ||
65 | } | ||
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h new file mode 100644 index 000000000000..1e8dfb8620ad --- /dev/null +++ b/arch/powerpc/kernel/signal.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration | ||
3 | * Extracted from signal_32.c and signal_64.c | ||
4 | * | ||
5 | * This file is subject to the terms and conditions of the GNU General | ||
6 | * Public License. See the file README.legal in the main directory of | ||
7 | * this archive for more details. | ||
8 | */ | ||
9 | |||
10 | #ifndef _POWERPC_ARCH_SIGNAL_H | ||
11 | #define _POWERPC_ARCH_SIGNAL_H | ||
12 | |||
13 | extern void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, | ||
14 | int has_handler); | ||
15 | |||
16 | #endif /* _POWERPC_ARCH_SIGNAL_H */ | ||
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index dd1dca5bfa81..e5cc803476a1 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -51,6 +51,8 @@ | |||
51 | #include <asm/pgtable.h> | 51 | #include <asm/pgtable.h> |
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | #include "signal.h" | ||
55 | |||
54 | #undef DEBUG_SIG | 56 | #undef DEBUG_SIG |
55 | 57 | ||
56 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 58 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -1156,30 +1158,8 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
1156 | #ifdef CONFIG_PPC32 | 1158 | #ifdef CONFIG_PPC32 |
1157 | no_signal: | 1159 | no_signal: |
1158 | #endif | 1160 | #endif |
1159 | if (TRAP(regs) == 0x0C00 /* System Call! */ | 1161 | /* Is there any syscall restart business here ? */ |
1160 | && regs->ccr & 0x10000000 /* error signalled */ | 1162 | check_syscall_restart(regs, &ka, signr > 0); |
1161 | && ((ret = regs->gpr[3]) == ERESTARTSYS | ||
1162 | || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR | ||
1163 | || ret == ERESTART_RESTARTBLOCK)) { | ||
1164 | |||
1165 | if (signr > 0 | ||
1166 | && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK | ||
1167 | || (ret == ERESTARTSYS | ||
1168 | && !(ka.sa.sa_flags & SA_RESTART)))) { | ||
1169 | /* make the system call return an EINTR error */ | ||
1170 | regs->result = -EINTR; | ||
1171 | regs->gpr[3] = EINTR; | ||
1172 | /* note that the cr0.SO bit is already set */ | ||
1173 | } else { | ||
1174 | regs->nip -= 4; /* Back up & retry system call */ | ||
1175 | regs->result = 0; | ||
1176 | regs->trap = 0; | ||
1177 | if (ret == ERESTART_RESTARTBLOCK) | ||
1178 | regs->gpr[0] = __NR_restart_syscall; | ||
1179 | else | ||
1180 | regs->gpr[3] = regs->orig_gpr3; | ||
1181 | } | ||
1182 | } | ||
1183 | 1163 | ||
1184 | if (signr == 0) { | 1164 | if (signr == 0) { |
1185 | /* No signal to deliver -- put the saved sigmask back */ | 1165 | /* No signal to deliver -- put the saved sigmask back */ |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 1ce0ae3f6ffc..5d2faf0fbf05 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
35 | #include <asm/vdso.h> | 35 | #include <asm/vdso.h> |
36 | 36 | ||
37 | #include "signal.h" | ||
38 | |||
37 | #define DEBUG_SIG 0 | 39 | #define DEBUG_SIG 0 |
38 | 40 | ||
39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 41 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -463,41 +465,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
463 | return ret; | 465 | return ret; |
464 | } | 466 | } |
465 | 467 | ||
466 | static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | ||
467 | { | ||
468 | switch ((int)regs->result) { | ||
469 | case -ERESTART_RESTARTBLOCK: | ||
470 | case -ERESTARTNOHAND: | ||
471 | /* ERESTARTNOHAND means that the syscall should only be | ||
472 | * restarted if there was no handler for the signal, and since | ||
473 | * we only get here if there is a handler, we dont restart. | ||
474 | */ | ||
475 | regs->result = -EINTR; | ||
476 | regs->gpr[3] = EINTR; | ||
477 | regs->ccr |= 0x10000000; | ||
478 | break; | ||
479 | case -ERESTARTSYS: | ||
480 | /* ERESTARTSYS means to restart the syscall if there is no | ||
481 | * handler or the handler was registered with SA_RESTART | ||
482 | */ | ||
483 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
484 | regs->result = -EINTR; | ||
485 | regs->gpr[3] = EINTR; | ||
486 | regs->ccr |= 0x10000000; | ||
487 | break; | ||
488 | } | ||
489 | /* fallthrough */ | ||
490 | case -ERESTARTNOINTR: | ||
491 | /* ERESTARTNOINTR means that the syscall should be | ||
492 | * called again after the signal handler returns. | ||
493 | */ | ||
494 | regs->gpr[3] = regs->orig_gpr3; | ||
495 | regs->nip -= 4; | ||
496 | regs->result = 0; | ||
497 | break; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | /* | 468 | /* |
502 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 469 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
503 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 470 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
@@ -522,13 +489,13 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
522 | oldset = ¤t->blocked; | 489 | oldset = ¤t->blocked; |
523 | 490 | ||
524 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 491 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
492 | |||
493 | /* Is there any syscall restart business here ? */ | ||
494 | check_syscall_restart(regs, &ka, signr > 0); | ||
495 | |||
525 | if (signr > 0) { | 496 | if (signr > 0) { |
526 | int ret; | 497 | int ret; |
527 | 498 | ||
528 | /* Whee! Actually deliver the signal. */ | ||
529 | if (TRAP(regs) == 0x0C00) | ||
530 | syscall_restart(regs, &ka); | ||
531 | |||
532 | /* | 499 | /* |
533 | * Reenable the DABR before delivering the signal to | 500 | * Reenable the DABR before delivering the signal to |
534 | * user space. The DABR will have been cleared if it | 501 | * user space. The DABR will have been cleared if it |
@@ -537,6 +504,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
537 | if (current->thread.dabr) | 504 | if (current->thread.dabr) |
538 | set_dabr(current->thread.dabr); | 505 | set_dabr(current->thread.dabr); |
539 | 506 | ||
507 | /* Whee! Actually deliver the signal. */ | ||
540 | ret = handle_signal(signr, &ka, &info, oldset, regs); | 508 | ret = handle_signal(signr, &ka, &info, oldset, regs); |
541 | 509 | ||
542 | /* If a signal was successfully delivered, the saved sigmask is in | 510 | /* If a signal was successfully delivered, the saved sigmask is in |
@@ -547,19 +515,6 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
547 | return ret; | 515 | return ret; |
548 | } | 516 | } |
549 | 517 | ||
550 | if (TRAP(regs) == 0x0C00) { /* System Call! */ | ||
551 | if ((int)regs->result == -ERESTARTNOHAND || | ||
552 | (int)regs->result == -ERESTARTSYS || | ||
553 | (int)regs->result == -ERESTARTNOINTR) { | ||
554 | regs->gpr[3] = regs->orig_gpr3; | ||
555 | regs->nip -= 4; /* Back up & retry system call */ | ||
556 | regs->result = 0; | ||
557 | } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) { | ||
558 | regs->gpr[0] = __NR_restart_syscall; | ||
559 | regs->nip -= 4; | ||
560 | regs->result = 0; | ||
561 | } | ||
562 | } | ||
563 | /* No signal to deliver -- put the saved sigmask back */ | 518 | /* No signal to deliver -- put the saved sigmask back */ |
564 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 519 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
565 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 520 | clear_thread_flag(TIF_RESTORE_SIGMASK); |