[parisc-linux] [RFC] pselect/ppoll support
Kyle McMartin
kyle at mcmartin.ca
Sun Apr 9 12:25:21 MDT 2006
First strike at adding TIF_RESTORE_SIGMASK support for the pselect/ppoll
system calls... Doesn't seem to work at all yet...
For instance, signals appear to be completely broken... Dunno why,
seems to work for other architectures...
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 7c95d76..22e3eed 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -32,6 +32,7 @@
#include <asm/psw.h>
#include <asm/assembly.h> /* for LDREG/STREG defines */
+#include <asm/cache.h>
#include <asm/pgtable.h>
#include <asm/signal.h>
#include <asm/unistd.h>
@@ -479,11 +480,7 @@
bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
copy \pmd,%r9
-#ifdef CONFIG_64BIT
- shld %r9,PxD_VALUE_SHIFT,\pmd
-#else
- shlw %r9,PxD_VALUE_SHIFT,\pmd
-#endif
+ SHLREG %r9,PxD_VALUE_SHIFT,\pmd
EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
@@ -962,11 +959,7 @@ intr_return:
/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
** irq_stat[] is defined using ____cacheline_aligned.
*/
-#ifdef CONFIG_64BIT
- shld %r1, 6, %r20
-#else
- shlw %r1, 5, %r20
-#endif
+ SHLREG %r1, L1_CACHE_SHIFT, %r20
add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
#endif /* CONFIG_SMP */
@@ -1071,7 +1064,7 @@ intr_do_preempt:
b intr_restore /* ssm PSW_SM_I done by intr_restore */
#endif /* CONFIG_PREEMPT */
- .import do_signal,code
+ .import do_notify_resume,code
intr_do_signal:
/*
This check is critical to having LWS
@@ -1088,14 +1081,13 @@ intr_do_signal:
CMPIB= 0,%r20,intr_restore /* backward */
nop
- copy %r0, %r24 /* unsigned long in_syscall */
- copy %r16, %r25 /* struct pt_regs *regs */
+ copy %r0, %r25 /* unsigned long in_syscall */
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- BL do_signal,%r2
- copy %r0, %r26 /* sigset_t *oldset = NULL */
+ BL do_notify_resume,%r2
+ copy %r16, %r26 /* struct pt_regs *regs */
b intr_check_sig
nop
@@ -2028,32 +2020,6 @@ sys32_sigaltstack_wrapper:
nop
#endif
- .export sys_rt_sigsuspend_wrapper
-sys_rt_sigsuspend_wrapper:
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
- ldo TASK_REGS(%r1),%r24
- reg_save %r24
-
- STREG %r2, -RP_OFFSET(%r30)
-#ifdef CONFIG_64BIT
- ldo FRAME_SIZE(%r30), %r30
- b,l sys_rt_sigsuspend,%r2
- ldo -16(%r30),%r29 /* Reference param save area */
-#else
- bl sys_rt_sigsuspend,%r2
- ldo FRAME_SIZE(%r30), %r30
-#endif
-
- ldo -FRAME_SIZE(%r30), %r30
- LDREG -RP_OFFSET(%r30), %r2
-
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
- ldo TASK_REGS(%r1),%r1
- reg_restore %r1
-
- bv %r0(%r2)
- nop
-
.export syscall_exit
syscall_exit:
@@ -2108,11 +2074,7 @@ syscall_check_bh:
ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
-#ifdef CONFIG_64BIT
- shld %r26, 6, %r20
-#else
- shlw %r26, 5, %r20
-#endif
+ SHLREG %r26, L1_CACHE_SHIFT, %r20
add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
#endif /* CONFIG_SMP */
@@ -2264,23 +2226,21 @@ syscall_do_resched:
b syscall_check_bh /* if resched, we start over again */
nop
- .import do_signal,code
+ .import do_notify_resume,code
syscall_do_signal:
/* Save callee-save registers (for sigcontext).
FIXME: After this point the process structure should be
consistent with all the relevant state of the process
before the syscall. We need to verify this. */
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
- ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
- reg_save %r25
-
- ldi 1, %r24 /* unsigned long in_syscall */
+ ldo TASK_REGS(%r1), %r26 /* struct pt_regs *regs */
+ reg_save %r26
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- BL do_signal,%r2
- copy %r0, %r26 /* sigset_t *oldset = NULL */
+ BL do_notify_resume,%r2
+ ldi 1, %r25 /* unsigned long in_syscall */
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 413292f..9aa4af0 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -36,8 +36,7 @@
#define DBG(x...)
#endif
-#ifdef __LP64__
-
+#ifdef CONFIG_64BIT
/* This function is needed to translate 32 bit pt_regs offsets in to
* 64 bit pt_regs offsets. For example, a 32 bit gdb under a 64 bit kernel
* will request offset 12 if it wants gr3, but the lower 32 bits of
@@ -90,8 +89,8 @@ long arch_ptrace(struct task_struct *chi
case PTRACE_PEEKDATA: {
int copied;
-#ifdef __LP64__
- if (personality(child->personality) == PER_LINUX32) {
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(child)) {
unsigned int tmp;
addr &= 0xffffffffL;
@@ -122,8 +121,8 @@ long arch_ptrace(struct task_struct *chi
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
ret = 0;
-#ifdef __LP64__
- if (personality(child->personality) == PER_LINUX32) {
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(child)) {
unsigned int tmp = (unsigned int)data;
DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
request == PTRACE_POKETEXT ? "TEXT" : "DATA",
@@ -145,8 +144,8 @@ long arch_ptrace(struct task_struct *chi
processes, the kernel saves all regs on a syscall. */
case PTRACE_PEEKUSR: {
ret = -EIO;
-#ifdef __LP64__
- if (personality(child->personality) == PER_LINUX32) {
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(child)) {
unsigned int tmp;
if (addr & (sizeof(int)-1))
@@ -204,8 +203,8 @@ long arch_ptrace(struct task_struct *chi
ret = 0;
goto out_tsk;
}
-#ifdef __LP64__
- if (personality(child->personality) == PER_LINUX32) {
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(child)) {
if (addr & (sizeof(int)-1))
goto out_tsk;
if ((addr = translate_usr_offset(addr)) < 0)
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 05767e8..5a1e21e 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2000 David Huggins-Daines <dhd at debian.org>
* Copyright (C) 2000 Linuxcare, Inc.
+ * Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
*
* Based on the ia64, i386, and alpha versions.
*
@@ -60,58 +61,13 @@
* this. */
#define A(__x) ((unsigned long)(__x))
-int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
#include "sys32.h"
#endif
-asmlinkage int
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
-{
- sigset_t saveset, newset;
-#ifdef __LP64__
- compat_sigset_t newset32;
-
- if(personality(current->personality) == PER_LINUX32){
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
- if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32)))
- return -EFAULT;
- sigset_32to64(&newset,&newset32);
-
- } else
-#endif
- {
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- }
-
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(¤t->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-
- regs->gr[28] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&saveset, regs, 1))
- return -EINTR;
- }
-}
-
/*
* Do a signal return - restore sigcontext.
*/
@@ -149,11 +105,11 @@ sys_rt_sigreturn(struct pt_regs *regs, i
sigset_t set;
unsigned long usp = (regs->gr[30] & ~(0x01UL));
unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
compat_sigset_t compat_set;
struct compat_rt_sigframe __user * compat_frame;
- if(personality(current->personality) == PER_LINUX32)
+ if (__is_compat_task(current))
sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
#endif
@@ -163,10 +119,10 @@ sys_rt_sigreturn(struct pt_regs *regs, i
(usp - sigframe_size);
DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
compat_frame = (struct compat_rt_sigframe __user *)frame;
- if(personality(current->personality) == PER_LINUX32){
+ if (__is_compat_task(current)) {
DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set)))
goto give_sigsegv;
@@ -185,10 +141,10 @@ sys_rt_sigreturn(struct pt_regs *regs, i
spin_unlock_irq(¤t->sighand->siglock);
/* Good thing we saved the old gr[30], eh? */
-#ifdef __LP64__
- if(personality(current->personality) == PER_LINUX32){
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(current)) {
DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n",
- &compat_frame->uc.uc_mcontext);
+ &compat_frame->uc.uc_mcontext);
// FIXME: Load upper half from register file
if (restore_sigcontext32(&compat_frame->uc.uc_mcontext,
&compat_frame->regs, regs))
@@ -297,12 +253,12 @@ setup_rt_frame(int sig, struct k_sigacti
unsigned long rp, usp;
unsigned long haddr, sigframe_size;
int err = 0;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
compat_int_t compat_val;
struct compat_rt_sigframe __user * compat_frame;
compat_sigset_t compat_set;
#endif
-
+
usp = (regs->gr[30] & ~(0x01UL));
/*FIXME: frame_size parameter is unused, remove it. */
frame = get_sigframe(ka, usp, sizeof(*frame));
@@ -311,11 +267,10 @@ setup_rt_frame(int sig, struct k_sigacti
DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info);
-#ifdef __LP64__
-
+#ifdef CONFIG_64BIT
compat_frame = (struct compat_rt_sigframe __user *)frame;
- if(personality(current->personality) == PER_LINUX32) {
+ if (__is_compat_task(current)) {
DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
err |= copy_siginfo_to_user32(&compat_frame->info, info);
DBG(1,"SETUP_RT_FRAME: 1\n");
@@ -391,8 +346,8 @@ setup_rt_frame(int sig, struct k_sigacti
haddr = A(ka->sa.sa_handler);
/* The sa_handler may be a pointer to a function descriptor */
-#ifdef __LP64__
- if(personality(current->personality) == PER_LINUX32) {
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(current)) {
#endif
if (haddr & PA_PLABEL_FDESC) {
Elf32_Fdesc fdesc;
@@ -406,7 +361,7 @@ setup_rt_frame(int sig, struct k_sigacti
haddr = fdesc.addr;
regs->gr[19] = fdesc.gp;
}
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
} else {
Elf64_Fdesc fdesc;
Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3);
@@ -426,20 +381,20 @@ setup_rt_frame(int sig, struct k_sigacti
/* The syscall return path will create IAOQ values from r31.
*/
sigframe_size = PARISC_RT_SIGFRAME_SIZE;
-#ifdef __LP64__
- if(personality(current->personality) == PER_LINUX32)
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(current))
sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
#endif
if (in_syscall) {
regs->gr[31] = haddr;
-#ifdef __LP64__
- if(personality(current->personality) == PER_LINUX)
+#ifdef CONFIG_64BIT
+ if (__is_native_task(current))
sigframe_size |= 1;
#endif
} else {
unsigned long psw = USER_PSW;
-#ifdef __LP64__
- if(personality(current->personality) == PER_LINUX)
+#ifdef CONFIG_64BIT
+ if (__is_native_task(current))
psw |= PSW_W;
#endif
@@ -463,8 +418,8 @@ setup_rt_frame(int sig, struct k_sigacti
regs->gr[2] = rp; /* userland return pointer */
regs->gr[26] = sig; /* signal number */
-#ifdef __LP64__
- if(personality(current->personality) == PER_LINUX32){
+#ifdef CONFIG_64BIT
+ if (__is_compat_task(current)) {
regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */
} else
@@ -485,12 +440,12 @@ setup_rt_frame(int sig, struct k_sigacti
current->comm, current->pid, frame, regs->gr[30],
regs->iaoq[0], regs->iaoq[1], rp);
- return 1;
+ return 0;
give_sigsegv:
DBG(1,"setup_rt_frame: sending SIGSEGV\n");
force_sigsegv(sig, current);
- return 0;
+ return -EFAULT;
}
/*
@@ -499,22 +454,97 @@ give_sigsegv:
static long
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
- sigset_t *oldset, struct pt_regs *regs, int in_syscall)
+ sigset_t *oldset, struct pt_regs *regs, int in_syscall)
{
+ int ret;
+ unsigned long flags;
+
DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n",
sig, ka, info, oldset, regs);
+
+ /* 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;
+
+ 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;
+ }
+ }
/* Set up the stack frame */
- if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
- return 0;
+ ret = setup_rt_frame(sig, ka, info, oldset, regs, in_syscall);
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- return 1;
+ if (ret == 0) {
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
+ sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(¤t->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+ }
+
+ return ret;
+}
+
+/* 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
+ */
+static void setup_restart_syscall_tramp(struct pt_regs *regs)
+{
+ unsigned int *usp = (unsigned int *)regs->gr[30];
+
+#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.
+ */
+ 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;
+
+ return;
}
/*
@@ -529,130 +559,91 @@ handle_signal(unsigned long sig, siginfo
* us due to the magic of delayed branching.
*/
-asmlinkage int
-do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
+static void
+parisc_do_signal(struct pt_regs *regs, int in_syscall)
{
siginfo_t info;
+ sigset_t *oldset;
struct k_sigaction ka;
int signr;
DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n",
oldset, regs, regs->sr[7], in_syscall);
- /* Everyone else checks to see if they are in kernel mode at
- this point and exits if that's the case. I'm not sure why
- we would be called in that case, but for some reason we
- are. */
+ if (!user_mode(regs))
+ return;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
oldset = ¤t->blocked;
DBG(1,"do_signal: oldset %08lx / %08lx\n",
oldset->sig[0], oldset->sig[1]);
-
/* May need to force signal if handle_signal failed to deliver */
- while (1) {
-
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]);
- if (signr <= 0)
- 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;
-
- 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;
- }
- }
+ if (signr > 0) {
/* 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)) {
+ * 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) == 0) {
DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
- regs->gr[28]);
- return 1;
+ regs->gr[28]);
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ return;
}
}
- /* 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.
+ switch(regs->gr[28]) {
+ case -ERESTART_RESTARTBLOCK:
+ /* Install the restart syscall trampoline on the
+ * userspace stack.
*/
- 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) {
+ setup_restart_syscall_tramp(regs);
+ break;
+ 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. */
+ * 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;
+ break;
}
}
DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n",
regs->gr[28]);
- return 0;
+ /* If there's no signal to deliver, we just put the saved
+ * sigmask back.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+ }
+
+ return;
+}
+
+void do_notify_resume(struct pt_regs *regs, int in_syscall)
+{
+ /* Hooks go here. */
+ if (test_thread_flag(TIF_SIGPENDING) ||
+ test_thread_flag(TIF_RESTORE_SIGMASK))
+ parisc_do_signal(regs, in_syscall);
+
+ return;
}
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index bbeeb61..5744506 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -283,7 +283,7 @@
* struct from a 32-bit user-space app.
*/
ENTRY_SAME(rt_sigqueueinfo)
- ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
+ ENTRY_COMP(rt_sigsuspend)
ENTRY_SAME(chown) /* 180 */
/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
ENTRY_COMP(setsockopt)
@@ -377,8 +377,8 @@
ENTRY_SAME(inotify_init)
ENTRY_SAME(inotify_add_watch) /* 270 */
ENTRY_SAME(inotify_rm_watch)
- ENTRY_SAME(ni_syscall) /* 271 ENTRY_COMP(pselect6) */
- ENTRY_SAME(ni_syscall) /* 272 ENTRY_COMP(ppoll) */
+ ENTRY_COMP(pselect6)
+ ENTRY_COMP(ppoll)
ENTRY_SAME(migrate_pages)
ENTRY_COMP(openat) /* 275 */
ENTRY_SAME(mkdirat)
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
index 3ce3440..00e387c 100644
--- a/include/asm-parisc/assembly.h
+++ b/include/asm-parisc/assembly.h
@@ -30,6 +30,7 @@
#define LDREGM ldd,mb
#define STREGM std,ma
#define SHRREG shrd
+#define SHLREG shld
#define RP_OFFSET 16
#define FRAME_SIZE 128
#define CALLEE_REG_FRAME_SIZE 144
@@ -39,7 +40,8 @@
#define LDREGX ldwx,s
#define LDREGM ldwm
#define STREGM stwm
-#define SHRREG shr
+#define SHRREG shrw
+#define SHLREG shld
#define RP_OFFSET 20
#define FRAME_SIZE 64
#define CALLEE_REG_FRAME_SIZE 128
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 289624d..cea3c35 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -5,6 +5,7 @@
*/
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/personality.h>
#define COMPAT_USER_HZ 100
@@ -149,4 +150,19 @@ static __inline__ void __user *compat_al
return (void __user *)regs->gr[30];
}
+static inline int __is_compat_task(struct task_struct *t)
+{
+ return (personality(t->personality) == PER_LINUX32);
+}
+
+static inline int __is_native_task(struct task_struct *t)
+{
+ return (personality(t->personality) == PER_LINUX);
+}
+
+static inline int is_compat_task(void)
+{
+ return __is_compat_task(current);
+}
+
#endif /* _ASM_PARISC_COMPAT_H */
diff --git a/include/asm-parisc/thread_info.h b/include/asm-parisc/thread_info.h
index f2f83b0..5ae7b38 100644
--- a/include/asm-parisc/thread_info.h
+++ b/include/asm-parisc/thread_info.h
@@ -62,6 +62,7 @@ struct thread_info {
#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_32BIT 5 /* 32 bit binary */
#define TIF_MEMDIE 6
+#define TIF_RESTORE_SIGMASK 7 /* restore signal mask in do_signal() */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
@@ -69,9 +70,10 @@ struct thread_info {
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_32BIT (1 << TIF_32BIT)
+#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
- _TIF_NEED_RESCHED)
+ _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK)
#endif /* __KERNEL__ */
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
index c56fccb..452e9cb 100644
--- a/include/asm-parisc/unistd.h
+++ b/include/asm-parisc/unistd.h
@@ -950,6 +950,8 @@ type name(type1 arg1, type2 arg2, type3
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#endif
/* mmap & mmap2 take 6 arguments */
More information about the parisc-linux
mailing list