diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_64.c')
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 182 |
1 files changed, 5 insertions, 177 deletions
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index b27e26852fdb..de895e6d8c62 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -34,9 +34,9 @@ | |||
34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
35 | #include <asm/vdso.h> | 35 | #include <asm/vdso.h> |
36 | 36 | ||
37 | #define DEBUG_SIG 0 | 37 | #include "signal.h" |
38 | 38 | ||
39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 39 | #define DEBUG_SIG 0 |
40 | 40 | ||
41 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) | 41 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) |
42 | #define FP_REGS_SIZE sizeof(elf_fpregset_t) | 42 | #define FP_REGS_SIZE sizeof(elf_fpregset_t) |
@@ -64,14 +64,6 @@ struct rt_sigframe { | |||
64 | char abigap[288]; | 64 | char abigap[288]; |
65 | } __attribute__ ((aligned (16))); | 65 | } __attribute__ ((aligned (16))); |
66 | 66 | ||
67 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, | ||
68 | unsigned long r6, unsigned long r7, unsigned long r8, | ||
69 | struct pt_regs *regs) | ||
70 | { | ||
71 | return do_sigaltstack(uss, uoss, regs->gpr[1]); | ||
72 | } | ||
73 | |||
74 | |||
75 | /* | 67 | /* |
76 | * Set up the sigcontext for the signal frame. | 68 | * Set up the sigcontext for the signal frame. |
77 | */ | 69 | */ |
@@ -208,25 +200,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | |||
208 | } | 200 | } |
209 | 201 | ||
210 | /* | 202 | /* |
211 | * Allocate space for the signal frame | ||
212 | */ | ||
213 | static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
214 | size_t frame_size) | ||
215 | { | ||
216 | unsigned long newsp; | ||
217 | |||
218 | /* Default to using normal stack */ | ||
219 | newsp = regs->gpr[1]; | ||
220 | |||
221 | if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) { | ||
222 | if (! on_sig_stack(regs->gpr[1])) | ||
223 | newsp = (current->sas_ss_sp + current->sas_ss_size); | ||
224 | } | ||
225 | |||
226 | return (void __user *)((newsp - frame_size) & -16ul); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Setup the trampoline code on the stack | 203 | * Setup the trampoline code on the stack |
231 | */ | 204 | */ |
232 | static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | 205 | static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) |
@@ -253,19 +226,6 @@ static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | |||
253 | } | 226 | } |
254 | 227 | ||
255 | /* | 228 | /* |
256 | * Restore the user process's signal mask (also used by signal32.c) | ||
257 | */ | ||
258 | void restore_sigmask(sigset_t *set) | ||
259 | { | ||
260 | sigdelsetmask(set, ~_BLOCKABLE); | ||
261 | spin_lock_irq(¤t->sighand->siglock); | ||
262 | current->blocked = *set; | ||
263 | recalc_sigpending(); | ||
264 | spin_unlock_irq(¤t->sighand->siglock); | ||
265 | } | ||
266 | |||
267 | |||
268 | /* | ||
269 | * Handle {get,set,swap}_context operations | 229 | * Handle {get,set,swap}_context operations |
270 | */ | 230 | */ |
271 | int sys_swapcontext(struct ucontext __user *old_ctx, | 231 | int sys_swapcontext(struct ucontext __user *old_ctx, |
@@ -359,7 +319,7 @@ badframe: | |||
359 | return 0; | 319 | return 0; |
360 | } | 320 | } |
361 | 321 | ||
362 | static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | 322 | int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, |
363 | sigset_t *set, struct pt_regs *regs) | 323 | sigset_t *set, struct pt_regs *regs) |
364 | { | 324 | { |
365 | /* Handler is *really* a pointer to the function descriptor for | 325 | /* Handler is *really* a pointer to the function descriptor for |
@@ -373,8 +333,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
373 | long err = 0; | 333 | long err = 0; |
374 | 334 | ||
375 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 335 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
376 | 336 | if (unlikely(frame == NULL)) | |
377 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
378 | goto badframe; | 337 | goto badframe; |
379 | 338 | ||
380 | err |= __put_user(&frame->info, &frame->pinfo); | 339 | err |= __put_user(&frame->info, &frame->pinfo); |
@@ -411,7 +370,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
411 | funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; | 370 | funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; |
412 | 371 | ||
413 | /* Allocate a dummy caller frame for the signal handler. */ | 372 | /* Allocate a dummy caller frame for the signal handler. */ |
414 | newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE; | 373 | newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; |
415 | err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); | 374 | err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); |
416 | 375 | ||
417 | /* Set up "regs" so we "return" to the signal handler. */ | 376 | /* Set up "regs" so we "return" to the signal handler. */ |
@@ -442,134 +401,3 @@ badframe: | |||
442 | force_sigsegv(signr, current); | 401 | force_sigsegv(signr, current); |
443 | return 0; | 402 | return 0; |
444 | } | 403 | } |
445 | |||
446 | |||
447 | /* | ||
448 | * OK, we're invoking a handler | ||
449 | */ | ||
450 | static int handle_signal(unsigned long sig, struct k_sigaction *ka, | ||
451 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) | ||
452 | { | ||
453 | int ret; | ||
454 | |||
455 | /* Set up Signal Frame */ | ||
456 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | ||
457 | |||
458 | if (ret) { | ||
459 | spin_lock_irq(¤t->sighand->siglock); | ||
460 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | ||
461 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
462 | sigaddset(¤t->blocked,sig); | ||
463 | recalc_sigpending(); | ||
464 | spin_unlock_irq(¤t->sighand->siglock); | ||
465 | } | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | ||
471 | { | ||
472 | switch ((int)regs->result) { | ||
473 | case -ERESTART_RESTARTBLOCK: | ||
474 | case -ERESTARTNOHAND: | ||
475 | /* ERESTARTNOHAND means that the syscall should only be | ||
476 | * restarted if there was no handler for the signal, and since | ||
477 | * we only get here if there is a handler, we dont restart. | ||
478 | */ | ||
479 | regs->result = -EINTR; | ||
480 | regs->gpr[3] = EINTR; | ||
481 | regs->ccr |= 0x10000000; | ||
482 | break; | ||
483 | case -ERESTARTSYS: | ||
484 | /* ERESTARTSYS means to restart the syscall if there is no | ||
485 | * handler or the handler was registered with SA_RESTART | ||
486 | */ | ||
487 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
488 | regs->result = -EINTR; | ||
489 | regs->gpr[3] = EINTR; | ||
490 | regs->ccr |= 0x10000000; | ||
491 | break; | ||
492 | } | ||
493 | /* fallthrough */ | ||
494 | case -ERESTARTNOINTR: | ||
495 | /* ERESTARTNOINTR means that the syscall should be | ||
496 | * called again after the signal handler returns. | ||
497 | */ | ||
498 | regs->gpr[3] = regs->orig_gpr3; | ||
499 | regs->nip -= 4; | ||
500 | regs->result = 0; | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
507 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
508 | * mistake. | ||
509 | */ | ||
510 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
511 | { | ||
512 | siginfo_t info; | ||
513 | int signr; | ||
514 | struct k_sigaction ka; | ||
515 | |||
516 | /* | ||
517 | * If the current thread is 32 bit - invoke the | ||
518 | * 32 bit signal handling code | ||
519 | */ | ||
520 | if (test_thread_flag(TIF_32BIT)) | ||
521 | return do_signal32(oldset, regs); | ||
522 | |||
523 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
524 | oldset = ¤t->saved_sigmask; | ||
525 | else if (!oldset) | ||
526 | oldset = ¤t->blocked; | ||
527 | |||
528 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
529 | if (signr > 0) { | ||
530 | int ret; | ||
531 | |||
532 | /* Whee! Actually deliver the signal. */ | ||
533 | if (TRAP(regs) == 0x0C00) | ||
534 | syscall_restart(regs, &ka); | ||
535 | |||
536 | /* | ||
537 | * Reenable the DABR before delivering the signal to | ||
538 | * user space. The DABR will have been cleared if it | ||
539 | * triggered inside the kernel. | ||
540 | */ | ||
541 | if (current->thread.dabr) | ||
542 | set_dabr(current->thread.dabr); | ||
543 | |||
544 | ret = handle_signal(signr, &ka, &info, oldset, regs); | ||
545 | |||
546 | /* If a signal was successfully delivered, the saved sigmask is in | ||
547 | its frame, and we can clear the TIF_RESTORE_SIGMASK flag */ | ||
548 | if (ret && test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
549 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
550 | |||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | if (TRAP(regs) == 0x0C00) { /* System Call! */ | ||
555 | if ((int)regs->result == -ERESTARTNOHAND || | ||
556 | (int)regs->result == -ERESTARTSYS || | ||
557 | (int)regs->result == -ERESTARTNOINTR) { | ||
558 | regs->gpr[3] = regs->orig_gpr3; | ||
559 | regs->nip -= 4; /* Back up & retry system call */ | ||
560 | regs->result = 0; | ||
561 | } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) { | ||
562 | regs->gpr[0] = __NR_restart_syscall; | ||
563 | regs->nip -= 4; | ||
564 | regs->result = 0; | ||
565 | } | ||
566 | } | ||
567 | /* No signal to deliver -- put the saved sigmask back */ | ||
568 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
569 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
570 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
571 | } | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | EXPORT_SYMBOL(do_signal); | ||