sh: pselect6 and ppoll, along with signal trampoline rework.

This implements support for ppoll() and pselect6()..

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index fcbf50d..fd5fe23 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -371,12 +371,12 @@
 	! r8: current_thread_info
 	! t:  result of "tst	#_TIF_NEED_RESCHED, r0"
 	bf/s	work_resched
-	 tst	#_TIF_SIGPENDING, r0
+	 tst	#(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
 work_notifysig:
 	bt/s	restore_all
 	 mov	r15, r4
-	mov	#0, r5
-	mov	r12, r6		! set arg2(save_r0)
+	mov	r12, r5		! set arg1(save_r0)
+	mov	r0, r6
 	mov.l	2f, r1
 	mova	restore_all, r0
 	jmp	@r1
@@ -414,7 +414,7 @@
 
 	.align	2
 1:	.long	schedule
-2:	.long	do_signal
+2:	.long	do_notify_resume
 
 	.align	2
 syscall_exit_work:
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index eb6a3b9..2f1c954 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -29,13 +29,10 @@
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 
-#define DEBUG_SIG 0
+#undef DEBUG
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset,
-			 unsigned int save_r0);
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -44,51 +41,17 @@
 	       unsigned long r5, unsigned long r6, unsigned long r7,
 	       struct pt_regs regs)
 {
-	sigset_t saveset;
-
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
+	current->saved_sigmask = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	regs.regs[0] = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&regs, &saveset, regs.regs[0]))
-			return -EINTR;
-	}
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
-		  unsigned long r6, unsigned long r7,
-		  struct pt_regs regs)
-{
-	sigset_t saveset, newset;
-
-	/* 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(&current->sighand->siglock);
-	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs.regs[0] = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&regs, &saveset, regs.regs[0]))
-			return -EINTR;
-	}
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
 }
 
 asmlinkage int 
@@ -349,7 +312,7 @@
 	return (void __user *)((sp - frame_size) & -8ul);
 }
 
-static void setup_frame(int sig, struct k_sigaction *ka,
+static int setup_frame(int sig, struct k_sigaction *ka,
 			sigset_t *set, struct pt_regs *regs)
 {
 	struct sigframe __user *frame;
@@ -369,10 +332,9 @@
 
 	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
 
-	if (_NSIG_WORDS > 1) {
+	if (_NSIG_WORDS > 1)
 		err |= __copy_to_user(frame->extramask, &set->sig[1],
 				      sizeof(frame->extramask));
-	}
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -403,21 +365,22 @@
 
 	set_fs(USER_DS);
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
-		current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+		 current->comm, current->pid, frame, regs->pc, regs->pr);
 
 	flush_cache_sigtramp(regs->pr);
+
 	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
 		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
-	return;
+
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe __user *frame;
@@ -478,28 +441,31 @@
 
 	set_fs(USER_DS);
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
-		current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+		 current->comm, current->pid, frame, regs->pc, regs->pr);
 
 	flush_cache_sigtramp(regs->pr);
+
 	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
 		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
-	return;
+
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler
  */
 
-static void
+static int
 handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
 	      sigset_t *oldset, struct pt_regs *regs)
 {
+	int ret;
+
 	/* Are we from a system call? */
 	if (regs->tra >= 0) {
 		/* If so, check system call restarting.. */
@@ -540,19 +506,23 @@
 
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		ret = setup_frame(sig, ka, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	if (ret == 0) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		if (!(ka->sa.sa_flags & SA_NODEFER))
+			sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+
+	return ret;
 }
 
 /*
@@ -564,11 +534,12 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
+static void do_signal(struct pt_regs *regs, unsigned int save_r0)
 {
 	siginfo_t info;
 	int signr;
 	struct k_sigaction ka;
+	sigset_t *oldset;
 
 	/*
 	 * We want the common case to go fast, which
@@ -577,19 +548,27 @@
 	 * if so.
 	 */
 	if (!user_mode(regs))
-		return 1;
+		return;
 
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, &ka, &info, oldset, regs);
-		return 1;
+		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
+		}
 	}
 
  no_signal:
@@ -606,5 +585,19 @@
 			regs->regs[3] = __NR_restart_syscall;
 		}
 	}
-	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, &current->saved_sigmask, NULL);
+	}
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
+				 __u32 thread_info_flags)
+{
+	/* deal with pending signal delivery */
+	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+		do_signal(regs, save_r0);
 }
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index ea23b21..768334e 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -319,34 +319,35 @@
 	.long sys_mq_getsetattr
 	.long sys_kexec_load
 	.long sys_waitid
-	.long sys_add_key		/* 285 */
+	.long sys_ni_syscall		/* 285 */
+	.long sys_add_key
 	.long sys_request_key
 	.long sys_keyctl
 	.long sys_ioprio_set
-	.long sys_ioprio_get
-	.long sys_inotify_init		/* 290 */
+	.long sys_ioprio_get		/* 290 */
+	.long sys_inotify_init
 	.long sys_inotify_add_watch
 	.long sys_inotify_rm_watch
 	.long sys_migrate_pages
-	.long sys_openat
-	.long sys_mkdirat		/* 295 */
+	.long sys_openat		/* 295 */
+	.long sys_mkdirat
 	.long sys_mknodat
 	.long sys_fchownat
 	.long sys_futimesat
-	.long sys_fstatat64
-	.long sys_unlinkat		/* 300 */
+	.long sys_fstatat64		/* 300 */
+	.long sys_unlinkat
 	.long sys_renameat
 	.long sys_linkat
 	.long sys_symlinkat
-	.long sys_readlinkat
-	.long sys_fchmodat		/* 305 */
+	.long sys_readlinkat		/* 305 */
+	.long sys_fchmodat
 	.long sys_faccessat
-	.long sys_ni_syscall		/* Reserved for pselect6 */
-	.long sys_ni_syscall		/* Reserved for ppoll */
-	.long sys_unshare
-	.long sys_set_robust_list	/* 310 */
+	.long sys_pselect6
+	.long sys_ppoll
+	.long sys_unshare		/* 310 */
+	.long sys_set_robust_list
 	.long sys_get_robust_list
 	.long sys_splice
 	.long sys_sync_file_range
-	.long sys_tee
-	.long sys_vmsplice		/* 315 */
+	.long sys_tee			/* 315 */
+	.long sys_vmsplice
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index b986a19..5eb874b 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -94,6 +94,7 @@
 #define TIF_NOTIFY_RESUME	1	/* resumption notification requested */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+#define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18
@@ -102,6 +103,7 @@
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 49c6a6e..080e572 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -292,39 +292,40 @@
 #define __NR_mq_getsetattr      (__NR_mq_open+5)
 #define __NR_kexec_load		283
 #define __NR_waitid		284
-#define __NR_add_key		285
-#define __NR_request_key	286
-#define __NR_keyctl		287
-#define __NR_ioprio_set		288
-#define __NR_ioprio_get		289
-#define __NR_inotify_init	290
-#define __NR_inotify_add_watch	291
-#define __NR_inotify_rm_watch	292
-#define __NR_migrate_pages	293
-#define __NR_openat		294
-#define __NR_mkdirat		295
-#define __NR_mknodat		296
-#define __NR_fchownat		297
-#define __NR_futimesat		298
-#define __NR_fstatat64		299
-#define __NR_unlinkat		300
-#define __NR_renameat		301
-#define __NR_linkat		302
-#define __NR_symlinkat		303
-#define __NR_readlinkat		304
-#define __NR_fchmodat		305
-#define __NR_faccessat		305
-#define __NR_pselect6		307
-#define __NR_ppoll		308
-#define __NR_unshare		309
-#define __NR_set_robust_list	310
-#define __NR_get_robust_list	311
-#define __NR_splice		312
-#define __NR_sync_file_range	313
-#define __NR_tee		314
-#define __NR_vmsplice		315
+/* #define __NR_sys_setaltroot	285 */
+#define __NR_add_key		286
+#define __NR_request_key	287
+#define __NR_keyctl		288
+#define __NR_ioprio_set		289
+#define __NR_ioprio_get		290
+#define __NR_inotify_init	291
+#define __NR_inotify_add_watch	292
+#define __NR_inotify_rm_watch	293
+#define __NR_migrate_pages	294
+#define __NR_openat		295
+#define __NR_mkdirat		296
+#define __NR_mknodat		297
+#define __NR_fchownat		298
+#define __NR_futimesat		299
+#define __NR_newfstatat		300
+#define __NR_unlinkat		301
+#define __NR_renameat		302
+#define __NR_linkat		303
+#define __NR_symlinkat		304
+#define __NR_readlinkat		305
+#define __NR_fchmodat		306
+#define __NR_faccessat		307
+#define __NR_pselect6		308
+#define __NR_ppoll		309
+#define __NR_unshare		310
+#define __NR_set_robust_list	311
+#define __NR_get_robust_list	312
+#define __NR_splice		313
+#define __NR_sync_file_range	314
+#define __NR_tee		315
+#define __NR_vmsplice		316
 
-#define NR_syscalls 316
+#define NR_syscalls 317
 
 #ifdef __KERNEL__
 
@@ -466,6 +467,7 @@
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 #ifdef __KERNEL_SYSCALLS__