Merge branch 'work.regset' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / arch / x86 / kernel / fpu / xstate.c
index 4f8e428..7a2bf88 100644 (file)
@@ -233,8 +233,10 @@ void fpu__init_cpu_xstate(void)
        /*
         * MSR_IA32_XSS sets supervisor states managed by XSAVES.
         */
-       if (boot_cpu_has(X86_FEATURE_XSAVES))
-               wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor());
+       if (boot_cpu_has(X86_FEATURE_XSAVES)) {
+               wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() |
+                                    xfeatures_mask_dynamic());
+       }
 }
 
 static bool xfeature_enabled(enum xfeature xfeature)
@@ -486,7 +488,7 @@ static int xfeature_uncompacted_offset(int xfeature_nr)
        return ebx;
 }
 
-static int xfeature_size(int xfeature_nr)
+int xfeature_size(int xfeature_nr)
 {
        u32 eax, ebx, ecx, edx;
 
@@ -598,7 +600,8 @@ static void check_xstate_against_struct(int nr)
         */
        if ((nr < XFEATURE_YMM) ||
            (nr >= XFEATURE_MAX) ||
-           (nr == XFEATURE_PT_UNIMPLEMENTED_SO_FAR)) {
+           (nr == XFEATURE_PT_UNIMPLEMENTED_SO_FAR) ||
+           ((nr >= XFEATURE_RSRVD_COMP_10) && (nr <= XFEATURE_LBR))) {
                WARN_ONCE(1, "no structure for xstate: %d\n", nr);
                XSTATE_WARN_ON(1);
        }
@@ -847,8 +850,10 @@ void fpu__resume_cpu(void)
         * Restore IA32_XSS. The same CPUID bit enumerates support
         * of XSAVES and MSR_IA32_XSS.
         */
-       if (boot_cpu_has(X86_FEATURE_XSAVES))
-               wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor());
+       if (boot_cpu_has(X86_FEATURE_XSAVES)) {
+               wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor()  |
+                                    xfeatures_mask_dynamic());
+       }
 }
 
 /*
@@ -1246,6 +1251,78 @@ void copy_supervisor_to_kernel(struct xregs_state *xstate)
        }
 }
 
+/**
+ * copy_dynamic_supervisor_to_kernel() - Save dynamic supervisor states to
+ *                                       an xsave area
+ * @xstate: A pointer to an xsave area
+ * @mask: Represent the dynamic supervisor features saved into the xsave area
+ *
+ * Only the dynamic supervisor states sets in the mask are saved into the xsave
+ * area (See the comment in XFEATURE_MASK_DYNAMIC for the details of dynamic
+ * supervisor feature). Besides the dynamic supervisor states, the legacy
+ * region and XSAVE header are also saved into the xsave area. The supervisor
+ * features in the XFEATURE_MASK_SUPERVISOR_SUPPORTED and
+ * XFEATURE_MASK_SUPERVISOR_UNSUPPORTED are not saved.
+ *
+ * The xsave area must be 64-bytes aligned.
+ */
+void copy_dynamic_supervisor_to_kernel(struct xregs_state *xstate, u64 mask)
+{
+       u64 dynamic_mask = xfeatures_mask_dynamic() & mask;
+       u32 lmask, hmask;
+       int err;
+
+       if (WARN_ON_FPU(!boot_cpu_has(X86_FEATURE_XSAVES)))
+               return;
+
+       if (WARN_ON_FPU(!dynamic_mask))
+               return;
+
+       lmask = dynamic_mask;
+       hmask = dynamic_mask >> 32;
+
+       XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
+
+       /* Should never fault when copying to a kernel buffer */
+       WARN_ON_FPU(err);
+}
+
+/**
+ * copy_kernel_to_dynamic_supervisor() - Restore dynamic supervisor states from
+ *                                       an xsave area
+ * @xstate: A pointer to an xsave area
+ * @mask: Represent the dynamic supervisor features restored from the xsave area
+ *
+ * Only the dynamic supervisor states sets in the mask are restored from the
+ * xsave area (See the comment in XFEATURE_MASK_DYNAMIC for the details of
+ * dynamic supervisor feature). Besides the dynamic supervisor states, the
+ * legacy region and XSAVE header are also restored from the xsave area. The
+ * supervisor features in the XFEATURE_MASK_SUPERVISOR_SUPPORTED and
+ * XFEATURE_MASK_SUPERVISOR_UNSUPPORTED are not restored.
+ *
+ * The xsave area must be 64-bytes aligned.
+ */
+void copy_kernel_to_dynamic_supervisor(struct xregs_state *xstate, u64 mask)
+{
+       u64 dynamic_mask = xfeatures_mask_dynamic() & mask;
+       u32 lmask, hmask;
+       int err;
+
+       if (WARN_ON_FPU(!boot_cpu_has(X86_FEATURE_XSAVES)))
+               return;
+
+       if (WARN_ON_FPU(!dynamic_mask))
+               return;
+
+       lmask = dynamic_mask;
+       hmask = dynamic_mask >> 32;
+
+       XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
+
+       /* Should never fault when copying from a kernel buffer */
+       WARN_ON_FPU(err);
+}
+
 #ifdef CONFIG_PROC_PID_ARCH_STATUS
 /*
  * Report the amount of time elapsed in millisecond since last AVX512