diff options
Diffstat (limited to 'arch/parisc/kernel/signal.c')
| -rw-r--r-- | arch/parisc/kernel/signal.c | 45 |
1 files changed, 15 insertions, 30 deletions
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 594459bde14e..537996955998 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
| @@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) | |||
| 113 | (usp - sigframe_size); | 113 | (usp - sigframe_size); |
| 114 | DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); | 114 | DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); |
| 115 | 115 | ||
| 116 | regs->orig_r28 = 1; /* no restarts for sigreturn */ | ||
| 117 | |||
| 116 | #ifdef CONFIG_64BIT | 118 | #ifdef CONFIG_64BIT |
| 117 | compat_frame = (struct compat_rt_sigframe __user *)frame; | 119 | compat_frame = (struct compat_rt_sigframe __user *)frame; |
| 118 | 120 | ||
| @@ -437,7 +439,7 @@ give_sigsegv: | |||
| 437 | * OK, we're invoking a handler. | 439 | * OK, we're invoking a handler. |
| 438 | */ | 440 | */ |
| 439 | 441 | ||
| 440 | static long | 442 | static void |
| 441 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 443 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 442 | struct pt_regs *regs, int in_syscall) | 444 | struct pt_regs *regs, int in_syscall) |
| 443 | { | 445 | { |
| @@ -447,7 +449,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 447 | 449 | ||
| 448 | /* Set up the stack frame */ | 450 | /* Set up the stack frame */ |
| 449 | if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) | 451 | if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) |
| 450 | return 0; | 452 | return; |
| 451 | 453 | ||
| 452 | signal_delivered(sig, info, ka, regs, | 454 | signal_delivered(sig, info, ka, regs, |
| 453 | test_thread_flag(TIF_SINGLESTEP) || | 455 | test_thread_flag(TIF_SINGLESTEP) || |
| @@ -455,13 +457,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 455 | 457 | ||
| 456 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", | 458 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", |
| 457 | regs->gr[28]); | 459 | regs->gr[28]); |
| 458 | |||
| 459 | return 1; | ||
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | static inline void | 462 | static inline void |
| 463 | syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | 463 | syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) |
| 464 | { | 464 | { |
| 465 | if (regs->orig_r28) | ||
| 466 | return; | ||
| 467 | regs->orig_r28 = 1; /* no more restarts */ | ||
| 465 | /* Check the return code */ | 468 | /* Check the return code */ |
| 466 | switch (regs->gr[28]) { | 469 | switch (regs->gr[28]) { |
| 467 | case -ERESTART_RESTARTBLOCK: | 470 | case -ERESTART_RESTARTBLOCK: |
| @@ -482,8 +485,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | |||
| 482 | * we have to do is fiddle the return pointer. | 485 | * we have to do is fiddle the return pointer. |
| 483 | */ | 486 | */ |
| 484 | regs->gr[31] -= 8; /* delayed branching */ | 487 | regs->gr[31] -= 8; /* delayed branching */ |
| 485 | /* Preserve original r28. */ | ||
| 486 | regs->gr[28] = regs->orig_r28; | ||
| 487 | break; | 488 | break; |
| 488 | } | 489 | } |
| 489 | } | 490 | } |
| @@ -491,6 +492,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | |||
| 491 | static inline void | 492 | static inline void |
| 492 | insert_restart_trampoline(struct pt_regs *regs) | 493 | insert_restart_trampoline(struct pt_regs *regs) |
| 493 | { | 494 | { |
| 495 | if (regs->orig_r28) | ||
| 496 | return; | ||
| 497 | regs->orig_r28 = 1; /* no more restarts */ | ||
| 494 | switch(regs->gr[28]) { | 498 | switch(regs->gr[28]) { |
| 495 | case -ERESTART_RESTARTBLOCK: { | 499 | case -ERESTART_RESTARTBLOCK: { |
| 496 | /* Restart the system call - no handlers present */ | 500 | /* Restart the system call - no handlers present */ |
| @@ -525,9 +529,6 @@ insert_restart_trampoline(struct pt_regs *regs) | |||
| 525 | flush_user_icache_range(regs->gr[30], regs->gr[30] + 4); | 529 | flush_user_icache_range(regs->gr[30], regs->gr[30] + 4); |
| 526 | 530 | ||
| 527 | regs->gr[31] = regs->gr[30] + 8; | 531 | regs->gr[31] = regs->gr[30] + 8; |
| 528 | /* Preserve original r28. */ | ||
| 529 | regs->gr[28] = regs->orig_r28; | ||
| 530 | |||
| 531 | return; | 532 | return; |
| 532 | } | 533 | } |
| 533 | case -ERESTARTNOHAND: | 534 | case -ERESTARTNOHAND: |
| @@ -539,9 +540,6 @@ insert_restart_trampoline(struct pt_regs *regs) | |||
| 539 | * slot of the branch external instruction. | 540 | * slot of the branch external instruction. |
| 540 | */ | 541 | */ |
| 541 | regs->gr[31] -= 8; | 542 | regs->gr[31] -= 8; |
| 542 | /* Preserve original r28. */ | ||
| 543 | regs->gr[28] = regs->orig_r28; | ||
| 544 | |||
| 545 | return; | 543 | return; |
| 546 | } | 544 | } |
| 547 | default: | 545 | default: |
| @@ -570,30 +568,17 @@ do_signal(struct pt_regs *regs, long in_syscall) | |||
| 570 | DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n", | 568 | DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n", |
| 571 | regs, regs->sr[7], in_syscall); | 569 | regs, regs->sr[7], in_syscall); |
| 572 | 570 | ||
| 573 | /* Everyone else checks to see if they are in kernel mode at | 571 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 574 | this point and exits if that's the case. I'm not sure why | 572 | DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); |
| 575 | we would be called in that case, but for some reason we | ||
| 576 | are. */ | ||
| 577 | |||
| 578 | /* May need to force signal if handle_signal failed to deliver */ | ||
| 579 | while (1) { | ||
| 580 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
| 581 | DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); | ||
| 582 | 573 | ||
| 583 | if (signr <= 0) | 574 | if (signr > 0) { |
| 584 | break; | ||
| 585 | |||
| 586 | /* Restart a system call if necessary. */ | 575 | /* Restart a system call if necessary. */ |
| 587 | if (in_syscall) | 576 | if (in_syscall) |
| 588 | syscall_restart(regs, &ka); | 577 | syscall_restart(regs, &ka); |
| 589 | 578 | ||
| 590 | /* Whee! Actually deliver the signal. If the | 579 | handle_signal(signr, &info, &ka, regs, in_syscall); |
| 591 | delivery failed, we need to continue to iterate in | 580 | return; |
| 592 | this loop so we can deliver the SIGSEGV... */ | ||
| 593 | if (handle_signal(signr, &info, &ka, regs, in_syscall)) | ||
| 594 | return; | ||
| 595 | } | 581 | } |
| 596 | /* end of while(1) looping forever if we can't force a signal */ | ||
| 597 | 582 | ||
| 598 | /* Did we come from a system call? */ | 583 | /* Did we come from a system call? */ |
| 599 | if (in_syscall) | 584 | if (in_syscall) |
