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_API_H 12 #define _ASM_X86_FPU_API_H 13 #include <linux/bottom_half.h> 14 15 #include <asm/fpu/types.h> 16 17 /* 18 * Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It 19 * disables preemption and softirq processing, so be careful if you intend to 20 * use it for long periods of time. Kernel-mode FPU cannot be used in all 21 * contexts -- see irq_fpu_usable() for details. 22 */ 23 24 /* Kernel FPU states to initialize in kernel_fpu_begin_mask() */ 25 #define KFPU_387 _BITUL(0) /* 387 state will be initialized */ 26 #define KFPU_MXCSR _BITUL(1) /* MXCSR will be initialized */ 27 28 extern void kernel_fpu_begin_mask(unsigned int kfpu_mask); 29 extern void kernel_fpu_end(void); 30 extern bool irq_fpu_usable(void); 31 extern void fpregs_mark_activate(void); 32 33 /* Code that is unaware of kernel_fpu_begin_mask() can use this */ 34 static inline void kernel_fpu_begin(void) 35 { 36 #ifdef CONFIG_X86_64 37 /* 38 * Any 64-bit code that uses 387 instructions must explicitly request 39 * KFPU_387. 40 */ 41 kernel_fpu_begin_mask(KFPU_MXCSR); 42 #else 43 /* 44 * 32-bit kernel code may use 387 operations as well as SSE2, etc, 45 * as long as it checks that the CPU has the required capability. 46 */ 47 kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR); 48 #endif 49 } 50 51 /* 52 * Use fpregs_lock() while editing CPU's FPU registers or fpu->fpstate, or while 53 * using the FPU in kernel mode. A context switch will (and softirq might) save 54 * CPU's FPU registers to fpu->fpstate.regs and set TIF_NEED_FPU_LOAD leaving 55 * CPU's FPU registers in a random state. 56 * 57 * local_bh_disable() protects against both preemption and soft interrupts 58 * on !RT kernels. 59 * 60 * On RT kernels local_bh_disable() is not sufficient because it only 61 * serializes soft interrupt related sections via a local lock, but stays 62 * preemptible. Disabling preemption is the right choice here as bottom 63 * half processing is always in thread context on RT kernels so it 64 * implicitly prevents bottom half processing as well. 65 */ 66 static inline void fpregs_lock(void) 67 { 68 if (!IS_ENABLED(CONFIG_PREEMPT_RT)) 69 local_bh_disable(); 70 else 71 preempt_disable(); 72 } 73 74 static inline void fpregs_unlock(void) 75 { 76 if (!IS_ENABLED(CONFIG_PREEMPT_RT)) 77 local_bh_enable(); 78 else 79 preempt_enable(); 80 } 81 82 /* 83 * FPU state gets lazily restored before returning to userspace. So when in the 84 * kernel, the valid FPU state may be kept in the buffer. This function will force 85 * restore all the fpu state to the registers early if needed, and lock them from 86 * being automatically saved/restored. Then FPU state can be modified safely in the 87 * registers, before unlocking with fpregs_unlock(). 88 */ 89 void fpregs_lock_and_load(void); 90 91 #ifdef CONFIG_X86_DEBUG_FPU 92 extern void fpregs_assert_state_consistent(void); 93 #else 94 static inline void fpregs_assert_state_consistent(void) { } 95 #endif 96 97 /* 98 * Load the task FPU state before returning to userspace. 99 */ 100 extern void switch_fpu_return(void); 101 102 /* 103 * Query the presence of one or more xfeatures. Works on any legacy CPU as well. 104 * 105 * If 'feature_name' is set then put a human-readable description of 106 * the feature there as well - this can be used to print error (or success) 107 * messages. 108 */ 109 extern int cpu_has_xfeatures(u64 xfeatures_mask, const char **feature_name); 110 111 /* Trap handling */ 112 extern int fpu__exception_code(struct fpu *fpu, int trap_nr); 113 extern void fpu_sync_fpstate(struct fpu *fpu); 114 extern void fpu_reset_from_exception_fixup(void); 115 116 /* Boot, hotplug and resume */ 117 extern void fpu__init_cpu(void); 118 extern void fpu__init_system(void); 119 extern void fpu__init_check_bugs(void); 120 extern void fpu__resume_cpu(void); 121 122 #ifdef CONFIG_MATH_EMULATION 123 extern void fpstate_init_soft(struct swregs_state *soft); 124 #else 125 static inline void fpstate_init_soft(struct swregs_state *soft) {} 126 #endif 127 128 /* State tracking */ 129 DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx); 130 131 /* Process cleanup */ 132 #ifdef CONFIG_X86_64 133 extern void fpstate_free(struct fpu *fpu); 134 #else 135 static inline void fpstate_free(struct fpu *fpu) { } 136 #endif 137 138 /* fpstate-related functions which are exported to KVM */ 139 extern void fpstate_clear_xstate_component(struct fpstate *fps, unsigned int xfeature); 140 141 extern u64 xstate_get_guest_group_perm(void); 142 143 extern void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); 144 145 146 /* KVM specific functions */ 147 extern bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu); 148 extern void fpu_free_guest_fpstate(struct fpu_guest *gfpu); 149 extern int fpu_swap_kvm_fpstate(struct fpu_guest *gfpu, bool enter_guest); 150 extern int fpu_enable_guest_xfd_features(struct fpu_guest *guest_fpu, u64 xfeatures); 151 152 #ifdef CONFIG_X86_64 153 extern void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd); 154 extern void fpu_sync_guest_vmexit_xfd_state(void); 155 #else 156 static inline void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) { } 157 static inline void fpu_sync_guest_vmexit_xfd_state(void) { } 158 #endif 159 160 extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, 161 unsigned int size, u64 xfeatures, u32 pkru); 162 extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru); 163 164 static inline void fpstate_set_confidential(struct fpu_guest *gfpu) 165 { 166 gfpu->fpstate->is_confidential = true; 167 } 168 169 static inline bool fpstate_is_confidential(struct fpu_guest *gfpu) 170 { 171 return gfpu->fpstate->is_confidential; 172 } 173 174 /* prctl */ 175 extern long fpu_xstate_prctl(int option, unsigned long arg2); 176 177 extern void fpu_idle_fpregs(void); 178 179 #endif /* _ASM_X86_FPU_API_H */ 180