asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
 }
 
+static inline void fxsave(struct fxregs_state *fx)
+{
+       if (IS_ENABLED(CONFIG_X86_32))
+               asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
+       else
+               asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
+}
+
 /* These macros all use (%edi)/(%rdi) as the single memory argument. */
 #define XSAVE          ".byte " REX_PREFIX "0x0f,0xae,0x27"
 #define XSAVEOPT       ".byte " REX_PREFIX "0x0f,0xae,0x37"
                     : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
                     : "memory")
 
-/*
- * This function is called only during boot time when x86 caps are not set
- * up and alternative can not be used yet.
- */
-static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
-{
-       u64 mask = xfeatures_mask_all;
-       u32 lmask = mask;
-       u32 hmask = mask >> 32;
-       int err;
-
-       WARN_ON(system_state != SYSTEM_BOOTING);
-
-       if (boot_cpu_has(X86_FEATURE_XSAVES))
-               XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
-       else
-               XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
-
-       /* We should never fault when copying to a kernel buffer: */
-       WARN_ON_FPU(err);
-}
-
 /*
  * This function is called only during boot time when x86 caps are not set
  * up and alternative can not be used yet.
 
        }
 }
 
+/*
+ * All supported features have either init state all zeros or are
+ * handled in setup_init_fpu() individually. This is an explicit
+ * feature list and does not use XFEATURE_MASK*SUPPORTED to catch
+ * newly added supported features at build time and make people
+ * actually look at the init state for the new feature.
+ */
+#define XFEATURES_INIT_FPSTATE_HANDLED         \
+       (XFEATURE_MASK_FP |                     \
+        XFEATURE_MASK_SSE |                    \
+        XFEATURE_MASK_YMM |                    \
+        XFEATURE_MASK_OPMASK |                 \
+        XFEATURE_MASK_ZMM_Hi256 |              \
+        XFEATURE_MASK_Hi16_ZMM  |              \
+        XFEATURE_MASK_PKRU |                   \
+        XFEATURE_MASK_BNDREGS |                \
+        XFEATURE_MASK_BNDCSR |                 \
+        XFEATURE_MASK_PASID)
+
 /*
  * setup the xstate image representing the init state
  */
 {
        static int on_boot_cpu __initdata = 1;
 
+       BUILD_BUG_ON((XFEATURE_MASK_USER_SUPPORTED |
+                     XFEATURE_MASK_SUPERVISOR_SUPPORTED) !=
+                    XFEATURES_INIT_FPSTATE_HANDLED);
+
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
 
        copy_kernel_to_xregs_booting(&init_fpstate.xsave);
 
        /*
-        * Dump the init state again. This is to identify the init state
-        * of any feature which is not represented by all zero's.
+        * All components are now in init state. Read the state back so
+        * that init_fpstate contains all non-zero init state. This only
+        * works with XSAVE, but not with XSAVEOPT and XSAVES because
+        * those use the init optimization which skips writing data for
+        * components in init state.
+        *
+        * XSAVE could be used, but that would require to reshuffle the
+        * data when XSAVES is available because XSAVES uses xstate
+        * compaction. But doing so is a pointless exercise because most
+        * components have an all zeros init state except for the legacy
+        * ones (FP and SSE). Those can be saved with FXSAVE into the
+        * legacy area. Adding new features requires to ensure that init
+        * state is all zeroes or if not to add the necessary handling
+        * here.
         */
-       copy_xregs_to_kernel_booting(&init_fpstate.xsave);
+       fxsave(&init_fpstate.fxsave);
 }
 
 static int xfeature_uncompacted_offset(int xfeature_nr)