x86/fpu: Rename initstate copy functions
[linux-2.6-microblaze.git] / arch / x86 / kernel / fpu / core.c
index 571220a..4a59e0f 100644 (file)
@@ -83,19 +83,23 @@ bool irq_fpu_usable(void)
 EXPORT_SYMBOL(irq_fpu_usable);
 
 /*
- * These must be called with preempt disabled. Returns
- * 'true' if the FPU state is still intact and we can
- * keep registers active.
+ * Save the FPU register state in fpu->state. The register state is
+ * preserved.
  *
- * The legacy FNSAVE instruction cleared all FPU state
- * unconditionally, so registers are essentially destroyed.
- * Modern FPU state can be kept in registers, if there are
- * no pending FP exceptions.
+ * Must be called with fpregs_lock() held.
+ *
+ * The legacy FNSAVE instruction clears all FPU state unconditionally, so
+ * register state has to be reloaded. That might be a pointless exercise
+ * when the FPU is going to be used by another task right after that. But
+ * this only affects 20+ years old 32bit systems and avoids conditionals all
+ * over the place.
+ *
+ * FXSAVE and all XSAVE variants preserve the FPU register state.
  */
-int copy_fpregs_to_fpstate(struct fpu *fpu)
+void save_fpregs_to_fpstate(struct fpu *fpu)
 {
        if (likely(use_xsave())) {
-               copy_xregs_to_kernel(&fpu->state.xsave);
+               os_xsave(&fpu->state.xsave);
 
                /*
                 * AVX512 state is tracked here because its use is
@@ -103,23 +107,22 @@ int copy_fpregs_to_fpstate(struct fpu *fpu)
                 */
                if (fpu->state.xsave.header.xfeatures & XFEATURE_MASK_AVX512)
                        fpu->avx512_timestamp = jiffies;
-               return 1;
+               return;
        }
 
        if (likely(use_fxsr())) {
-               copy_fxregs_to_kernel(fpu);
-               return 1;
+               fxsave(&fpu->state.fxsave);
+               return;
        }
 
        /*
         * Legacy FPU register saving, FNSAVE always clears FPU registers,
-        * so we have to mark them inactive:
+        * so we have to reload them from the memory state.
         */
        asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state.fsave));
-
-       return 0;
+       frstor(&fpu->state.fsave);
 }
-EXPORT_SYMBOL(copy_fpregs_to_fpstate);
+EXPORT_SYMBOL(save_fpregs_to_fpstate);
 
 void kernel_fpu_begin_mask(unsigned int kfpu_mask)
 {
@@ -133,11 +136,7 @@ void kernel_fpu_begin_mask(unsigned int kfpu_mask)
        if (!(current->flags & PF_KTHREAD) &&
            !test_thread_flag(TIF_NEED_FPU_LOAD)) {
                set_thread_flag(TIF_NEED_FPU_LOAD);
-               /*
-                * Ignore return value -- we don't care if reg state
-                * is clobbered.
-                */
-               copy_fpregs_to_fpstate(&current->thread.fpu);
+               save_fpregs_to_fpstate(&current->thread.fpu);
        }
        __cpu_invalidate_fpregs_state();
 
@@ -171,16 +170,28 @@ void fpu__save(struct fpu *fpu)
        fpregs_lock();
        trace_x86_fpu_before_save(fpu);
 
-       if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
-               if (!copy_fpregs_to_fpstate(fpu)) {
-                       copy_kernel_to_fpregs(&fpu->state);
-               }
-       }
+       if (!test_thread_flag(TIF_NEED_FPU_LOAD))
+               save_fpregs_to_fpstate(fpu);
 
        trace_x86_fpu_after_save(fpu);
        fpregs_unlock();
 }
 
+static inline void fpstate_init_xstate(struct xregs_state *xsave)
+{
+       /*
+        * XRSTORS requires these bits set in xcomp_bv, or it will
+        * trigger #GP:
+        */
+       xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask_all;
+}
+
+static inline void fpstate_init_fxstate(struct fxregs_state *fx)
+{
+       fx->cwd = 0x37f;
+       fx->mxcsr = MXCSR_DEFAULT;
+}
+
 /*
  * Legacy x87 fpstate state init:
  */
@@ -229,20 +240,16 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src)
        memset(&dst_fpu->state.xsave, 0, fpu_kernel_xstate_size);
 
        /*
-        * If the FPU registers are not current just memcpy() the state.
-        * Otherwise save current FPU registers directly into the child's FPU
-        * context, without any memory-to-memory copying.
-        *
-        * ( The function 'fails' in the FNSAVE case, which destroys
-        *   register contents so we have to load them back. )
+        * If the FPU registers are not owned by current just memcpy() the
+        * state.  Otherwise save the FPU registers directly into the
+        * child's FPU context, without any memory-to-memory copying.
         */
        fpregs_lock();
        if (test_thread_flag(TIF_NEED_FPU_LOAD))
                memcpy(&dst_fpu->state, &src_fpu->state, fpu_kernel_xstate_size);
 
-       else if (!copy_fpregs_to_fpstate(dst_fpu))
-               copy_kernel_to_fpregs(&dst_fpu->state);
-
+       else
+               save_fpregs_to_fpstate(dst_fpu);
        fpregs_unlock();
 
        set_tsk_thread_flag(dst, TIF_NEED_FPU_LOAD);
@@ -266,50 +273,6 @@ static void fpu__initialize(struct fpu *fpu)
        trace_x86_fpu_init_state(fpu);
 }
 
-/*
- * This function must be called before we read a task's fpstate.
- *
- * There's two cases where this gets called:
- *
- * - for the current task (when coredumping), in which case we have
- *   to save the latest FPU registers into the fpstate,
- *
- * - or it's called for stopped tasks (ptrace), in which case the
- *   registers were already saved by the context-switch code when
- *   the task scheduled out.
- *
- * If the task has used the FPU before then save it.
- */
-void fpu__prepare_read(struct fpu *fpu)
-{
-       if (fpu == &current->thread.fpu)
-               fpu__save(fpu);
-}
-
-/*
- * This function must be called before we write a task's fpstate.
- *
- * Invalidate any cached FPU registers.
- *
- * After this function call, after registers in the fpstate are
- * modified and the child task has woken up, the child task will
- * restore the modified FPU state from the modified context. If we
- * didn't clear its cached status here then the cached in-registers
- * state pending on its former CPU could be restored, corrupting
- * the modifications.
- */
-void fpu__prepare_write(struct fpu *fpu)
-{
-       /*
-        * Only stopped child tasks can be used to modify the FPU
-        * state in the fpstate buffer:
-        */
-       WARN_ON_FPU(fpu == &current->thread.fpu);
-
-       /* Invalidate any cached state: */
-       __fpu_invalidate_fpregs_state(fpu);
-}
-
 /*
  * Drops current FPU state: deactivates the fpregs and
  * the fpstate. NOTE: it still leaves previous contents
@@ -340,14 +303,14 @@ void fpu__drop(struct fpu *fpu)
  * Clear FPU registers by setting them up from the init fpstate.
  * Caller must do fpregs_[un]lock() around it.
  */
-static inline void copy_init_fpstate_to_fpregs(u64 features_mask)
+static inline void restore_fpregs_from_init_fpstate(u64 features_mask)
 {
        if (use_xsave())
-               copy_kernel_to_xregs(&init_fpstate.xsave, features_mask);
-       else if (static_cpu_has(X86_FEATURE_FXSR))
-               copy_kernel_to_fxregs(&init_fpstate.fxsave);
+               os_xrstor(&init_fpstate.xsave, features_mask);
+       else if (use_fxsr())
+               fxrstor(&init_fpstate.fxsave);
        else
-               copy_kernel_to_fregs(&init_fpstate.fsave);
+               frstor(&init_fpstate.fsave);
 
        if (boot_cpu_has(X86_FEATURE_OSPKE))
                copy_init_pkru_to_fpregs();
@@ -374,11 +337,10 @@ static void fpu__clear(struct fpu *fpu, bool user_only)
        if (user_only) {
                if (!fpregs_state_valid(fpu, smp_processor_id()) &&
                    xfeatures_mask_supervisor())
-                       copy_kernel_to_xregs(&fpu->state.xsave,
-                                            xfeatures_mask_supervisor());
-               copy_init_fpstate_to_fpregs(xfeatures_mask_user());
+                       os_xrstor(&fpu->state.xsave, xfeatures_mask_supervisor());
+               restore_fpregs_from_init_fpstate(xfeatures_mask_user());
        } else {
-               copy_init_fpstate_to_fpregs(xfeatures_mask_all);
+               restore_fpregs_from_init_fpstate(xfeatures_mask_all);
        }
 
        fpregs_mark_activate();