Commit 2b163b71 authored by Kyle McMartin's avatar Kyle McMartin Committed by Kyle McMartin

[PARISC] factor syscall_restart code out of do_signal

looks better this way... ;)
Signed-off-by: default avatarKyle McMartin <kyle@parisc-linux.org>
parent f354ef8a
...@@ -471,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, ...@@ -471,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
return 1; return 1;
} }
static inline void
syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
{
/* Check the return code */
switch (regs->gr[28]) {
case -ERESTART_RESTARTBLOCK:
current_thread_info()->restart_block.fn =
do_no_restart_syscall;
case -ERESTARTNOHAND:
DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
regs->gr[28] = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
DBG(1,"ERESTARTSYS: putting -EINTR\n");
regs->gr[28] = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
/* A syscall is just a branch, so all
* we have to do is fiddle the return pointer.
*/
regs->gr[31] -= 8; /* delayed branching */
/* Preserve original r28. */
regs->gr[28] = regs->orig_r28;
break;
}
}
static inline void
insert_restart_trampoline(struct pt_regs *regs)
{
switch(regs->gr[28]) {
case -ERESTART_RESTARTBLOCK: {
/* Restart the system call - no handlers present */
unsigned int *usp = (unsigned int *)regs->gr[30];
/* Setup a trampoline to restart the syscall
* with __NR_restart_syscall
*
* 0: <return address (orig r31)>
* 4: <2nd half for 64-bit>
* 8: ldw 0(%sp), %r31
* 12: be 0x100(%sr2, %r0)
* 16: ldi __NR_restart_syscall, %r20
*/
#ifdef CONFIG_64BIT
put_user(regs->gr[31] >> 32, &usp[0]);
put_user(regs->gr[31] & 0xffffffff, &usp[1]);
put_user(0x0fc010df, &usp[2]);
#else
put_user(regs->gr[31], &usp[0]);
put_user(0x0fc0109f, &usp[2]);
#endif
put_user(0xe0008200, &usp[3]);
put_user(0x34140000, &usp[4]);
/* Stack is 64-byte aligned, and we only need
* to flush 1 cache line.
* Flushing one cacheline is cheap.
* "sync" on bigger (> 4 way) boxes is not.
*/
flush_icache_range(regs->gr[30], regs->gr[30] + 4);
regs->gr[31] = regs->gr[30] + 8;
/* Preserve original r28. */
regs->gr[28] = regs->orig_r28;
return;
}
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR: {
/* Hooray for delayed branching. We don't
* have to restore %r20 (the system call
* number) because it gets loaded in the delay
* slot of the branch external instruction.
*/
regs->gr[31] -= 8;
/* Preserve original r28. */
regs->gr[28] = regs->orig_r28;
return;
}
default:
break;
}
}
/* /*
* Note that 'init' is a special process: it doesn't get signals it doesn't * Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by * 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,7 +573,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
* registers). As noted below, the syscall number gets restored for * registers). As noted below, the syscall number gets restored for
* us due to the magic of delayed branching. * us due to the magic of delayed branching.
*/ */
asmlinkage void asmlinkage void
do_signal(struct pt_regs *regs, long in_syscall) do_signal(struct pt_regs *regs, long in_syscall)
{ {
...@@ -518,36 +608,14 @@ do_signal(struct pt_regs *regs, long in_syscall) ...@@ -518,36 +608,14 @@ do_signal(struct pt_regs *regs, long in_syscall)
break; break;
/* Restart a system call if necessary. */ /* Restart a system call if necessary. */
if (in_syscall) { if (in_syscall)
/* Check the return code */ syscall_restart(regs, &ka);
switch (regs->gr[28]) {
case -ERESTART_RESTARTBLOCK:
current_thread_info()->restart_block.fn = do_no_restart_syscall;
case -ERESTARTNOHAND:
DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
regs->gr[28] = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka.sa.sa_flags & SA_RESTART)) {
DBG(1,"ERESTARTSYS: putting -EINTR\n");
regs->gr[28] = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
/* A syscall is just a branch, so all
we have to do is fiddle the return pointer. */
regs->gr[31] -= 8; /* delayed branching */
/* Preserve original r28. */
regs->gr[28] = regs->orig_r28;
break;
}
}
/* Whee! Actually deliver the signal. If the /* Whee! Actually deliver the signal. If the
delivery failed, we need to continue to iterate in delivery failed, we need to continue to iterate in
this loop so we can deliver the SIGSEGV... */ this loop so we can deliver the SIGSEGV... */
if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { if (handle_signal(signr, &info, &ka, oldset,
regs, in_syscall)) {
DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
regs->gr[28]); regs->gr[28]);
if (test_thread_flag(TIF_RESTORE_SIGMASK)) if (test_thread_flag(TIF_RESTORE_SIGMASK))
...@@ -558,57 +626,8 @@ do_signal(struct pt_regs *regs, long in_syscall) ...@@ -558,57 +626,8 @@ do_signal(struct pt_regs *regs, long in_syscall)
/* end of while(1) looping forever if we can't force a signal */ /* end of while(1) looping forever if we can't force a signal */
/* Did we come from a system call? */ /* Did we come from a system call? */
if (in_syscall) { if (in_syscall)
/* Restart the system call - no handlers present */ insert_restart_trampoline(regs);
if (regs->gr[28] == -ERESTART_RESTARTBLOCK) {
unsigned int *usp = (unsigned int *)regs->gr[30];
/* Setup a trampoline to restart the syscall
* with __NR_restart_syscall
*
* 0: <return address (orig r31)>
* 4: <2nd half for 64-bit>
* 8: ldw 0(%sp), %r31
* 12: be 0x100(%sr2, %r0)
* 16: ldi __NR_restart_syscall, %r20
*/
#ifndef __LP64__
put_user(regs->gr[31], &usp[0]);
put_user(0x0fc0109f, &usp[2]);
#else
put_user(regs->gr[31] >> 32, &usp[0]);
put_user(regs->gr[31] & 0xffffffff, &usp[1]);
put_user(0x0fc010df, &usp[2]);
#endif
put_user(0xe0008200, &usp[3]);
put_user(0x34140000, &usp[4]);
/* Stack is 64-byte aligned, and we only need
* to flush 1 cache line.
* Flushing one cacheline is cheap.
* "sync" on bigger (> 4 way) boxes is not.
*/
asm("fdc %%r0(%%sr3, %0)\n"
"sync\n"
"fic %%r0(%%sr3, %0)\n"
"sync\n"
: : "r"(regs->gr[30]));
regs->gr[31] = regs->gr[30] + 8;
/* Preserve original r28. */
regs->gr[28] = regs->orig_r28;
} else if (regs->gr[28] == -ERESTARTNOHAND ||
regs->gr[28] == -ERESTARTSYS ||
regs->gr[28] == -ERESTARTNOINTR) {
/* Hooray for delayed branching. We don't
have to restore %r20 (the system call
number) because it gets loaded in the delay
slot of the branch external instruction. */
regs->gr[31] -= 8;
/* Preserve original r28. */
regs->gr[28] = regs->orig_r28;
}
}
DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n",
regs->gr[28]); regs->gr[28]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment