mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-26 17:30:59 +07:00
[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:
parent
f354ef8abe
commit
2b163b71e6
@ -471,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
|
||||
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
|
||||
* 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
|
||||
* us due to the magic of delayed branching.
|
||||
*/
|
||||
|
||||
asmlinkage void
|
||||
do_signal(struct pt_regs *regs, long in_syscall)
|
||||
{
|
||||
@ -518,36 +608,14 @@ do_signal(struct pt_regs *regs, long in_syscall)
|
||||
break;
|
||||
|
||||
/* Restart a system call if necessary. */
|
||||
if (in_syscall) {
|
||||
/* 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;
|
||||
if (in_syscall)
|
||||
syscall_restart(regs, &ka);
|
||||
|
||||
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
|
||||
delivery failed, we need to continue to iterate in
|
||||
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",
|
||||
regs->gr[28]);
|
||||
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 */
|
||||
|
||||
/* Did we come from a system call? */
|
||||
if (in_syscall) {
|
||||
/* Restart the system call - no handlers present */
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (in_syscall)
|
||||
insert_restart_trampoline(regs);
|
||||
|
||||
DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n",
|
||||
regs->gr[28]);
|
||||
|
Loading…
Reference in New Issue
Block a user