diff options
| author | Kyle McMartin <kyle@parisc-linux.org> | 2007-01-15 00:36:26 -0500 |
|---|---|---|
| committer | Kyle McMartin <kyle@athena.road.mcmartin.ca> | 2007-02-17 01:11:06 -0500 |
| commit | 2b163b71e6d4471cae74037cb680e885eafc8d64 (patch) | |
| tree | 66b60d9ce3e894ddccac99105a341d8b37a78243 | |
| parent | f354ef8abe5d6d967c023b21980241e6f883a698 (diff) | |
[PARISC] factor syscall_restart code out of do_signal
looks better this way... ;)
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
| -rw-r--r-- | arch/parisc/kernel/signal.c | 177 |
1 files changed, 98 insertions, 79 deletions
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 8d781b0e668b..64169ab82de2 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
| @@ -471,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 471 | return 1; | 471 | return 1; |
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | static inline void | ||
| 475 | syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | ||
| 476 | { | ||
| 477 | /* Check the return code */ | ||
| 478 | switch (regs->gr[28]) { | ||
| 479 | case -ERESTART_RESTARTBLOCK: | ||
| 480 | current_thread_info()->restart_block.fn = | ||
| 481 | do_no_restart_syscall; | ||
| 482 | case -ERESTARTNOHAND: | ||
| 483 | DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); | ||
| 484 | regs->gr[28] = -EINTR; | ||
| 485 | break; | ||
| 486 | |||
| 487 | case -ERESTARTSYS: | ||
| 488 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
| 489 | DBG(1,"ERESTARTSYS: putting -EINTR\n"); | ||
| 490 | regs->gr[28] = -EINTR; | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | /* fallthrough */ | ||
| 494 | case -ERESTARTNOINTR: | ||
| 495 | /* A syscall is just a branch, so all | ||
| 496 | * we have to do is fiddle the return pointer. | ||
| 497 | */ | ||
| 498 | regs->gr[31] -= 8; /* delayed branching */ | ||
| 499 | /* Preserve original r28. */ | ||
| 500 | regs->gr[28] = regs->orig_r28; | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | static inline void | ||
| 506 | insert_restart_trampoline(struct pt_regs *regs) | ||
| 507 | { | ||
| 508 | switch(regs->gr[28]) { | ||
| 509 | case -ERESTART_RESTARTBLOCK: { | ||
| 510 | /* Restart the system call - no handlers present */ | ||
| 511 | unsigned int *usp = (unsigned int *)regs->gr[30]; | ||
| 512 | |||
| 513 | /* Setup a trampoline to restart the syscall | ||
| 514 | * with __NR_restart_syscall | ||
| 515 | * | ||
| 516 | * 0: <return address (orig r31)> | ||
| 517 | * 4: <2nd half for 64-bit> | ||
| 518 | * 8: ldw 0(%sp), %r31 | ||
| 519 | * 12: be 0x100(%sr2, %r0) | ||
| 520 | * 16: ldi __NR_restart_syscall, %r20 | ||
| 521 | */ | ||
| 522 | #ifdef CONFIG_64BIT | ||
| 523 | put_user(regs->gr[31] >> 32, &usp[0]); | ||
| 524 | put_user(regs->gr[31] & 0xffffffff, &usp[1]); | ||
| 525 | put_user(0x0fc010df, &usp[2]); | ||
| 526 | #else | ||
| 527 | put_user(regs->gr[31], &usp[0]); | ||
| 528 | put_user(0x0fc0109f, &usp[2]); | ||
| 529 | #endif | ||
| 530 | put_user(0xe0008200, &usp[3]); | ||
| 531 | put_user(0x34140000, &usp[4]); | ||
| 532 | |||
| 533 | /* Stack is 64-byte aligned, and we only need | ||
| 534 | * to flush 1 cache line. | ||
| 535 | * Flushing one cacheline is cheap. | ||
| 536 | * "sync" on bigger (> 4 way) boxes is not. | ||
| 537 | */ | ||
| 538 | flush_icache_range(regs->gr[30], regs->gr[30] + 4); | ||
| 539 | |||
| 540 | regs->gr[31] = regs->gr[30] + 8; | ||
| 541 | /* Preserve original r28. */ | ||
| 542 | regs->gr[28] = regs->orig_r28; | ||
| 543 | |||
| 544 | return; | ||
| 545 | } | ||
| 546 | case -ERESTARTNOHAND: | ||
| 547 | case -ERESTARTSYS: | ||
| 548 | case -ERESTARTNOINTR: { | ||
| 549 | /* Hooray for delayed branching. We don't | ||
| 550 | * have to restore %r20 (the system call | ||
| 551 | * number) because it gets loaded in the delay | ||
| 552 | * slot of the branch external instruction. | ||
| 553 | */ | ||
| 554 | regs->gr[31] -= 8; | ||
| 555 | /* Preserve original r28. */ | ||
| 556 | regs->gr[28] = regs->orig_r28; | ||
| 557 | |||
| 558 | return; | ||
| 559 | } | ||
| 560 | default: | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 474 | /* | 565 | /* |
| 475 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 566 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 476 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 567 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| @@ -482,7 +573,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 482 | * registers). As noted below, the syscall number gets restored for | 573 | * registers). As noted below, the syscall number gets restored for |
| 483 | * us due to the magic of delayed branching. | 574 | * us due to the magic of delayed branching. |
| 484 | */ | 575 | */ |
| 485 | |||
| 486 | asmlinkage void | 576 | asmlinkage void |
| 487 | do_signal(struct pt_regs *regs, long in_syscall) | 577 | do_signal(struct pt_regs *regs, long in_syscall) |
| 488 | { | 578 | { |
| @@ -518,36 +608,14 @@ do_signal(struct pt_regs *regs, long in_syscall) | |||
| 518 | break; | 608 | break; |
| 519 | 609 | ||
| 520 | /* Restart a system call if necessary. */ | 610 | /* Restart a system call if necessary. */ |
| 521 | if (in_syscall) { | 611 | if (in_syscall) |
| 522 | /* Check the return code */ | 612 | syscall_restart(regs, &ka); |
| 523 | switch (regs->gr[28]) { | 613 | |
| 524 | case -ERESTART_RESTARTBLOCK: | ||
| 525 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
| 526 | case -ERESTARTNOHAND: | ||
| 527 | DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); | ||
| 528 | regs->gr[28] = -EINTR; | ||
| 529 | break; | ||
| 530 | |||
| 531 | case -ERESTARTSYS: | ||
| 532 | if (!(ka.sa.sa_flags & SA_RESTART)) { | ||
| 533 | DBG(1,"ERESTARTSYS: putting -EINTR\n"); | ||
| 534 | regs->gr[28] = -EINTR; | ||
| 535 | break; | ||
| 536 | } | ||
| 537 | /* fallthrough */ | ||
| 538 | case -ERESTARTNOINTR: | ||
| 539 | /* A syscall is just a branch, so all | ||
| 540 | we have to do is fiddle the return pointer. */ | ||
| 541 | regs->gr[31] -= 8; /* delayed branching */ | ||
| 542 | /* Preserve original r28. */ | ||
| 543 | regs->gr[28] = regs->orig_r28; | ||
| 544 | break; | ||
| 545 | } | ||
| 546 | } | ||
| 547 | /* Whee! Actually deliver the signal. If the | 614 | /* Whee! Actually deliver the signal. If the |
| 548 | delivery failed, we need to continue to iterate in | 615 | delivery failed, we need to continue to iterate in |
| 549 | this loop so we can deliver the SIGSEGV... */ | 616 | this loop so we can deliver the SIGSEGV... */ |
| 550 | if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { | 617 | if (handle_signal(signr, &info, &ka, oldset, |
| 618 | regs, in_syscall)) { | ||
| 551 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", | 619 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", |
| 552 | regs->gr[28]); | 620 | regs->gr[28]); |
| 553 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 621 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| @@ -558,57 +626,8 @@ do_signal(struct pt_regs *regs, long in_syscall) | |||
| 558 | /* end of while(1) looping forever if we can't force a signal */ | 626 | /* end of while(1) looping forever if we can't force a signal */ |
| 559 | 627 | ||
| 560 | /* Did we come from a system call? */ | 628 | /* Did we come from a system call? */ |
| 561 | if (in_syscall) { | 629 | if (in_syscall) |
| 562 | /* Restart the system call - no handlers present */ | 630 | insert_restart_trampoline(regs); |
| 563 | if (regs->gr[28] == -ERESTART_RESTARTBLOCK) { | ||
| 564 | unsigned int *usp = (unsigned int *)regs->gr[30]; | ||
| 565 | |||
| 566 | /* Setup a trampoline to restart the syscall | ||
| 567 | * with __NR_restart_syscall | ||
| 568 | * | ||
| 569 | * 0: <return address (orig r31)> | ||
| 570 | * 4: <2nd half for 64-bit> | ||
| 571 | * 8: ldw 0(%sp), %r31 | ||
| 572 | * 12: be 0x100(%sr2, %r0) | ||
| 573 | * 16: ldi __NR_restart_syscall, %r20 | ||
| 574 | */ | ||
| 575 | #ifndef __LP64__ | ||
| 576 | put_user(regs->gr[31], &usp[0]); | ||
| 577 | put_user(0x0fc0109f, &usp[2]); | ||
| 578 | #else | ||
| 579 | put_user(regs->gr[31] >> 32, &usp[0]); | ||
| 580 | put_user(regs->gr[31] & 0xffffffff, &usp[1]); | ||
| 581 | put_user(0x0fc010df, &usp[2]); | ||
| 582 | #endif | ||
| 583 | put_user(0xe0008200, &usp[3]); | ||
| 584 | put_user(0x34140000, &usp[4]); | ||
| 585 | |||
| 586 | /* Stack is 64-byte aligned, and we only need | ||
| 587 | * to flush 1 cache line. | ||
| 588 | * Flushing one cacheline is cheap. | ||
| 589 | * "sync" on bigger (> 4 way) boxes is not. | ||
| 590 | */ | ||
| 591 | asm("fdc %%r0(%%sr3, %0)\n" | ||
| 592 | "sync\n" | ||
| 593 | "fic %%r0(%%sr3, %0)\n" | ||
| 594 | "sync\n" | ||
| 595 | : : "r"(regs->gr[30])); | ||
| 596 | |||
| 597 | regs->gr[31] = regs->gr[30] + 8; | ||
| 598 | /* Preserve original r28. */ | ||
| 599 | regs->gr[28] = regs->orig_r28; | ||
| 600 | } else if (regs->gr[28] == -ERESTARTNOHAND || | ||
| 601 | regs->gr[28] == -ERESTARTSYS || | ||
| 602 | regs->gr[28] == -ERESTARTNOINTR) { | ||
| 603 | /* Hooray for delayed branching. We don't | ||
| 604 | have to restore %r20 (the system call | ||
| 605 | number) because it gets loaded in the delay | ||
| 606 | slot of the branch external instruction. */ | ||
| 607 | regs->gr[31] -= 8; | ||
| 608 | /* Preserve original r28. */ | ||
| 609 | regs->gr[28] = regs->orig_r28; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | 631 | ||
| 613 | DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", | 632 | DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", |
| 614 | regs->gr[28]); | 633 | regs->gr[28]); |
