[PARISC] factor syscall_restart code out of do_signal
looks better this way... ;) Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
This commit is contained in:
committed by
Kyle McMartin
parent
f354ef8abe
commit
2b163b71e6
@@ -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,
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
/* 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]);
|
||||||
|
Reference in New Issue
Block a user