LCOV - code coverage report
Current view: top level - arch/x86/include/asm/fpu - internal.h (source / functions) Hit Total Coverage
Test: landlock.info Lines: 100 141 70.9 %
Date: 2021-04-22 12:43:58 Functions: 10 15 66.7 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0 */
       2             : /*
       3             :  * Copyright (C) 1994 Linus Torvalds
       4             :  *
       5             :  * Pentium III FXSR, SSE support
       6             :  * General FPU state handling cleanups
       7             :  *      Gareth Hughes <gareth@valinux.com>, May 2000
       8             :  * x86-64 work by Andi Kleen 2002
       9             :  */
      10             : 
      11             : #ifndef _ASM_X86_FPU_INTERNAL_H
      12             : #define _ASM_X86_FPU_INTERNAL_H
      13             : 
      14             : #include <linux/compat.h>
      15             : #include <linux/sched.h>
      16             : #include <linux/slab.h>
      17             : #include <linux/mm.h>
      18             : 
      19             : #include <asm/user.h>
      20             : #include <asm/fpu/api.h>
      21             : #include <asm/fpu/xstate.h>
      22             : #include <asm/fpu/xcr.h>
      23             : #include <asm/cpufeature.h>
      24             : #include <asm/trace/fpu.h>
      25             : 
      26             : /*
      27             :  * High level FPU state handling functions:
      28             :  */
      29             : extern void fpu__prepare_read(struct fpu *fpu);
      30             : extern void fpu__prepare_write(struct fpu *fpu);
      31             : extern void fpu__save(struct fpu *fpu);
      32             : extern int  fpu__restore_sig(void __user *buf, int ia32_frame);
      33             : extern void fpu__drop(struct fpu *fpu);
      34             : extern int  fpu__copy(struct task_struct *dst, struct task_struct *src);
      35             : extern void fpu__clear_user_states(struct fpu *fpu);
      36             : extern void fpu__clear_all(struct fpu *fpu);
      37             : extern int  fpu__exception_code(struct fpu *fpu, int trap_nr);
      38             : 
      39             : /*
      40             :  * Boot time FPU initialization functions:
      41             :  */
      42             : extern void fpu__init_cpu(void);
      43             : extern void fpu__init_system_xstate(void);
      44             : extern void fpu__init_cpu_xstate(void);
      45             : extern void fpu__init_system(struct cpuinfo_x86 *c);
      46             : extern void fpu__init_check_bugs(void);
      47             : extern void fpu__resume_cpu(void);
      48             : extern u64 fpu__get_supported_xfeatures_mask(void);
      49             : 
      50             : /*
      51             :  * Debugging facility:
      52             :  */
      53             : #ifdef CONFIG_X86_DEBUG_FPU
      54             : # define WARN_ON_FPU(x) WARN_ON_ONCE(x)
      55             : #else
      56             : # define WARN_ON_FPU(x) ({ (void)(x); 0; })
      57             : #endif
      58             : 
      59             : /*
      60             :  * FPU related CPU feature flag helper routines:
      61             :  */
      62           0 : static __always_inline __pure bool use_xsaveopt(void)
      63             : {
      64           0 :         return static_cpu_has(X86_FEATURE_XSAVEOPT);
      65             : }
      66             : 
      67       36180 : static __always_inline __pure bool use_xsave(void)
      68             : {
      69       54637 :         return static_cpu_has(X86_FEATURE_XSAVE);
      70             : }
      71             : 
      72        1306 : static __always_inline __pure bool use_fxsr(void)
      73             : {
      74        1306 :         return static_cpu_has(X86_FEATURE_FXSR);
      75             : }
      76             : 
      77             : /*
      78             :  * fpstate handling functions:
      79             :  */
      80             : 
      81             : extern union fpregs_state init_fpstate;
      82             : 
      83             : extern void fpstate_init(union fpregs_state *state);
      84             : #ifdef CONFIG_MATH_EMULATION
      85             : extern void fpstate_init_soft(struct swregs_state *soft);
      86             : #else
      87             : static inline void fpstate_init_soft(struct swregs_state *soft) {}
      88             : #endif
      89             : 
      90           0 : static inline void fpstate_init_xstate(struct xregs_state *xsave)
      91             : {
      92             :         /*
      93             :          * XRSTORS requires these bits set in xcomp_bv, or it will
      94             :          * trigger #GP:
      95             :          */
      96           0 :         xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask_all;
      97           0 : }
      98             : 
      99           1 : static inline void fpstate_init_fxstate(struct fxregs_state *fx)
     100             : {
     101           1 :         fx->cwd = 0x37f;
     102           1 :         fx->mxcsr = MXCSR_DEFAULT;
     103             : }
     104             : extern void fpstate_sanitize_xstate(struct fpu *fpu);
     105             : 
     106             : #define user_insn(insn, output, input...)                               \
     107             : ({                                                                      \
     108             :         int err;                                                        \
     109             :                                                                         \
     110             :         might_fault();                                                  \
     111             :                                                                         \
     112             :         asm volatile(ASM_STAC "\n"                                    \
     113             :                      "1:" #insn "\n\t"                                      \
     114             :                      "2: " ASM_CLAC "\n"                            \
     115             :                      ".section .fixup,\"ax\"\n"                             \
     116             :                      "3:  movl $-1,%[err]\n"                          \
     117             :                      "    jmp  2b\n"                                  \
     118             :                      ".previous\n"                                    \
     119             :                      _ASM_EXTABLE(1b, 3b)                               \
     120             :                      : [err] "=r" (err), output                               \
     121             :                      : "0"(0), input);                                        \
     122             :         err;                                                            \
     123             : })
     124             : 
     125             : #define kernel_insn_err(insn, output, input...)                         \
     126             : ({                                                                      \
     127             :         int err;                                                        \
     128             :         asm volatile("1:" #insn "\n\t"                                      \
     129             :                      "2:\n"                                           \
     130             :                      ".section .fixup,\"ax\"\n"                             \
     131             :                      "3:  movl $-1,%[err]\n"                          \
     132             :                      "    jmp  2b\n"                                  \
     133             :                      ".previous\n"                                    \
     134             :                      _ASM_EXTABLE(1b, 3b)                               \
     135             :                      : [err] "=r" (err), output                               \
     136             :                      : "0"(0), input);                                        \
     137             :         err;                                                            \
     138             : })
     139             : 
     140             : #define kernel_insn(insn, output, input...)                             \
     141             :         asm volatile("1:" #insn "\n\t"                                      \
     142             :                      "2:\n"                                           \
     143             :                      _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore)  \
     144             :                      : output : input)
     145             : 
     146             : static inline int copy_fregs_to_user(struct fregs_state __user *fx)
     147             : {
     148             :         return user_insn(fnsave %[fx]; fwait,  [fx] "=m" (*fx), "m" (*fx));
     149             : }
     150             : 
     151           0 : static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)
     152             : {
     153           0 :         if (IS_ENABLED(CONFIG_X86_32))
     154             :                 return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
     155             :         else
     156           0 :                 return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
     157             : 
     158             : }
     159             : 
     160           0 : static inline void copy_kernel_to_fxregs(struct fxregs_state *fx)
     161             : {
     162           0 :         if (IS_ENABLED(CONFIG_X86_32))
     163             :                 kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
     164             :         else
     165           0 :                 kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
     166           0 : }
     167             : 
     168           0 : static inline int copy_kernel_to_fxregs_err(struct fxregs_state *fx)
     169             : {
     170           0 :         if (IS_ENABLED(CONFIG_X86_32))
     171             :                 return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
     172             :         else
     173           0 :                 return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
     174             : }
     175             : 
     176           0 : static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
     177             : {
     178           0 :         if (IS_ENABLED(CONFIG_X86_32))
     179             :                 return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
     180             :         else
     181           0 :                 return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
     182             : }
     183             : 
     184             : static inline void copy_kernel_to_fregs(struct fregs_state *fx)
     185             : {
     186             :         kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
     187             : }
     188             : 
     189             : static inline int copy_kernel_to_fregs_err(struct fregs_state *fx)
     190             : {
     191             :         return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
     192             : }
     193             : 
     194             : static inline int copy_user_to_fregs(struct fregs_state __user *fx)
     195             : {
     196             :         return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
     197             : }
     198             : 
     199           0 : static inline void copy_fxregs_to_kernel(struct fpu *fpu)
     200             : {
     201           0 :         if (IS_ENABLED(CONFIG_X86_32))
     202             :                 asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave));
     203             :         else
     204           0 :                 asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
     205           0 : }
     206             : 
     207             : /* These macros all use (%edi)/(%rdi) as the single memory argument. */
     208             : #define XSAVE           ".byte " REX_PREFIX "0x0f,0xae,0x27"
     209             : #define XSAVEOPT        ".byte " REX_PREFIX "0x0f,0xae,0x37"
     210             : #define XSAVES          ".byte " REX_PREFIX "0x0f,0xc7,0x2f"
     211             : #define XRSTOR          ".byte " REX_PREFIX "0x0f,0xae,0x2f"
     212             : #define XRSTORS         ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
     213             : 
     214             : #define XSTATE_OP(op, st, lmask, hmask, err)                            \
     215             :         asm volatile("1:" op "\n\t"                                 \
     216             :                      "xor %[err], %[err]\n"                           \
     217             :                      "2:\n\t"                                         \
     218             :                      ".pushsection .fixup,\"ax\"\n\t"                       \
     219             :                      "3: movl $-2,%[err]\n\t"                         \
     220             :                      "jmp 2b\n\t"                                     \
     221             :                      ".popsection\n\t"                                        \
     222             :                      _ASM_EXTABLE(1b, 3b)                               \
     223             :                      : [err] "=r" (err)                                       \
     224             :                      : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
     225             :                      : "memory")
     226             : 
     227             : /*
     228             :  * If XSAVES is enabled, it replaces XSAVEOPT because it supports a compact
     229             :  * format and supervisor states in addition to modified optimization in
     230             :  * XSAVEOPT.
     231             :  *
     232             :  * Otherwise, if XSAVEOPT is enabled, XSAVEOPT replaces XSAVE because XSAVEOPT
     233             :  * supports modified optimization which is not supported by XSAVE.
     234             :  *
     235             :  * We use XSAVE as a fallback.
     236             :  *
     237             :  * The 661 label is defined in the ALTERNATIVE* macros as the address of the
     238             :  * original instruction which gets replaced. We need to use it here as the
     239             :  * address of the instruction where we might get an exception at.
     240             :  */
     241             : #define XSTATE_XSAVE(st, lmask, hmask, err)                             \
     242             :         asm volatile(ALTERNATIVE_2(XSAVE,                               \
     243             :                                    XSAVEOPT, X86_FEATURE_XSAVEOPT,      \
     244             :                                    XSAVES,   X86_FEATURE_XSAVES)        \
     245             :                      "\n"                                             \
     246             :                      "xor %[err], %[err]\n"                           \
     247             :                      "3:\n"                                           \
     248             :                      ".pushsection .fixup,\"ax\"\n"                 \
     249             :                      "4: movl $-2, %[err]\n"                          \
     250             :                      "jmp 3b\n"                                               \
     251             :                      ".popsection\n"                                  \
     252             :                      _ASM_EXTABLE(661b, 4b)                             \
     253             :                      : [err] "=r" (err)                                       \
     254             :                      : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
     255             :                      : "memory")
     256             : 
     257             : /*
     258             :  * Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
     259             :  * XSAVE area format.
     260             :  */
     261             : #define XSTATE_XRESTORE(st, lmask, hmask)                               \
     262             :         asm volatile(ALTERNATIVE(XRSTOR,                                \
     263             :                                  XRSTORS, X86_FEATURE_XSAVES)           \
     264             :                      "\n"                                             \
     265             :                      "3:\n"                                           \
     266             :                      _ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\
     267             :                      :                                                  \
     268             :                      : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)    \
     269             :                      : "memory")
     270             : 
     271             : /*
     272             :  * This function is called only during boot time when x86 caps are not set
     273             :  * up and alternative can not be used yet.
     274             :  */
     275           1 : static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
     276             : {
     277           1 :         u64 mask = xfeatures_mask_all;
     278           1 :         u32 lmask = mask;
     279           1 :         u32 hmask = mask >> 32;
     280           1 :         int err;
     281             : 
     282           1 :         WARN_ON(system_state != SYSTEM_BOOTING);
     283             : 
     284           1 :         if (boot_cpu_has(X86_FEATURE_XSAVES))
     285           0 :                 XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
     286             :         else
     287           1 :                 XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
     288             : 
     289             :         /* We should never fault when copying to a kernel buffer: */
     290           1 :         WARN_ON_FPU(err);
     291           1 : }
     292             : 
     293             : /*
     294             :  * This function is called only during boot time when x86 caps are not set
     295             :  * up and alternative can not be used yet.
     296             :  */
     297           1 : static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
     298             : {
     299           1 :         u64 mask = -1;
     300           1 :         u32 lmask = mask;
     301           1 :         u32 hmask = mask >> 32;
     302           1 :         int err;
     303             : 
     304           1 :         WARN_ON(system_state != SYSTEM_BOOTING);
     305             : 
     306           1 :         if (boot_cpu_has(X86_FEATURE_XSAVES))
     307           0 :                 XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
     308             :         else
     309           1 :                 XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
     310             : 
     311             :         /*
     312             :          * We should never fault when copying from a kernel buffer, and the FPU
     313             :          * state we set at boot time should be valid.
     314             :          */
     315           1 :         WARN_ON_FPU(err);
     316           1 : }
     317             : 
     318             : /*
     319             :  * Save processor xstate to xsave area.
     320             :  */
     321       17150 : static inline void copy_xregs_to_kernel(struct xregs_state *xstate)
     322             : {
     323       17150 :         u64 mask = xfeatures_mask_all;
     324       17150 :         u32 lmask = mask;
     325       17150 :         u32 hmask = mask >> 32;
     326       17150 :         int err;
     327             : 
     328       17150 :         WARN_ON_FPU(!alternatives_patched);
     329             : 
     330       17150 :         XSTATE_XSAVE(xstate, lmask, hmask, err);
     331             : 
     332             :         /* We should never fault when copying to a kernel buffer: */
     333       17150 :         WARN_ON_FPU(err);
     334       17150 : }
     335             : 
     336             : /*
     337             :  * Restore processor xstate from xsave area.
     338             :  */
     339       10857 : static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask)
     340             : {
     341       10857 :         u32 lmask = mask;
     342       10857 :         u32 hmask = mask >> 32;
     343             : 
     344       10857 :         XSTATE_XRESTORE(xstate, lmask, hmask);
     345       10859 : }
     346             : 
     347             : /*
     348             :  * Save xstate to user space xsave area.
     349             :  *
     350             :  * We don't use modified optimization because xrstor/xrstors might track
     351             :  * a different application.
     352             :  *
     353             :  * We don't use compacted format xsave area for
     354             :  * backward compatibility for old applications which don't understand
     355             :  * compacted format of xsave area.
     356             :  */
     357        1644 : static inline int copy_xregs_to_user(struct xregs_state __user *buf)
     358             : {
     359        1644 :         u64 mask = xfeatures_mask_user();
     360        1644 :         u32 lmask = mask;
     361        1644 :         u32 hmask = mask >> 32;
     362        1644 :         int err;
     363             : 
     364             :         /*
     365             :          * Clear the xsave header first, so that reserved fields are
     366             :          * initialized to zero.
     367             :          */
     368        1644 :         err = __clear_user(&buf->header, sizeof(buf->header));
     369        1644 :         if (unlikely(err))
     370             :                 return -EFAULT;
     371             : 
     372        1496 :         stac();
     373        1496 :         XSTATE_OP(XSAVE, buf, lmask, hmask, err);
     374        1496 :         clac();
     375             : 
     376        1496 :         return err;
     377             : }
     378             : 
     379             : /*
     380             :  * Restore xstate from user space xsave area.
     381             :  */
     382        1306 : static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask)
     383             : {
     384        1306 :         struct xregs_state *xstate = ((__force struct xregs_state *)buf);
     385        1306 :         u32 lmask = mask;
     386        1306 :         u32 hmask = mask >> 32;
     387        1306 :         int err;
     388             : 
     389        1306 :         stac();
     390        1306 :         XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
     391        1306 :         clac();
     392             : 
     393        1306 :         return err;
     394             : }
     395             : 
     396             : /*
     397             :  * Restore xstate from kernel space xsave area, return an error code instead of
     398             :  * an exception.
     399             :  */
     400           0 : static inline int copy_kernel_to_xregs_err(struct xregs_state *xstate, u64 mask)
     401             : {
     402           0 :         u32 lmask = mask;
     403           0 :         u32 hmask = mask >> 32;
     404           0 :         int err;
     405             : 
     406           0 :         if (static_cpu_has(X86_FEATURE_XSAVES))
     407           0 :                 XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
     408             :         else
     409           0 :                 XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
     410             : 
     411           0 :         return err;
     412             : }
     413             : 
     414             : extern int copy_fpregs_to_fpstate(struct fpu *fpu);
     415             : 
     416        7296 : static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate, u64 mask)
     417             : {
     418        7296 :         if (use_xsave()) {
     419        7296 :                 copy_kernel_to_xregs(&fpstate->xsave, mask);
     420             :         } else {
     421           0 :                 if (use_fxsr())
     422           0 :                         copy_kernel_to_fxregs(&fpstate->fxsave);
     423             :                 else
     424             :                         copy_kernel_to_fregs(&fpstate->fsave);
     425             :         }
     426        7298 : }
     427             : 
     428        7296 : static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate)
     429             : {
     430             :         /*
     431             :          * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is
     432             :          * pending. Clear the x87 state here by setting it to fixed values.
     433             :          * "m" is a random variable that should be in L1.
     434             :          */
     435       14592 :         if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK))) {
     436           0 :                 asm volatile(
     437             :                         "fnclex\n\t"
     438             :                         "emms\n\t"
     439             :                         "fildl %P[addr]"      /* set F?P to defined value */
     440             :                         : : [addr] "m" (fpstate));
     441             :         }
     442             : 
     443        7296 :         __copy_kernel_to_fpregs(fpstate, -1);
     444        7298 : }
     445             : 
     446             : extern int copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size);
     447             : 
     448             : /*
     449             :  * FPU context switch related helper methods:
     450             :  */
     451             : 
     452             : DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);
     453             : 
     454             : /*
     455             :  * The in-register FPU state for an FPU context on a CPU is assumed to be
     456             :  * valid if the fpu->last_cpu matches the CPU, and the fpu_fpregs_owner_ctx
     457             :  * matches the FPU.
     458             :  *
     459             :  * If the FPU register state is valid, the kernel can skip restoring the
     460             :  * FPU state from memory.
     461             :  *
     462             :  * Any code that clobbers the FPU registers or updates the in-memory
     463             :  * FPU state for a task MUST let the rest of the kernel know that the
     464             :  * FPU registers are no longer valid for this task.
     465             :  *
     466             :  * Either one of these invalidation functions is enough. Invalidate
     467             :  * a resource you control: CPU if using the CPU for something else
     468             :  * (with preemption disabled), FPU for the current task, or a task that
     469             :  * is prevented from running by the current task.
     470             :  */
     471           0 : static inline void __cpu_invalidate_fpregs_state(void)
     472             : {
     473           0 :         __this_cpu_write(fpu_fpregs_owner_ctx, NULL);
     474             : }
     475             : 
     476           0 : static inline void __fpu_invalidate_fpregs_state(struct fpu *fpu)
     477             : {
     478           0 :         fpu->last_cpu = -1;
     479           0 : }
     480             : 
     481       15291 : static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
     482             : {
     483       15292 :         return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
     484             : }
     485             : 
     486             : /*
     487             :  * These generally need preemption protection to work,
     488             :  * do try to avoid using these on their own:
     489             :  */
     490        2545 : static inline void fpregs_deactivate(struct fpu *fpu)
     491             : {
     492        2545 :         this_cpu_write(fpu_fpregs_owner_ctx, NULL);
     493        2545 :         trace_x86_fpu_regs_deactivated(fpu);
     494        2545 : }
     495             : 
     496       12163 : static inline void fpregs_activate(struct fpu *fpu)
     497             : {
     498        5699 :         this_cpu_write(fpu_fpregs_owner_ctx, fpu);
     499       12163 :         trace_x86_fpu_regs_activated(fpu);
     500             : }
     501             : 
     502             : /*
     503             :  * Internal helper, do not use directly. Use switch_fpu_return() instead.
     504             :  */
     505       13987 : static inline void __fpregs_load_activate(void)
     506             : {
     507       13987 :         struct fpu *fpu = &current->thread.fpu;
     508       13987 :         int cpu = smp_processor_id();
     509             : 
     510       13987 :         if (WARN_ON_ONCE(current->flags & PF_KTHREAD))
     511             :                 return;
     512             : 
     513       13987 :         if (!fpregs_state_valid(fpu, cpu)) {
     514        7295 :                 copy_kernel_to_fpregs(&fpu->state);
     515        7298 :                 fpregs_activate(fpu);
     516        7297 :                 fpu->last_cpu = cpu;
     517             :         }
     518       13990 :         clear_thread_flag(TIF_NEED_FPU_LOAD);
     519             : }
     520             : 
     521             : /*
     522             :  * FPU state switching for scheduling.
     523             :  *
     524             :  * This is a two-stage process:
     525             :  *
     526             :  *  - switch_fpu_prepare() saves the old state.
     527             :  *    This is done within the context of the old process.
     528             :  *
     529             :  *  - switch_fpu_finish() sets TIF_NEED_FPU_LOAD; the floating point state
     530             :  *    will get loaded on return to userspace, or when the kernel needs it.
     531             :  *
     532             :  * If TIF_NEED_FPU_LOAD is cleared then the CPU's FPU registers
     533             :  * are saved in the current thread's FPU register state.
     534             :  *
     535             :  * If TIF_NEED_FPU_LOAD is set then CPU's FPU registers may not
     536             :  * hold current()'s FPU registers. It is required to load the
     537             :  * registers before returning to userland or using the content
     538             :  * otherwise.
     539             :  *
     540             :  * The FPU context is only stored/restored for a user task and
     541             :  * PF_KTHREAD is used to distinguish between kernel and user threads.
     542             :  */
     543       14352 : static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu)
     544             : {
     545       14352 :         if (static_cpu_has(X86_FEATURE_FPU) && !(current->flags & PF_KTHREAD)) {
     546       14351 :                 if (!copy_fpregs_to_fpstate(old_fpu))
     547           0 :                         old_fpu->last_cpu = -1;
     548             :                 else
     549       14352 :                         old_fpu->last_cpu = cpu;
     550             : 
     551             :                 /* But leave fpu_fpregs_owner_ctx! */
     552       14352 :                 trace_x86_fpu_regs_deactivated(old_fpu);
     553             :         }
     554       14350 : }
     555             : 
     556             : /*
     557             :  * Misc helper functions:
     558             :  */
     559             : 
     560             : /*
     561             :  * Load PKRU from the FPU context if available. Delay loading of the
     562             :  * complete FPU state until the return to userland.
     563             :  */
     564       53467 : static inline void switch_fpu_finish(struct fpu *new_fpu)
     565             : {
     566       53467 :         u32 pkru_val = init_pkru_value;
     567       53467 :         struct pkru_state *pk;
     568             : 
     569       53467 :         if (!static_cpu_has(X86_FEATURE_FPU))
     570             :                 return;
     571             : 
     572       53467 :         set_thread_flag(TIF_NEED_FPU_LOAD);
     573             : 
     574       53473 :         if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
     575       53473 :                 return;
     576             : 
     577             :         /*
     578             :          * PKRU state is switched eagerly because it needs to be valid before we
     579             :          * return to userland e.g. for a copy_to_user() operation.
     580             :          */
     581             :         if (current->mm) {
     582             :                 pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU);
     583             :                 if (pk)
     584             :                         pkru_val = pk->pkru;
     585             :         }
     586             :         __write_pkru(pkru_val);
     587             : 
     588             :         /*
     589             :          * Expensive PASID MSR write will be avoided in update_pasid() because
     590             :          * TIF_NEED_FPU_LOAD was set. And the PASID state won't be updated
     591             :          * unless it's different from mm->pasid to reduce overhead.
     592             :          */
     593             :         update_pasid();
     594             : }
     595             : 
     596             : #endif /* _ASM_X86_FPU_INTERNAL_H */

Generated by: LCOV version 1.14