vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc64 / kernel / signal32.c
index 106f008..145eac7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/elf.h>
 #include <linux/compat.h>
+#include <linux/ptrace.h>
 #include <asm/ppc32.h>
 #include <asm/uaccess.h>
 #include <asm/ppcdebug.h>
@@ -71,7 +72,7 @@ struct sigregs32 {
  *
  */
 struct rt_sigframe32 {
-       struct compat_siginfo   info;
+       compat_siginfo_t        info;
        struct ucontext32       uc;
        /*
         * Programs using the rs6000/xcoff abi can save up to 19 gp
@@ -189,7 +190,7 @@ static long restore_user_regs(struct pt_regs *regs,
        elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
        int i;
        long err = 0;
-       unsigned int save_r2;
+       unsigned int save_r2 = 0;
 #ifdef CONFIG_ALTIVEC
        unsigned long msr;
 #endif
@@ -227,13 +228,21 @@ static long restore_user_regs(struct pt_regs *regs,
                                     sizeof(sr->mc_vregs)))
                        return 1;
        } else if (current->thread.used_vr)
-               memset(&current->thread.vr, 0, ELF_NVRREG32 * sizeof(vector128));
+               memset(current->thread.vr, 0, ELF_NVRREG32 * sizeof(vector128));
 
        /* Always get VRSAVE back */
        if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32]))
                return 1;
 #endif /* CONFIG_ALTIVEC */
 
+#ifndef CONFIG_SMP
+       preempt_disable();
+       if (last_task_used_math == current)
+               last_task_used_math = NULL;
+       if (last_task_used_altivec == current)
+               last_task_used_altivec = NULL;
+       preempt_enable();
+#endif
        return 0;
 }
 
@@ -276,14 +285,12 @@ long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
                schedule();
                if (do_signal32(&saveset, regs))
                        /*
-                        * If a signal handler needs to be called,
-                        * do_signal32() has set R3 to the signal number (the
-                        * first argument of the signal handler), so don't
-                        * overwrite that with EINTR !
-                        * In the other cases, do_signal32() doesn't touch 
-                        * R3, so it's still set to -EINTR (see above).
+                        * Returning 0 means we return to userspace via
+                        * ret_from_except and thus restore all user
+                        * registers from *regs.  This is what we need
+                        * to do when a signal has been delivered.
                         */
-                       return regs->gpr[3];
+                       return 0;
        }
 }
 
@@ -334,7 +341,6 @@ long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
  *       sigpending               sys32_rt_sigpending
  *       sigprocmask              sys32_rt_sigprocmask
  *       sigreturn                sys32_rt_sigreturn
- *       sigtimedwait             sys32_rt_sigtimedwait
  *       sigqueueinfo             sys32_rt_sigqueueinfo
  *       sigsuspend               sys32_rt_sigsuspend
  *
@@ -438,9 +444,9 @@ long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
 }
 
 
-static long copy_siginfo_to_user32(compat_siginfo_t __user *d, siginfo_t *s)
+int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)
 {
-       long err;
+       int err;
 
        if (!access_ok (VERIFY_WRITE, d, sizeof(*d)))
                return -EFAULT;
@@ -472,10 +478,14 @@ static long copy_siginfo_to_user32(compat_siginfo_t __user *d, siginfo_t *s)
                                  &d->si_addr);
                break;
        case __SI_POLL >> 16:
-       case __SI_TIMER >> 16:
                err |= __put_user(s->si_band, &d->si_band);
                err |= __put_user(s->si_fd, &d->si_fd);
                break;
+       case __SI_TIMER >> 16:
+               err |= __put_user(s->si_tid, &d->si_tid);
+               err |= __put_user(s->si_overrun, &d->si_overrun);
+               err |= __put_user(s->si_int, &d->si_int);
+               break;
        case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
        case __SI_MESGQ >> 16:
                err |= __put_user(s->si_int, &d->si_int);
@@ -489,35 +499,6 @@ static long copy_siginfo_to_user32(compat_siginfo_t __user *d, siginfo_t *s)
        return err;
 }
 
-long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, compat_siginfo_t __user *uinfo,
-               struct compat_timespec __user *uts, compat_size_t sigsetsize)
-{
-       sigset_t s;
-       compat_sigset_t s32;
-       struct timespec t;
-       int ret;
-       mm_segment_t old_fs = get_fs();
-       siginfo_t info;
-
-       if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
-               return -EFAULT;
-       sigset_from_compat(&s, &s32);
-       if (uts && get_compat_timespec(&t, uts))
-               return -EFAULT;
-       set_fs(KERNEL_DS);
-       /* The __user pointer casts are valid because of the set_fs() */
-       ret = sys_rt_sigtimedwait((sigset_t __user *) &s,
-                       uinfo ? (siginfo_t __user *) &info : NULL,
-                       uts ? (struct timespec __user *) &t : NULL,
-                       sigsetsize);
-       set_fs(old_fs);
-       if (ret >= 0 && uinfo) {
-               if (copy_siginfo_to_user32(uinfo, &info))
-                       return -EFAULT;
-       }
-       return ret;
-}
-
 /*
  * Note: it is necessary to treat pid and sig as unsigned ints, with the
  * corresponding cast to a signed int to insure that the proper conversion
@@ -575,14 +556,12 @@ int sys32_rt_sigsuspend(compat_sigset_t __user * unewset, size_t sigsetsize, int
                schedule();
                if (do_signal32(&saveset, regs))
                        /*
-                        * If a signal handler needs to be called,
-                        * do_signal32() has set R3 to the signal number (the
-                        * first argument of the signal handler), so don't
-                        * overwrite that with EINTR !
-                        * In the other cases, do_signal32() doesn't touch 
-                        * R3, so it's still set to -EINTR (see above).
+                        * Returning 0 means we return to userspace via
+                        * ret_from_except and thus restore all user
+                        * registers from *regs.  This is what we need
+                        * to do when a signal has been delivered.
                         */
-                       return regs->gpr[3];
+                       return 0;
        }
 }
 
@@ -641,9 +620,9 @@ int sys32_sigaltstack(u32 __new, u32 __old, int r5,
  * Set up a signal frame for a "real-time" signal handler
  * (one which gets siginfo).
  */
-static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
-                              siginfo_t *info, sigset_t *oldset,
-                              struct pt_regs * regs, unsigned long newsp)
+static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
+                             siginfo_t *info, sigset_t *oldset,
+                             struct pt_regs * regs, unsigned long newsp)
 {
        struct rt_sigframe32 __user *rt_sf;
        struct mcontext32 __user *frame;
@@ -692,16 +671,18 @@ static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
        regs->trap = 0;
        regs->result = 0;
 
-       return;
+       if (test_thread_flag(TIF_SINGLESTEP))
+               ptrace_notify(SIGTRAP);
+
+       return 1;
 
 badframe:
 #if DEBUG_SIG
        printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
               regs, frame, newsp);
 #endif
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(sig, current);
+       return 0;
 }
 
 static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig)
@@ -812,7 +793,7 @@ long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
 /*
  * OK, we're invoking a handler
  */
-static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
+static int handle_signal32(unsigned long sig, struct k_sigaction *ka,
                            siginfo_t *info, sigset_t *oldset,
                            struct pt_regs * regs, unsigned long newsp)
 {
@@ -857,16 +838,18 @@ static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
        regs->trap = 0;
        regs->result = 0;
 
-       return;
+       if (test_thread_flag(TIF_SINGLESTEP))
+               ptrace_notify(SIGTRAP);
+
+       return 1;
 
 badframe:
 #if DEBUG_SIG
        printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n",
               regs, frame, *newspp);
 #endif
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(sig, current);
+       return 0;
 }
 
 /*
@@ -928,18 +911,16 @@ badframe:
 int do_signal32(sigset_t *oldset, struct pt_regs *regs)
 {
        siginfo_t info;
-       struct k_sigaction *ka;
        unsigned int frame, newsp;
        int signr, ret;
+       struct k_sigaction ka;
 
        if (!oldset)
                oldset = &current->blocked;
 
        newsp = frame = 0;
 
-       signr = get_signal_to_deliver(&info, regs, NULL);
-
-       ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
        if (TRAP(regs) == 0x0C00                /* System Call! */
            && regs->ccr & 0x10000000           /* error signalled */
@@ -950,7 +931,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
                if (signr > 0
                    && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
                        || (ret == ERESTARTSYS
-                           && !(ka->sa.sa_flags & SA_RESTART)))) {
+                           && !(ka.sa.sa_flags & SA_RESTART)))) {
                        /* make the system call return an EINTR error */
                        regs->result = -EINTR;
                        regs->gpr[3] = EINTR;
@@ -969,7 +950,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
        if (signr == 0)
                return 0;               /* no signals delivered */
 
-       if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+       if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
            && (!on_sig_stack(regs->gpr[1])))
                newsp = (current->sas_ss_sp + current->sas_ss_size);
        else
@@ -977,21 +958,19 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
        newsp &= ~0xfUL;
 
        /* Whee!  Actually deliver the signal.  */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               handle_rt_signal32(signr, ka, &info, oldset, regs, newsp);
+       if (ka.sa.sa_flags & SA_SIGINFO)
+               ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp);
        else
-               handle_signal32(signr, ka, &info, oldset, regs, newsp);
-
-       if (ka->sa.sa_flags & SA_ONESHOT)
-               ka->sa.sa_handler = SIG_DFL;
+               ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret && !(ka.sa.sa_flags & SA_NODEFER)) {
                spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+               sigorsets(&current->blocked, &current->blocked,
+                         &ka.sa.sa_mask);
                sigaddset(&current->blocked, signr);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
 
-       return 1;
+       return ret;
 }