diff options
Diffstat (limited to 'arch/sparc64/kernel/signal.c')
-rw-r--r-- | arch/sparc64/kernel/signal.c | 102 |
1 files changed, 50 insertions, 52 deletions
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 45d6bf632daa..6e4dc67d16af 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c | |||
@@ -247,7 +247,9 @@ static long _sigpause_common(old_sigset_t set) | |||
247 | 247 | ||
248 | current->state = TASK_INTERRUPTIBLE; | 248 | current->state = TASK_INTERRUPTIBLE; |
249 | schedule(); | 249 | schedule(); |
250 | set_thread_flag(TIF_RESTORE_SIGMASK); | 250 | |
251 | set_restore_sigmask(); | ||
252 | |||
251 | return -ERESTARTNOHAND; | 253 | return -ERESTARTNOHAND; |
252 | } | 254 | } |
253 | 255 | ||
@@ -333,7 +335,7 @@ void do_rt_sigreturn(struct pt_regs *regs) | |||
333 | regs->tnpc = tnpc; | 335 | regs->tnpc = tnpc; |
334 | 336 | ||
335 | /* Prevent syscall restart. */ | 337 | /* Prevent syscall restart. */ |
336 | pt_regs_clear_trap_type(regs); | 338 | pt_regs_clear_syscall(regs); |
337 | 339 | ||
338 | sigdelsetmask(&set, ~_BLOCKABLE); | 340 | sigdelsetmask(&set, ~_BLOCKABLE); |
339 | spin_lock_irq(¤t->sighand->siglock); | 341 | spin_lock_irq(¤t->sighand->siglock); |
@@ -376,16 +378,29 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | |||
376 | 378 | ||
377 | static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize) | 379 | static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize) |
378 | { | 380 | { |
379 | unsigned long sp; | 381 | unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; |
380 | 382 | ||
381 | sp = regs->u_regs[UREG_FP] + STACK_BIAS; | 383 | /* |
384 | * If we are on the alternate signal stack and would overflow it, don't. | ||
385 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
386 | */ | ||
387 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) | ||
388 | return (void __user *) -1L; | ||
382 | 389 | ||
383 | /* This is the X/Open sanctioned signal stack switching. */ | 390 | /* This is the X/Open sanctioned signal stack switching. */ |
384 | if (ka->sa.sa_flags & SA_ONSTACK) { | 391 | if (ka->sa.sa_flags & SA_ONSTACK) { |
385 | if (!on_sig_stack(sp) && | 392 | if (sas_ss_flags(sp) == 0) |
386 | !((current->sas_ss_sp + current->sas_ss_size) & 7)) | ||
387 | sp = current->sas_ss_sp + current->sas_ss_size; | 393 | sp = current->sas_ss_sp + current->sas_ss_size; |
388 | } | 394 | } |
395 | |||
396 | /* Always align the stack frame. This handles two cases. First, | ||
397 | * sigaltstack need not be mindful of platform specific stack | ||
398 | * alignment. Second, if we took this signal because the stack | ||
399 | * is not aligned properly, we'd like to take the signal cleanly | ||
400 | * and report that. | ||
401 | */ | ||
402 | sp &= ~7UL; | ||
403 | |||
389 | return (void __user *)(sp - framesize); | 404 | return (void __user *)(sp - framesize); |
390 | } | 405 | } |
391 | 406 | ||
@@ -486,7 +501,7 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, | |||
486 | } | 501 | } |
487 | 502 | ||
488 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | 503 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, |
489 | struct sigaction *sa) | 504 | struct sigaction *sa) |
490 | { | 505 | { |
491 | switch (regs->u_regs[UREG_I0]) { | 506 | switch (regs->u_regs[UREG_I0]) { |
492 | case ERESTART_RESTARTBLOCK: | 507 | case ERESTART_RESTARTBLOCK: |
@@ -512,21 +527,19 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | |||
512 | */ | 527 | */ |
513 | static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | 528 | static void do_signal(struct pt_regs *regs, unsigned long orig_i0) |
514 | { | 529 | { |
515 | struct signal_deliver_cookie cookie; | ||
516 | struct k_sigaction ka; | 530 | struct k_sigaction ka; |
531 | int restart_syscall; | ||
517 | sigset_t *oldset; | 532 | sigset_t *oldset; |
518 | siginfo_t info; | 533 | siginfo_t info; |
519 | int signr; | 534 | int signr; |
520 | 535 | ||
521 | if (pt_regs_is_syscall(regs) && | 536 | if (pt_regs_is_syscall(regs) && |
522 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { | 537 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { |
523 | pt_regs_clear_trap_type(regs); | 538 | restart_syscall = 1; |
524 | cookie.restart_syscall = 1; | ||
525 | } else | 539 | } else |
526 | cookie.restart_syscall = 0; | 540 | restart_syscall = 0; |
527 | cookie.orig_i0 = orig_i0; | ||
528 | 541 | ||
529 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 542 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
530 | oldset = ¤t->saved_sigmask; | 543 | oldset = ¤t->saved_sigmask; |
531 | else | 544 | else |
532 | oldset = ¤t->blocked; | 545 | oldset = ¤t->blocked; |
@@ -534,77 +547,62 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
534 | #ifdef CONFIG_COMPAT | 547 | #ifdef CONFIG_COMPAT |
535 | if (test_thread_flag(TIF_32BIT)) { | 548 | if (test_thread_flag(TIF_32BIT)) { |
536 | extern void do_signal32(sigset_t *, struct pt_regs *, | 549 | extern void do_signal32(sigset_t *, struct pt_regs *, |
537 | struct signal_deliver_cookie *); | 550 | int restart_syscall, |
538 | do_signal32(oldset, regs, &cookie); | 551 | unsigned long orig_i0); |
552 | do_signal32(oldset, regs, restart_syscall, orig_i0); | ||
539 | return; | 553 | return; |
540 | } | 554 | } |
541 | #endif | 555 | #endif |
542 | 556 | ||
543 | signr = get_signal_to_deliver(&info, &ka, regs, &cookie); | 557 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
558 | |||
559 | /* If the debugger messes with the program counter, it clears | ||
560 | * the software "in syscall" bit, directing us to not perform | ||
561 | * a syscall restart. | ||
562 | */ | ||
563 | if (restart_syscall && !pt_regs_is_syscall(regs)) | ||
564 | restart_syscall = 0; | ||
565 | |||
544 | if (signr > 0) { | 566 | if (signr > 0) { |
545 | if (cookie.restart_syscall) | 567 | if (restart_syscall) |
546 | syscall_restart(cookie.orig_i0, regs, &ka.sa); | 568 | syscall_restart(orig_i0, regs, &ka.sa); |
547 | handle_signal(signr, &ka, &info, oldset, regs); | 569 | handle_signal(signr, &ka, &info, oldset, regs); |
548 | 570 | ||
549 | /* a signal was successfully delivered; the saved | 571 | /* A signal was successfully delivered; the saved |
550 | * sigmask will have been stored in the signal frame, | 572 | * sigmask will have been stored in the signal frame, |
551 | * and will be restored by sigreturn, so we can simply | 573 | * and will be restored by sigreturn, so we can simply |
552 | * clear the TIF_RESTORE_SIGMASK flag. | 574 | * clear the TS_RESTORE_SIGMASK flag. |
553 | */ | 575 | */ |
554 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 576 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
555 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
556 | return; | 577 | return; |
557 | } | 578 | } |
558 | if (cookie.restart_syscall && | 579 | if (restart_syscall && |
559 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | 580 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || |
560 | regs->u_regs[UREG_I0] == ERESTARTSYS || | 581 | regs->u_regs[UREG_I0] == ERESTARTSYS || |
561 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | 582 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { |
562 | /* replay the system call when we are done */ | 583 | /* replay the system call when we are done */ |
563 | regs->u_regs[UREG_I0] = cookie.orig_i0; | 584 | regs->u_regs[UREG_I0] = orig_i0; |
564 | regs->tpc -= 4; | 585 | regs->tpc -= 4; |
565 | regs->tnpc -= 4; | 586 | regs->tnpc -= 4; |
566 | } | 587 | } |
567 | if (cookie.restart_syscall && | 588 | if (restart_syscall && |
568 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | 589 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { |
569 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | 590 | regs->u_regs[UREG_G1] = __NR_restart_syscall; |
570 | regs->tpc -= 4; | 591 | regs->tpc -= 4; |
571 | regs->tnpc -= 4; | 592 | regs->tnpc -= 4; |
572 | } | 593 | } |
573 | 594 | ||
574 | /* if there's no signal to deliver, we just put the saved sigmask | 595 | /* If there's no signal to deliver, we just put the saved sigmask |
575 | * back | 596 | * back |
576 | */ | 597 | */ |
577 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 598 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) { |
578 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 599 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
579 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 600 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
580 | } | 601 | } |
581 | } | 602 | } |
582 | 603 | ||
583 | void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) | 604 | void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) |
584 | { | 605 | { |
585 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 606 | if (thread_info_flags & _TIF_SIGPENDING) |
586 | do_signal(regs, orig_i0); | 607 | do_signal(regs, orig_i0); |
587 | } | 608 | } |
588 | |||
589 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
590 | { | ||
591 | struct signal_deliver_cookie *cp = cookie; | ||
592 | |||
593 | if (cp->restart_syscall && | ||
594 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | ||
595 | regs->u_regs[UREG_I0] == ERESTARTSYS || | ||
596 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | ||
597 | /* replay the system call when we are done */ | ||
598 | regs->u_regs[UREG_I0] = cp->orig_i0; | ||
599 | regs->tpc -= 4; | ||
600 | regs->tnpc -= 4; | ||
601 | cp->restart_syscall = 0; | ||
602 | } | ||
603 | if (cp->restart_syscall && | ||
604 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | ||
605 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | ||
606 | regs->tpc -= 4; | ||
607 | regs->tnpc -= 4; | ||
608 | cp->restart_syscall = 0; | ||
609 | } | ||
610 | } | ||