aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
authorKyle McMartin <kyle@parisc-linux.org>2007-01-15 00:36:26 -0500
committerKyle McMartin <kyle@athena.road.mcmartin.ca>2007-02-17 01:11:06 -0500
commit2b163b71e6d4471cae74037cb680e885eafc8d64 (patch)
tree66b60d9ce3e894ddccac99105a341d8b37a78243 /arch/parisc
parentf354ef8abe5d6d967c023b21980241e6f883a698 (diff)
[PARISC] factor syscall_restart code out of do_signal
looks better this way... ;) Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/kernel/signal.c177
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
474static inline void
475syscall_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
505static inline void
506insert_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
486asmlinkage void 576asmlinkage void
487do_signal(struct pt_regs *regs, long in_syscall) 577do_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]);