]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/signal_32.c
Merge branch 'x86/pebs' into x86/unify-cpu-detect
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / signal_32.c
index 6fb5bcdd893366c66ccae845f2b1a20c076fa2f3..8d380b699c0cc4327e2afc8581ac8449928d76a8 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/syscalls.h>
 
 #include "sigframe.h"
 
@@ -159,28 +160,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 +249,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 +276,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 +293,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 +320,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 +343,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 +360,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 +421,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 +442,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)