patch-2.4.15 linux/arch/ia64/ia32/ia32_signal.c

Next file: linux/arch/ia64/ia32/ia32_support.c
Previous file: linux/arch/ia64/ia32/ia32_ldt.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c
@@ -1,8 +1,8 @@
 /*
  * IA32 Architecture-specific signal handling support.
  *
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
  * Copyright (C) 2000 VA Linux Co
  * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -28,9 +29,15 @@
 #include <asm/segment.h>
 #include <asm/ia32.h>
 
+#include "../kernel/sigframe.h"
+
+#define A(__x)		((unsigned long)(__x))
+
 #define DEBUG_SIG	0
 #define _BLOCKABLE	(~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
+#define __IA32_NR_sigreturn            119
+#define __IA32_NR_rt_sigreturn         173
 
 struct sigframe_ia32
 {
@@ -54,12 +61,51 @@
        char retcode[8];
 };
 
-static int
+int
+copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from)
+{
+	unsigned long tmp;
+	int err;
+
+	if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t32)))
+		return -EFAULT;
+
+	err = __get_user(to->si_signo, &from->si_signo);
+	err |= __get_user(to->si_errno, &from->si_errno);
+	err |= __get_user(to->si_code, &from->si_code);
+
+	if (from->si_code < 0)
+		err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+	else {
+		switch (from->si_code >> 16) {
+		      case __SI_CHLD >> 16:
+			err |= __get_user(to->si_utime, &from->si_utime);
+			err |= __get_user(to->si_stime, &from->si_stime);
+			err |= __get_user(to->si_status, &from->si_status);
+		      default:
+			err |= __get_user(to->si_pid, &from->si_pid);
+			err |= __get_user(to->si_uid, &from->si_uid);
+			break;
+		      case __SI_FAULT >> 16:
+			err |= __get_user(tmp, &from->si_addr);
+			to->si_addr = (void *) tmp;
+			break;
+		      case __SI_POLL >> 16:
+			err |= __get_user(to->si_band, &from->si_band);
+			err |= __get_user(to->si_fd, &from->si_fd);
+			break;
+			/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+	}
+	return err;
+}
+
+int
 copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from)
 {
 	int err;
 
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32)))
+	if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32)))
 		return -EFAULT;
 
 	/* If you change siginfo_t structure, please be sure
@@ -97,110 +143,329 @@
 	return err;
 }
 
+static inline void
+sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
+{
+	if (handler + 1 <= 2)
+		/* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */
+		sa->sa.sa_handler = (__sighandler_t) A((int) handler);
+	else
+		sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler);
+}
 
+asmlinkage long
+ia32_rt_sigsuspend (sigset32_t *uset, unsigned int sigsetsize, struct sigscratch *scr)
+{
+	extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall);
+	sigset_t oldset, set;
 
-static int
-setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
-                struct pt_regs *regs, unsigned long mask)
+	scr->scratch_unat = 0;	/* avoid leaking kernel bits to user level */
+	memset(&set, 0, sizeof(&set));
+
+	if (sigsetsize > sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&set.sig, &uset->sig, sigsetsize))
+		return -EFAULT;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	{
+		oldset = current->blocked;
+		current->blocked = set;
+		recalc_sigpending(current);
+	}
+	spin_unlock_irq(&current->sigmask_lock);
+
+	/*
+	 * The return below usually returns to the signal handler.  We need to pre-set the
+	 * correct error code here to ensure that the right values get saved in sigcontext
+	 * by ia64_do_signal.
+	 */
+	scr->pt.r8 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (ia64_do_signal(&oldset, scr, 1))
+			return -EINTR;
+	}
+}
+
+asmlinkage long
+ia32_sigsuspend (unsigned int mask, struct sigscratch *scr)
+{
+	return ia32_rt_sigsuspend((sigset32_t *)&mask, sizeof(mask), scr);
+}
+
+asmlinkage long
+sys32_signal (int sig, unsigned int handler)
+{
+	struct k_sigaction new_sa, old_sa;
+	int ret;
+
+	sigact_set_handler(&new_sa, handler, 0);
+	new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+
+	ret = do_sigaction(sig, &new_sa, &old_sa);
+
+	return ret ? ret : IA32_SA_HANDLER(&old_sa);
+}
+
+asmlinkage long
+sys32_rt_sigaction (int sig, struct sigaction32 *act,
+		    struct sigaction32 *oact, unsigned int sigsetsize)
+{
+	struct k_sigaction new_ka, old_ka;
+	unsigned int handler, restorer;
+	int ret;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset32_t))
+		return -EINVAL;
+
+	if (act) {
+		ret = get_user(handler, &act->sa_handler);
+		ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		ret |= get_user(restorer, &act->sa_restorer);
+		ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(sigset32_t));
+		if (ret)
+			return -EFAULT;
+
+		sigact_set_handler(&new_ka, handler, restorer);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler);
+		ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer);
+		ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(sigset32_t));
+	}
+	return ret;
+}
+
+
+extern asmlinkage long sys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset,
+					   size_t sigsetsize);
+
+asmlinkage long
+sys32_rt_sigprocmask (int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize)
+{
+	mm_segment_t old_fs = get_fs();
+	sigset_t s;
+	long ret;
+
+	if (sigsetsize > sizeof(s))
+		return -EINVAL;
+
+	if (set) {
+		memset(&s, 0, sizeof(s));
+		if (copy_from_user(&s.sig, set, sigsetsize))
+			return -EFAULT;
+	}
+	set_fs(KERNEL_DS);
+	ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s));
+	set_fs(old_fs);
+	if (ret)
+		return ret;
+	if (oset) {
+		if (copy_to_user(oset, &s.sig, sigsetsize))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+asmlinkage long
+sys32_sigprocmask (int how, unsigned int *set, unsigned int *oset)
 {
-       int  err = 0;
-       unsigned long flag;
+	return sys32_rt_sigprocmask(how, (sigset32_t *) set, (sigset32_t *) oset, sizeof(*set));
+}
 
-       err |= __put_user((regs->r16 >> 32) & 0xffff , (unsigned int *)&sc->fs);
-       err |= __put_user((regs->r16 >> 48) & 0xffff , (unsigned int *)&sc->gs);
+asmlinkage long
+sys32_rt_sigtimedwait (sigset32_t *uthese, siginfo_t32 *uinfo, struct timespec32 *uts,
+		       unsigned int sigsetsize)
+{
+	extern asmlinkage long sys_rt_sigtimedwait (const sigset_t *, siginfo_t *,
+						    const struct timespec *, size_t);
+	extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *);
+	mm_segment_t old_fs = get_fs();
+	struct timespec t;
+	siginfo_t info;
+	sigset_t s;
+	int ret;
 
-       err |= __put_user((regs->r16 >> 56) & 0xffff, (unsigned int *)&sc->es);
-       err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds);
-       err |= __put_user(regs->r15, &sc->edi);
-       err |= __put_user(regs->r14, &sc->esi);
-       err |= __put_user(regs->r13, &sc->ebp);
-       err |= __put_user(regs->r12, &sc->esp);
-       err |= __put_user(regs->r11, &sc->ebx);
-       err |= __put_user(regs->r10, &sc->edx);
-       err |= __put_user(regs->r9, &sc->ecx);
-       err |= __put_user(regs->r8, &sc->eax);
+	if (copy_from_user(&s.sig, uthese, sizeof(sigset32_t)))
+		return -EFAULT;
+	if (uts) {
+		ret = get_user(t.tv_sec, &uts->tv_sec);
+		ret |= get_user(t.tv_nsec, &uts->tv_nsec);
+		if (ret)
+			return -EFAULT;
+	}
+	set_fs(KERNEL_DS);
+	ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
+	set_fs(old_fs);
+	if (ret >= 0 && uinfo) {
+		if (copy_siginfo_to_user32(uinfo, &info))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage long
+sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo)
+{
+	extern asmlinkage long sys_rt_sigqueueinfo (int, int, siginfo_t *);
+	extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from);
+	mm_segment_t old_fs = get_fs();
+	siginfo_t info;
+	int ret;
+
+	if (copy_siginfo_from_user32(&info, uinfo))
+		return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_rt_sigqueueinfo(pid, sig, &info);
+	set_fs(old_fs);
+	return ret;
+}
+
+asmlinkage long
+sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	unsigned int handler, restorer;
+	int ret;
+
+	if (act) {
+		old_sigset32_t mask;
+
+		ret = get_user(handler, &act->sa_handler);
+		ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		ret |= get_user(restorer, &act->sa_restorer);
+		ret |= get_user(mask, &act->sa_mask);
+		if (ret)
+			return ret;
+
+		sigact_set_handler(&new_ka, handler, restorer);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler);
+		ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer);
+		ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+static int
+setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
+		       struct pt_regs *regs, unsigned long mask)
+{
+	int  err = 0;
+	unsigned long flag;
+
+	err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs);
+	err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs);
+	err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es);
+	err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds);
+	err |= __put_user(regs->r15, &sc->edi);
+	err |= __put_user(regs->r14, &sc->esi);
+	err |= __put_user(regs->r13, &sc->ebp);
+	err |= __put_user(regs->r12, &sc->esp);
+	err |= __put_user(regs->r11, &sc->ebx);
+	err |= __put_user(regs->r10, &sc->edx);
+	err |= __put_user(regs->r9, &sc->ecx);
+	err |= __put_user(regs->r8, &sc->eax);
 #if 0
-       err |= __put_user(current->tss.trap_no, &sc->trapno);
-       err |= __put_user(current->tss.error_code, &sc->err);
+	err |= __put_user(current->tss.trap_no, &sc->trapno);
+	err |= __put_user(current->tss.error_code, &sc->err);
 #endif
-       err |= __put_user(regs->cr_iip, &sc->eip);
-       err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs);
-       /*
-	*  `eflags' is in an ar register for this context
-	*/
-       asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag));
-       err |= __put_user((unsigned int)flag, &sc->eflags);
-       
-       err |= __put_user(regs->r12, &sc->esp_at_signal);
-       err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
+	err |= __put_user(regs->cr_iip, &sc->eip);
+	err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs);
+	/*
+	 *  `eflags' is in an ar register for this context
+	 */
+	asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag));
+	err |= __put_user((unsigned int)flag, &sc->eflags);
+	err |= __put_user(regs->r12, &sc->esp_at_signal);
+	err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
 
 #if 0
-       tmp = save_i387(fpstate);
-       if (tmp < 0)
-         err = 1;
-       else
-         err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+	tmp = save_i387(fpstate);
+	if (tmp < 0)
+		err = 1;
+	else
+		err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
 
-       /* non-iBCS2 extensions.. */
+	/* non-iBCS2 extensions.. */
 #endif
-       err |= __put_user(mask, &sc->oldmask);
+	err |= __put_user(mask, &sc->oldmask);
 #if 0
-       err |= __put_user(current->tss.cr2, &sc->cr2);
+	err |= __put_user(current->tss.cr2, &sc->cr2);
 #endif
-       
-       return err;
+	return err;
 }
 
 static int
-restore_sigcontext_ia32(struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax)
+restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax)
 {
-       unsigned int err = 0;
+	unsigned int err = 0;
+
+#define COPY(ia64x, ia32x)	err |= __get_user(regs->ia64x, &sc->ia32x)
 
-#define COPY(ia64x, ia32x)             err |= __get_user(regs->ia64x, &sc->ia32x)
+#define copyseg_gs(tmp)		(regs->r16 |= (unsigned long) tmp << 48)
+#define copyseg_fs(tmp)		(regs->r16 |= (unsigned long) tmp << 32)
+#define copyseg_cs(tmp)		(regs->r17 |= tmp)
+#define copyseg_ss(tmp)		(regs->r17 |= (unsigned long) tmp << 16)
+#define copyseg_es(tmp)		(regs->r16 |= (unsigned long) tmp << 16)
+#define copyseg_ds(tmp)		(regs->r16 |= tmp)
+
+#define COPY_SEG(seg)					\
+	{						\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		copyseg_##seg(tmp);			\
+	}
+#define COPY_SEG_STRICT(seg)				\
+	{						\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		copyseg_##seg(tmp|3);			\
+	}
 
-#define copyseg_gs(tmp)        (regs->r16 |= (unsigned long) tmp << 48)
-#define copyseg_fs(tmp)        (regs->r16 |= (unsigned long) tmp << 32)
-#define copyseg_cs(tmp)        (regs->r17 |= tmp)
-#define copyseg_ss(tmp)        (regs->r17 |= (unsigned long) tmp << 16)
-#define copyseg_es(tmp)        (regs->r16 |= (unsigned long) tmp << 16)
-#define copyseg_ds(tmp)        (regs->r16 |= tmp)
-
-#define COPY_SEG(seg)                                          \
-       { unsigned short tmp;                                   \
-         err |= __get_user(tmp, &sc->seg);                             \
-         copyseg_##seg(tmp); }
-
-#define COPY_SEG_STRICT(seg)                                   \
-       { unsigned short tmp;                                   \
-         err |= __get_user(tmp, &sc->seg);                             \
-         copyseg_##seg(tmp|3); }
-
-       /* To make COPY_SEGs easier, we zero r16, r17 */
-       regs->r16 = 0;
-       regs->r17 = 0;
-
-       COPY_SEG(gs);
-       COPY_SEG(fs);
-       COPY_SEG(es);
-       COPY_SEG(ds);
-       COPY(r15, edi);
-       COPY(r14, esi);
-       COPY(r13, ebp);
-       COPY(r12, esp);
-       COPY(r11, ebx);
-       COPY(r10, edx);
-       COPY(r9, ecx);
-       COPY(cr_iip, eip);
-       COPY_SEG_STRICT(cs);
-       COPY_SEG_STRICT(ss);
-       {
+	/* To make COPY_SEGs easier, we zero r16, r17 */
+	regs->r16 = 0;
+	regs->r17 = 0;
+
+	COPY_SEG(gs);
+	COPY_SEG(fs);
+	COPY_SEG(es);
+	COPY_SEG(ds);
+	COPY(r15, edi);
+	COPY(r14, esi);
+	COPY(r13, ebp);
+	COPY(r12, esp);
+	COPY(r11, ebx);
+	COPY(r10, edx);
+	COPY(r9, ecx);
+	COPY(cr_iip, eip);
+	COPY_SEG_STRICT(cs);
+	COPY_SEG_STRICT(ss);
+	ia32_load_segment_descriptors(current);
+	{
 		unsigned int tmpflags;
 		unsigned long flag;
 
 		/*
-		 *  IA32 `eflags' is not part of `pt_regs', it's
-		 *  in an ar register which is part of the thread
-		 *  context.  Fortunately, we are executing in the
+		 *  IA32 `eflags' is not part of `pt_regs', it's in an ar register which
+		 *  is part of the thread context.  Fortunately, we are executing in the
 		 *  IA32 process's context.
 		 */
 		err |= __get_user(tmpflags, &sc->eflags);
@@ -210,186 +475,191 @@
 		asm volatile ("mov ar.eflag=%0 ;;" :: "r"(flag));
 
 		regs->r1 = -1;	/* disable syscall checks, r1 is orig_eax */
-       }
+	}
 
 #if 0
-       {
-               struct _fpstate * buf;
-               err |= __get_user(buf, &sc->fpstate);
-               if (buf) {
-                       if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
-               }
-       }
+	{
+		struct _fpstate * buf;
+		err |= __get_user(buf, &sc->fpstate);
+		if (buf) {
+			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+				goto badframe;
+			err |= restore_i387(buf);
+		}
+	}
 #endif
 
-       err |= __get_user(*peax, &sc->eax);
-       return err;
+	err |= __get_user(*peax, &sc->eax);
+	return err;
 
-#if 0       
-badframe:
-       return 1;
+#if 0
+  badframe:
+	return 1;
 #endif
-
 }
 
 /*
  * Determine which stack to use..
  */
 static inline void *
-get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 {
-       unsigned long esp;
-       unsigned int xss;
+	unsigned long esp;
 
-       /* Default to using normal stack */
-       esp = regs->r12;
-       xss = regs->r16 >> 16;
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (! on_sig_stack(esp))
-                       esp = current->sas_ss_sp + current->sas_ss_size;
-       }
-       /* Legacy stack switching not supported */
-       
-       return (void *)((esp - frame_size) & -8ul);
+	/* Default to using normal stack (truncate off sign-extension of bit 31: */
+	esp = (unsigned int) regs->r12;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (!on_sig_stack(esp))
+			esp = current->sas_ss_sp + current->sas_ss_size;
+	}
+	/* Legacy stack switching not supported */
+
+	return (void *)((esp - frame_size) & -8ul);
 }
 
 static int
-setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set,
-           struct pt_regs * regs) 
-{      
-       struct sigframe_ia32 *frame;
-       int err = 0;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       err |= __put_user((current->exec_domain
-                          && current->exec_domain->signal_invmap
-                          && sig < 32
-                          ? (int)(current->exec_domain->signal_invmap[sig])
-                          : sig),
-                         &frame->sig);
-
-       err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]);
-
-       if (_IA32_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.  */
-       err |= __put_user((long)frame->retcode, &frame->pretcode);
-       /* This is popl %eax ; movl $,%eax ; int $0x80 */
-       err |= __put_user(0xb858, (short *)(frame->retcode+0));
-#define __IA32_NR_sigreturn            119
-       err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2));
-       err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4));
-       err |= __put_user(0x80cd, (short *)(frame->retcode+6));
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       regs->r12 = (unsigned long) frame;
-       regs->cr_iip = (unsigned long) ka->sa.sa_handler;
-
-       set_fs(USER_DS);
-       regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
-       regs->r17 = (__USER_DS << 16) | __USER_CS;
+setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs)
+{
+	struct sigframe_ia32 *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user((current->exec_domain
+			   && current->exec_domain->signal_invmap
+			   && sig < 32
+			   ? (int)(current->exec_domain->signal_invmap[sig])
+			   : sig),
+			  &frame->sig);
+
+	err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+
+	if (_IA32_NSIG_WORDS > 1)
+		err |= __copy_to_user(frame->extramask, (char *) &set->sig + 4,
+				      sizeof(frame->extramask));
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		unsigned int restorer = IA32_SA_RESTORER(ka);
+		err |= __put_user(restorer, &frame->pretcode);
+	} else {
+		err |= __put_user((long)frame->retcode, &frame->pretcode);
+		/* This is popl %eax ; movl $,%eax ; int $0x80 */
+		err |= __put_user(0xb858, (short *)(frame->retcode+0));
+		err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2));
+		err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	regs->r12 = (unsigned long) frame;
+	regs->cr_iip = IA32_SA_HANDLER(ka);
+
+	set_fs(USER_DS);
+	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS;
 
 #if 0
-       regs->eflags &= ~TF_MASK;
+	regs->eflags &= ~TF_MASK;
 #endif
 
 #if 0
-       printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n",
+	printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n",
                current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode);
 #endif
 
-       return 1;
+	return 1;
 
-give_sigsegv:
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
-       return 0;
+  give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 static int
-setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info,
-              sigset_t *set, struct pt_regs * regs)
+setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
+		     sigset_t *set, struct pt_regs * regs)
 {
-       struct rt_sigframe_ia32 *frame;
-       int err = 0;
+	struct rt_sigframe_ia32 *frame;
+	int err = 0;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       err |= __put_user((current->exec_domain
-                          && current->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
-       err |= __put_user((long)&frame->info, &frame->pinfo);
-       err |= __put_user((long)&frame->uc, &frame->puc);
-       err |= copy_siginfo_to_user32(&frame->info, info);
-
-       /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
-       err |= __put_user(0, &frame->uc.uc_link);
-       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(regs->r12),
-                         &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate,
-                               regs, set->sig[0]);
-       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-       
-       err |= __put_user((long)frame->retcode, &frame->pretcode);
-       /* This is movl $,%eax ; int $0x80 */
-       err |= __put_user(0xb8, (char *)(frame->retcode+0));
-#define __IA32_NR_rt_sigreturn         173
-       err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
-       err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user((current->exec_domain
+			   && current->exec_domain->signal_invmap
+			   && sig < 32
+			   ? current->exec_domain->signal_invmap[sig]
+			   : sig),
+			  &frame->sig);
+	err |= __put_user((long)&frame->info, &frame->pinfo);
+	err |= __put_user((long)&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user32(&frame->info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->r12), &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		unsigned int restorer = IA32_SA_RESTORER(ka);
+		err |= __put_user(restorer, &frame->pretcode);
+	} else {
+		err |= __put_user((long)frame->retcode, &frame->pretcode);
+		/* This is movl $,%eax ; int $0x80 */
+		err |= __put_user(0xb8, (char *)(frame->retcode+0));
+		err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+	}
 
-       if (err)
-               goto give_sigsegv;
+	if (err)
+		goto give_sigsegv;
 
-       /* Set up registers for signal handler */
-       regs->r12 = (unsigned long) frame;
-       regs->cr_iip = (unsigned long) ka->sa.sa_handler;
+	/* Set up registers for signal handler */
+	regs->r12 = (unsigned long) frame;
+	regs->cr_iip = IA32_SA_HANDLER(ka);
 
-       set_fs(USER_DS);
+	set_fs(USER_DS);
 
-       regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
-       regs->r17 = (__USER_DS << 16) | __USER_CS;
+	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS;
 
 #if 0
-       regs->eflags &= ~TF_MASK;
+	regs->eflags &= ~TF_MASK;
 #endif
 
 #if 0
-       printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
+	printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
                current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode);
 #endif
 
-       return 1;
+	return 1;
 
 give_sigsegv:
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
-       return 0;
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 int
@@ -398,95 +668,78 @@
 {
        /* Set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
-               return(setup_rt_frame_ia32(sig, ka, info, set, regs));
+               return setup_rt_frame_ia32(sig, ka, info, set, regs);
        else
-               return(setup_frame_ia32(sig, ka, set, regs));
+               return setup_frame_ia32(sig, ka, set, regs);
 }
 
-asmlinkage int
-sys32_sigreturn(
-int arg0,
-int arg1,
-int arg2,
-int arg3,
-int arg4,
-int arg5,
-int arg6,
-int arg7,
-unsigned long stack)
-{
-       struct pt_regs *regs = (struct pt_regs *) &stack;
-       struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8);
-       sigset_t set;
-       int eax;
-
-       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-
-       if (__get_user(set.sig[0], &frame->sc.oldmask)
-           || (_IA32_NSIG_WORDS > 1
-               && __copy_from_user((((char *) &set.sig) + 4),
-                                   &frame->extramask,
-                                   sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sigmask_lock);
-       current->blocked = (sigset_t) set;
-       recalc_sigpending(current);
-       spin_unlock_irq(&current->sigmask_lock);
-       
-       if (restore_sigcontext_ia32(regs, &frame->sc, &eax))
-               goto badframe;
-       return eax;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}      
-
-asmlinkage int
-sys32_rt_sigreturn(
-int arg0,
-int arg1,
-int arg2,
-int arg3,
-int arg4,
-int arg5,
-int arg6,
-int arg7,
-unsigned long stack)
-{
-       struct pt_regs *regs = (struct pt_regs *) &stack;
-       struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4);
-       sigset_t set;
-       stack_t st;
-       int eax;
-
-       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sigmask_lock);
-       current->blocked =  set;
-       recalc_sigpending(current);
-       spin_unlock_irq(&current->sigmask_lock);
-       
-       if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax))
-               goto badframe;
-
-       if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
-               goto badframe;
-       /* It is more difficult to avoid calling this function than to
-          call it and ignore errors.  */
-       do_sigaltstack(&st, NULL, regs->r12);
-
-       return eax;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}      
+asmlinkage long
+sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7,
+		 unsigned long stack)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stack;
+	unsigned long esp = (unsigned int) regs->r12;
+	struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(esp - 8);
+	sigset_t set;
+	int eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+
+	if (__get_user(set.sig[0], &frame->sc.oldmask)
+	    || (_IA32_NSIG_WORDS > 1 && __copy_from_user((char *) &set.sig + 4, &frame->extramask,
+							 sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = (sigset_t) set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (restore_sigcontext_ia32(regs, &frame->sc, &eax))
+		goto badframe;
+	return eax;
+
+  badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
 
+asmlinkage long
+sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7,
+		    unsigned long stack)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stack;
+	unsigned long esp = (unsigned int) regs->r12;
+	struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(esp - 4);
+	sigset_t set;
+	stack_t st;
+	int eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked =  set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, esp);
+
+	return eax;
+
+  badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)