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),
 
 # define _fpstate_ia32         _fpstate
 # define _xstate_ia32          _xstate
 # define sig_xstate_ia32_size   sig_xstate_size
+# define fx_sw_reserved_ia32   fx_sw_reserved
 # define user_i387_ia32_struct user_i387_struct
 # define user32_fxsr_struct    user_fxsr_struct
 #endif
        if (err)
                return -1;
 
-       if (__copy_to_user(&buf->_fxsr_env[0], fx,
-                          sizeof(struct i387_fxsave_struct)))
+       if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
                return -1;
        return 1;
 }
 
+static int save_i387_xsave(void __user *buf)
+{
+       struct _fpstate_ia32 __user *fx = buf;
+       int err = 0;
+
+       if (save_i387_fxsave(fx) < 0)
+               return -1;
+
+       err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
+                            sizeof(struct _fpx_sw_bytes));
+       err |= __put_user(FP_XSTATE_MAGIC2,
+                         (__u32 __user *) (buf + sig_xstate_ia32_size
+                                           - FP_XSTATE_MAGIC2_SIZE));
+       if (err)
+               return -1;
+
+       return 1;
+}
+
 int save_i387_xstate_ia32(void __user *buf)
 {
        struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
 
        unlazy_fpu(tsk);
 
+       if (cpu_has_xsave)
+               return save_i387_xsave(fp);
        if (cpu_has_fxsr)
                return save_i387_fxsave(fp);
        else
                                sizeof(struct i387_fsave_struct));
 }
 
-static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
+static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
+                              unsigned int size)
 {
        struct task_struct *tsk = current;
        struct user_i387_ia32_struct env;
        int err;
 
        err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
-                              sizeof(struct i387_fxsave_struct));
+                              size);
        /* mxcsr reserved bits must be masked to zero for security reasons */
        tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
        if (err || __copy_from_user(&env, buf, sizeof(env)))
        return 0;
 }
 
+static int restore_i387_xsave(void __user *buf)
+{
+       struct _fpx_sw_bytes fx_sw_user;
+       struct _fpstate_ia32 __user *fx_user =
+                       ((struct _fpstate_ia32 __user *) buf);
+       struct i387_fxsave_struct __user *fx =
+               (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
+       struct xsave_hdr_struct *xsave_hdr =
+                               ¤t->thread.xstate->xsave.xsave_hdr;
+       unsigned int lmask, hmask;
+       int err;
+
+       if (check_for_xstate(fx, buf, &fx_sw_user))
+               goto fx_only;
+
+       lmask = fx_sw_user.xstate_bv;
+       hmask = fx_sw_user.xstate_bv >> 32;
+
+       err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
+
+       xsave_hdr->xstate_bv &=  (pcntxt_lmask | (((u64) pcntxt_hmask) << 32));
+       /*
+        * These bits must be zero.
+        */
+       xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
+
+       /*
+        * Init the state that is not present in the memory layout
+        * and enabled by the OS.
+        */
+       lmask = ~(pcntxt_lmask & ~lmask);
+       hmask = ~(pcntxt_hmask & ~hmask);
+       xsave_hdr->xstate_bv &=  (lmask | (((u64) hmask) << 32));
+
+       return err;
+fx_only:
+       /*
+        * Couldn't find the extended state information in the memory
+        * layout. Restore the FP/SSE and init the other extended state
+        * enabled by the OS.
+        */
+       xsave_hdr->xstate_bv = XSTATE_FPSSE;
+       return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
+}
+
 int restore_i387_xstate_ia32(void __user *buf)
 {
        int err;
        }
 
        if (HAVE_HWFP) {
-               if (cpu_has_fxsr)
-                       err = restore_i387_fxsave(fp);
+               if (cpu_has_xsave)
+                       err = restore_i387_xsave(buf);
+               else if (cpu_has_fxsr)
+                       err = restore_i387_fxsave(fp, sizeof(struct
+                                                          i387_fxsave_struct));
                else
                        err = restore_i387_fsave(fp);
        } else {
 
                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),
 
                        sp = current->sas_ss_sp + current->sas_ss_size;
        }
 
-       return (void __user *)round_down(sp - size, 16);
+       return (void __user *)round_down(sp - size, 64);
 }
 
 static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        }
                
        /* 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(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->sp),
 
 #include <linux/bootmem.h>
 #include <linux/compat.h>
 #include <asm/i387.h>
+#ifdef CONFIG_IA32_EMULATION
+#include <asm/sigcontext32.h>
+#endif
 
 /*
  * Supported feature mask by the CPU and the kernel.
  */
 unsigned int pcntxt_hmask, pcntxt_lmask;
 
+struct _fpx_sw_bytes fx_sw_reserved;
+#ifdef CONFIG_IA32_EMULATION
+struct _fpx_sw_bytes fx_sw_reserved_ia32;
+#endif
+
+/*
+ * Check for the presence of extended state information in the
+ * user fpstate pointer in the sigcontext.
+ */
+int check_for_xstate(struct i387_fxsave_struct __user *buf,
+                    void __user *fpstate,
+                    struct _fpx_sw_bytes *fx_sw_user)
+{
+       int min_xstate_size = sizeof(struct i387_fxsave_struct) +
+                             sizeof(struct xsave_hdr_struct);
+       unsigned int magic2;
+       int err;
+
+       err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
+                              sizeof(struct _fpx_sw_bytes));
+
+       if (err)
+               return err;
+
+       /*
+        * First Magic check failed.
+        */
+       if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
+               return -1;
+
+       /*
+        * Check for error scenarios.
+        */
+       if (fx_sw_user->xstate_size < min_xstate_size ||
+           fx_sw_user->xstate_size > xstate_size ||
+           fx_sw_user->xstate_size > fx_sw_user->extended_size)
+               return -1;
+
+       err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
+                                           fx_sw_user->extended_size -
+                                           FP_XSTATE_MAGIC2_SIZE));
+       /*
+        * Check for the presence of second magic word at the end of memory
+        * layout. This detects the case where the user just copied the legacy
+        * fpstate layout with out copying the extended state information
+        * in the memory layout.
+        */
+       if (err || magic2 != FP_XSTATE_MAGIC2)
+               return -1;
+
+       return 0;
+}
+
 #ifdef CONFIG_X86_64
 /*
  * Signal frame handlers.
        BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
                        sizeof(tsk->thread.xstate->fxsave));
 
-       if ((unsigned long)buf % 16)
+       if ((unsigned long)buf % 64)
                printk("save_i387_xstate: bad fpstate %p\n", buf);
 
        if (!used_math())
                return 0;
        clear_used_math(); /* trigger finit */
        if (task_thread_info(tsk)->status & TS_USEDFPU) {
-               err = save_i387_checking((struct i387_fxsave_struct __user *)
-                                        buf);
+               if (task_thread_info(tsk)->status & TS_XSAVE)
+                       err = xsave_user(buf);
+               else
+                       err = fxsave_user(buf);
+
                if (err)
                        return err;
                task_thread_info(tsk)->status &= ~TS_USEDFPU;
                                   xstate_size))
                        return -1;
        }
+
+       if (task_thread_info(tsk)->status & TS_XSAVE) {
+               struct _fpstate __user *fx = buf;
+
+               err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
+                                    sizeof(struct _fpx_sw_bytes));
+
+               err |= __put_user(FP_XSTATE_MAGIC2,
+                                 (__u32 __user *) (buf + sig_xstate_size
+                                                   - FP_XSTATE_MAGIC2_SIZE));
+       }
+
        return 1;
 }
 
+/*
+ * Restore the extended state if present. Otherwise, restore the FP/SSE
+ * state.
+ */
+int restore_user_xstate(void __user *buf)
+{
+       struct _fpx_sw_bytes fx_sw_user;
+       unsigned int lmask, hmask;
+       int err;
+
+       if (((unsigned long)buf % 64) ||
+            check_for_xstate(buf, buf, &fx_sw_user))
+               goto fx_only;
+
+       lmask = fx_sw_user.xstate_bv;
+       hmask = fx_sw_user.xstate_bv >> 32;
+
+       /*
+        * restore the state passed by the user.
+        */
+       err = xrestore_user(buf, lmask, hmask);
+       if (err)
+               return err;
+
+       /*
+        * init the state skipped by the user.
+        */
+       lmask = pcntxt_lmask & ~lmask;
+       hmask = pcntxt_hmask & ~hmask;
+
+       xrstor_state(init_xstate_buf, lmask, hmask);
+
+       return 0;
+
+fx_only:
+       /*
+        * couldn't find the extended state information in the
+        * memory layout. Restore just the FP/SSE and init all
+        * the other extended state.
+        */
+       xrstor_state(init_xstate_buf, pcntxt_lmask & ~XSTATE_FPSSE,
+                    pcntxt_hmask);
+       return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
+}
+
 /*
  * This restores directly out of user space. Exceptions are handled.
  */
 int restore_i387_xstate(void __user *buf)
 {
        struct task_struct *tsk = current;
-       int err;
+       int err = 0;
 
        if (!buf) {
-               if (used_math()) {
-                       clear_fpu(tsk);
-                       clear_used_math();
-               }
-
+               if (used_math())
+                       goto clear;
                return 0;
        } else
                if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
                clts();
                task_thread_info(current)->status |= TS_USEDFPU;
        }
-       err = fxrstor_checking((__force struct i387_fxsave_struct *)buf);
+       if (task_thread_info(tsk)->status & TS_XSAVE)
+               err = restore_user_xstate(buf);
+       else
+               err = fxrstor_checking((__force struct i387_fxsave_struct *)
+                                      buf);
        if (unlikely(err)) {
                /*
                 * Encountered an error while doing the restore from the
                 * user buffer, clear the fpu state.
                 */
+clear:
                clear_fpu(tsk);
                clear_used_math();
        }
 }
 #endif
 
+/*
+ * Prepare the SW reserved portion of the fxsave memory layout, indicating
+ * the presence of the extended state information in the memory layout
+ * pointed by the fpstate pointer in the sigcontext.
+ * This will be saved when ever the FP and extended state context is
+ * saved on the user stack during the signal handler delivery to the user.
+ */
+void prepare_fx_sw_frame(void)
+{
+       int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
+                            FP_XSTATE_MAGIC2_SIZE;
+
+       sig_xstate_size = sizeof(struct _fpstate) + size_extended;
+
+#ifdef CONFIG_IA32_EMULATION
+       sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
+#endif
+
+       memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
+
+       fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
+       fx_sw_reserved.extended_size = sig_xstate_size;
+       fx_sw_reserved.xstate_bv = pcntxt_lmask |
+                                        (((u64) (pcntxt_hmask)) << 32);
+       fx_sw_reserved.xstate_size = xstate_size;
+#ifdef CONFIG_IA32_EMULATION
+       memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
+              sizeof(struct _fpx_sw_bytes));
+       fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
+#endif
+}
+
 /*
  * Represents init state for the supported extended state.
  */
 
        xstate_size = ebx;
 
+       prepare_fx_sw_frame();
+
        setup_xstate_init();
 
        printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, "
 
 extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
 extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
 
+extern struct _fpx_sw_bytes fx_sw_reserved;
 #ifdef CONFIG_IA32_EMULATION
 extern unsigned int sig_xstate_ia32_size;
+extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
 struct _fpstate_ia32;
 struct _xstate_ia32;
 extern int save_i387_xstate_ia32(void __user *buf);
                          X86_FEATURE_FXSAVE_LEAK);
 }
 
-static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
+static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 {
        int err;
 
 
 #ifndef ASM_X86__UCONTEXT_H
 #define ASM_X86__UCONTEXT_H
 
+#define UC_FP_XSTATE   0x1     /* indicates the presence of extended state
+                                * information in the memory layout pointed
+                                * by the fpstate pointer in the ucontext's
+                                * sigcontext struct (uc_mcontext).
+                                */
+
 struct ucontext {
        unsigned long     uc_flags;
        struct ucontext  *uc_link;
 
 extern void xsave_cntxt_init(void);
 extern void xsave_init(void);
 extern int init_fpu(struct task_struct *child);
+extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
+                           void __user *fpstate,
+                           struct _fpx_sw_bytes *sw);
 
 static inline int xrstor_checking(struct xsave_struct *fx)
 {
        return err;
 }
 
-static inline int xsave_check(struct xsave_struct __user *buf)
+static inline int xsave_user(struct xsave_struct __user *buf)
 {
        int err;
        __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"