fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / ia64 / kernel / signal.c
index 135cb55..fd0145d 100644 (file)
@@ -7,11 +7,10 @@
  * Derived from i386 and Alpha versions.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
@@ -84,18 +83,17 @@ ia64_rt_sigsuspend (sigset_t __user *uset, size_t sigsetsize, struct sigscratch
 }
 
 asmlinkage long
-sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2, long arg3, long arg4,
-                long arg5, long arg6, long arg7, long stack)
+sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2,
+                long arg3, long arg4, long arg5, long arg6, long arg7,
+                struct pt_regs regs)
 {
-       struct pt_regs *pt = (struct pt_regs *) &stack;
-
-       return do_sigaltstack(uss, uoss, pt->r12);
+       return do_sigaltstack(uss, uoss, regs.r12);
 }
 
 static long
 restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
 {
-       unsigned long ip, flags, nat, um, cfm;
+       unsigned long ip, flags, nat, um, cfm, rsc;
        long err;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -107,7 +105,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
        err |= __get_user(ip, &sc->sc_ip);                      /* instruction pointer */
        err |= __get_user(cfm, &sc->sc_cfm);
        err |= __get_user(um, &sc->sc_um);                      /* user mask */
-       err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc);
+       err |= __get_user(rsc, &sc->sc_ar_rsc);
        err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat);
        err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr);
        err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs);
@@ -120,6 +118,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
        err |= __copy_from_user(&scr->pt.r15, &sc->sc_gr[15], 8);       /* r15 */
 
        scr->pt.cr_ifs = cfm | (1UL << 63);
+       scr->pt.ar_rsc = rsc | (3 << 2); /* force PL3 */
 
        /* establish new instruction pointer: */
        scr->pt.cr_iip = ip & ~0x3UL;
@@ -143,6 +142,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
 
                __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
                psr->mfh = 0;   /* drop signal handler's fph contents... */
+               preempt_disable();
                if (psr->dfh)
                        ia64_drop_fpu(current);
                else {
@@ -150,6 +150,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
                        __ia64_load_fpu(current->thread.fph);
                        ia64_set_local_fpu_owner(current);
                }
+               preempt_enable();
        }
        return err;
 }
@@ -225,7 +226,8 @@ ia64_rt_sigreturn (struct sigscratch *scr)
         * could be corrupted.
         */
        retval = (long) &ia64_leave_kernel;
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
+       if (test_thread_flag(TIF_SYSCALL_TRACE)
+           || test_thread_flag(TIF_SYSCALL_AUDIT))
                /*
                 * strace expects to be notified after sigreturn returns even though the
                 * context to which we return may not be in the middle of a syscall.
@@ -290,12 +292,10 @@ setup_sigcontext (struct sigcontext __user *sc, sigset_t *mask, struct sigscratc
 
        if (on_sig_stack((unsigned long) sc))
                flags |= IA64_SC_FLAG_ONSTACK;
-       if ((ifs & (1UL << 63)) == 0) {
-               /* if cr_ifs isn't valid, we got here through a syscall */
+       if ((ifs & (1UL << 63)) == 0)
+               /* if cr_ifs doesn't have the valid bit set, we got here through a syscall */
                flags |= IA64_SC_FLAG_IN_SYSCALL;
-               cfm = scr->ar_pfs & ((1UL << 38) - 1);
-       } else
-               cfm = ifs & ((1UL << 38) - 1);
+       cfm = ifs & ((1UL << 38) - 1);
        ia64_flush_fph(current);
        if ((current->thread.flags & IA64_THREAD_FPH_VALID)) {
                flags |= IA64_SC_FLAG_FPH_VALID;
@@ -386,15 +386,14 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
             struct sigscratch *scr)
 {
        extern char __kernel_sigtramp[];
-       unsigned long tramp_addr, new_rbs = 0;
+       unsigned long tramp_addr, new_rbs = 0, new_sp;
        struct sigframe __user *frame;
        long err;
 
-       frame = (void __user *) scr->pt.r12;
+       new_sp = scr->pt.r12;
        tramp_addr = (unsigned long) __kernel_sigtramp;
-       if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
-               frame = (void __user *) ((current->sas_ss_sp + current->sas_ss_size)
-                                        & ~(STACK_ALIGN - 1));
+       if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(new_sp) == 0) {
+               new_sp = current->sas_ss_sp + current->sas_ss_size;
                /*
                 * We need to check for the register stack being on the signal stack
                 * separately, because it's switched separately (memory stack is switched
@@ -403,7 +402,7 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
                if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
                        new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
        }
-       frame = (void __user *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
+       frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
                return force_sigsegv_info(sig, frame);
@@ -466,15 +465,14 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
                if (!setup_frame(sig, ka, info, oldset, scr))
                        return 0;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               {
-                       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-                       sigaddset(&current->blocked, sig);
-                       recalc_sigpending();
-               }
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       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);
+
+       tracehook_report_handle_signal(sig, ka, oldset, &scr->pt);
        return 1;
 }