]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/signal_32.c
Merge branch 'x86/unify-cpu-detect' into x86-v28-for-linus-phase4-D
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / signal_32.c
index 6fb5bcdd893366c66ccae845f2b1a20c076fa2f3..b21070ea33a485c314ed8538288632fb8fa2a869 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/tracehook.h>
 #include <linux/elf.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
@@ -26,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/syscalls.h>
 
 #include "sigframe.h"
 
@@ -159,28 +161,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
        }
 
        {
-               struct _fpstate __user *buf;
+               void __user *buf;
 
                err |= __get_user(buf, &sc->fpstate);
-               if (buf) {
-                       if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
-               } else {
-                       struct task_struct *me = current;
-
-                       if (used_math()) {
-                               clear_fpu(me);
-                               clear_used_math();
-                       }
-               }
+               err |= restore_i387_xstate(buf);
        }
 
        err |= __get_user(*pax, &sc->ax);
        return err;
-
-badframe:
-       return 1;
 }
 
 asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
@@ -262,7 +250,7 @@ badframe:
  * Set up a signal frame.
  */
 static int
-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
+setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
                 struct pt_regs *regs, unsigned long mask)
 {
        int tmp, err = 0;
@@ -289,7 +277,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
        err |= __put_user(regs->sp, &sc->sp_at_signal);
        err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
 
-       tmp = save_i387(fpstate);
+       tmp = save_i387_xstate(fpstate);
        if (tmp < 0)
                err = 1;
        else
@@ -306,7 +294,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
  * Determine which stack to use..
  */
 static inline void __user *
-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,
+            void **fpstate)
 {
        unsigned long sp;
 
@@ -332,6 +321,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
                        sp = (unsigned long) ka->sa.sa_restorer;
        }
 
+       if (used_math()) {
+               sp = sp - sig_xstate_size;
+               *fpstate = (struct _fpstate *) sp;
+       }
+
        sp -= frame_size;
        /*
         * Align the stack pointer according to the i386 ABI,
@@ -350,8 +344,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
        void __user *restorer;
        int err = 0;
        int usig;
+       void __user *fpstate = NULL;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
                goto give_sigsegv;
@@ -366,7 +361,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
        if (err)
                goto give_sigsegv;
 
-       err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+       err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
        if (err)
                goto give_sigsegv;
 
@@ -427,8 +422,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        void __user *restorer;
        int err = 0;
        int usig;
+       void __user *fpstate = NULL;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
                goto give_sigsegv;
@@ -447,13 +443,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                goto give_sigsegv;
 
        /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
+       if (cpu_has_xsave)
+               err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+       else
+               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->sp),
                          &frame->uc.uc_stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+       err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
                                regs, set->sig[0]);
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
        if (err)
@@ -558,8 +557,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
         * handler too.
         */
        regs->flags &= ~X86_EFLAGS_TF;
-       if (test_thread_flag(TIF_SINGLESTEP))
-               ptrace_notify(SIGTRAP);
 
        spin_lock_irq(&current->sighand->siglock);
        sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@@ -568,6 +565,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
+       tracehook_signal_handler(sig, info, ka, regs,
+                                test_thread_flag(TIF_SINGLESTEP));
+
        return 0;
 }
 
@@ -661,5 +661,10 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs);
 
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+       }
+
        clear_thread_flag(TIF_IRET);
 }