/*
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
  *
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
+ *  2000-2002   x86-64 support by Andi Kleen
  */
 
 #include <linux/sched.h>
 }
 #endif /* CONFIG_X86_32 */
 
+#ifdef CONFIG_X86_32
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 
        return ret;
 }
+#endif /* CONFIG_X86_32 */
 
 #ifdef CONFIG_X86_32
 asmlinkage int sys_sigaltstack(unsigned long bx)
 /*
  * Do a signal return; undo the signal stack.
  */
+#ifdef CONFIG_X86_32
 asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
 {
        struct sigframe __user *frame;
 
        return 0;
 }
+#endif /* CONFIG_X86_32 */
 
 static long do_rt_sigreturn(struct pt_regs *regs)
 {
 
        err |= __get_user(regs->x, &sc->x);     \
 }
 
+#define COPY_SEG(seg)          {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp;                        \
+}
+
 #define COPY_SEG_CPL3(seg)     {                       \
                unsigned short tmp;                     \
                err |= __get_user(tmp, &sc->seg);       \
                regs->seg = tmp | 3;                    \
 }
 
+#define GET_SEG(seg)           {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               loadsegment(seg, tmp);                  \
+}
+
 static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
                   unsigned long *pax)
 }
 #endif /* CONFIG_X86_32 */
 
+#ifdef CONFIG_X86_32
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+       mask &= _BLOCKABLE;
+       spin_lock_irq(¤t->sighand->siglock);
+       current->saved_sigmask = current->blocked;
+       siginitset(¤t->blocked, mask);
+       recalc_sigpending();
+       spin_unlock_irq(¤t->sighand->siglock);
+
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_restore_sigmask();
+
+       return -ERESTARTNOHAND;
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+             struct old_sigaction __user *oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       if (act) {
+               old_sigset_t mask;
+
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+                       return -EFAULT;
+
+               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               __get_user(mask, &act->sa_mask);
+               siginitset(&new_ka.sa.sa_mask, mask);
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+                       return -EFAULT;
+
+               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+       }
+
+       return ret;
+}
+#endif /* CONFIG_X86_32 */
+
 #ifdef CONFIG_X86_32
 asmlinkage int sys_sigaltstack(unsigned long bx)
 {
 /*
  * Do a signal return; undo the signal stack.
  */
+#ifdef CONFIG_X86_32
+asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
+{
+       struct sigframe __user *frame;
+       struct pt_regs *regs;
+       unsigned long ax;
+       sigset_t set;
+
+       regs = (struct pt_regs *) &__unused;
+       frame = (struct sigframe __user *)(regs->sp - 8);
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1
+               && __copy_from_user(&set.sig[1], &frame->extramask,
+                                   sizeof(frame->extramask))))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(¤t->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(¤t->sighand->siglock);
+
+       if (restore_sigcontext(regs, &frame->sc, &ax))
+               goto badframe;
+       return ax;
+
+badframe:
+       if (show_unhandled_signals && printk_ratelimit()) {
+               printk("%s%s[%d] bad frame in sigreturn frame:"
+                       "%p ip:%lx sp:%lx oeax:%lx",
+                   task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
+                   current->comm, task_pid_nr(current), frame, regs->ip,
+                   regs->sp, regs->orig_ax);
+               print_vma_addr(" in ", regs->ip);
+               printk(KERN_CONT "\n");
+       }
+
+       force_sig(SIGSEGV, current);
+
+       return 0;
+}
+#endif /* CONFIG_X86_32 */
+
 static long do_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
 #endif /* CONFIG_X86_32 */
 
 /*
- * OK, we're invoking a handler
+ * OK, we're invoking a handler:
  */
 static int signr_convert(int sig)
 {