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 so be careful if you intend to use it for long periods |
20 | * of time. |
21 | * If you intend to use the FPU in irq/softirq you need to check first with |
22 | * irq_fpu_usable() if it is possible. |
23 | */ |
24 | |
25 | /* Kernel FPU states to initialize in kernel_fpu_begin_mask() */ |
26 | #define KFPU_387 _BITUL(0) /* 387 state will be initialized */ |
27 | #define KFPU_MXCSR _BITUL(1) /* MXCSR will be initialized */ |
28 | |
29 | extern void kernel_fpu_begin_mask(unsigned int kfpu_mask); |
30 | extern void kernel_fpu_end(void); |
31 | extern bool irq_fpu_usable(void); |
32 | extern void fpregs_mark_activate(void); |
33 | |
34 | /* Code that is unaware of kernel_fpu_begin_mask() can use this */ |
35 | static inline void kernel_fpu_begin(void) |
36 | { |
37 | #ifdef CONFIG_X86_64 |
38 | /* |
39 | * Any 64-bit code that uses 387 instructions must explicitly request |
40 | * KFPU_387. |
41 | */ |
42 | kernel_fpu_begin_mask(KFPU_MXCSR); |
43 | #else |
44 | /* |
45 | * 32-bit kernel code may use 387 operations as well as SSE2, etc, |
46 | * as long as it checks that the CPU has the required capability. |
47 | */ |
48 | kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR); |
49 | #endif |
50 | } |
51 | |
52 | /* |
53 | * Use fpregs_lock() while editing CPU's FPU registers or fpu->fpstate. |
54 | * A context switch will (and softirq might) save CPU's FPU registers to |
55 | * fpu->fpstate.regs and set TIF_NEED_FPU_LOAD leaving CPU's FPU registers in |
56 | * a random state. |
57 | * |
58 | * local_bh_disable() protects against both preemption and soft interrupts |
59 | * on !RT kernels. |
60 | * |
61 | * On RT kernels local_bh_disable() is not sufficient because it only |
62 | * serializes soft interrupt related sections via a local lock, but stays |
63 | * preemptible. Disabling preemption is the right choice here as bottom |
64 | * half processing is always in thread context on RT kernels so it |
65 | * implicitly prevents bottom half processing as well. |
66 | * |
67 | * Disabling preemption also serializes against kernel_fpu_begin(). |
68 | */ |
69 | static inline void fpregs_lock(void) |
70 | { |
71 | if (!IS_ENABLED(CONFIG_PREEMPT_RT)) |
72 | local_bh_disable(); |
73 | else |
74 | preempt_disable(); |
75 | } |
76 | |
77 | static inline void fpregs_unlock(void) |
78 | { |
79 | if (!IS_ENABLED(CONFIG_PREEMPT_RT)) |
80 | local_bh_enable(); |
81 | else |
82 | preempt_enable(); |
83 | } |
84 | |
85 | /* |
86 | * FPU state gets lazily restored before returning to userspace. So when in the |
87 | * kernel, the valid FPU state may be kept in the buffer. This function will force |
88 | * restore all the fpu state to the registers early if needed, and lock them from |
89 | * being automatically saved/restored. Then FPU state can be modified safely in the |
90 | * registers, before unlocking with fpregs_unlock(). |
91 | */ |
92 | void fpregs_lock_and_load(void); |
93 | |
94 | #ifdef CONFIG_X86_DEBUG_FPU |
95 | extern void fpregs_assert_state_consistent(void); |
96 | #else |
97 | static inline void fpregs_assert_state_consistent(void) { } |
98 | #endif |
99 | |
100 | /* |
101 | * Load the task FPU state before returning to userspace. |
102 | */ |
103 | extern void switch_fpu_return(void); |
104 | |
105 | /* |
106 | * Query the presence of one or more xfeatures. Works on any legacy CPU as well. |
107 | * |
108 | * If 'feature_name' is set then put a human-readable description of |
109 | * the feature there as well - this can be used to print error (or success) |
110 | * messages. |
111 | */ |
112 | extern int cpu_has_xfeatures(u64 xfeatures_mask, const char **feature_name); |
113 | |
114 | /* Trap handling */ |
115 | extern int fpu__exception_code(struct fpu *fpu, int trap_nr); |
116 | extern void fpu_sync_fpstate(struct fpu *fpu); |
117 | extern void fpu_reset_from_exception_fixup(void); |
118 | |
119 | /* Boot, hotplug and resume */ |
120 | extern void fpu__init_cpu(void); |
121 | extern void fpu__init_system(void); |
122 | extern void fpu__init_check_bugs(void); |
123 | extern void fpu__resume_cpu(void); |
124 | |
125 | #ifdef CONFIG_MATH_EMULATION |
126 | extern void fpstate_init_soft(struct swregs_state *soft); |
127 | #else |
128 | static inline void fpstate_init_soft(struct swregs_state *soft) {} |
129 | #endif |
130 | |
131 | /* State tracking */ |
132 | DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx); |
133 | |
134 | /* Process cleanup */ |
135 | #ifdef CONFIG_X86_64 |
136 | extern void fpstate_free(struct fpu *fpu); |
137 | #else |
138 | static inline void fpstate_free(struct fpu *fpu) { } |
139 | #endif |
140 | |
141 | /* fpstate-related functions which are exported to KVM */ |
142 | extern void fpstate_clear_xstate_component(struct fpstate *fps, unsigned int xfeature); |
143 | |
144 | extern u64 xstate_get_guest_group_perm(void); |
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 | |