134002571SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0 */
234002571SThomas Gleixner #ifndef __X86_KERNEL_FPU_LEGACY_H
334002571SThomas Gleixner #define __X86_KERNEL_FPU_LEGACY_H
434002571SThomas Gleixner
534002571SThomas Gleixner #include <asm/fpu/types.h>
634002571SThomas Gleixner
7d9d005f3SThomas Gleixner extern unsigned int mxcsr_feature_mask;
8d9d005f3SThomas Gleixner
ldmxcsr(u32 mxcsr)9d9d005f3SThomas Gleixner static inline void ldmxcsr(u32 mxcsr)
10d9d005f3SThomas Gleixner {
11d9d005f3SThomas Gleixner asm volatile("ldmxcsr %0" :: "m" (mxcsr));
12d9d005f3SThomas Gleixner }
13d9d005f3SThomas Gleixner
1434002571SThomas Gleixner /*
1534002571SThomas Gleixner * Returns 0 on success or the trap number when the operation raises an
1634002571SThomas Gleixner * exception.
1734002571SThomas Gleixner */
1834002571SThomas Gleixner #define user_insn(insn, output, input...) \
1934002571SThomas Gleixner ({ \
2034002571SThomas Gleixner int err; \
2134002571SThomas Gleixner \
2234002571SThomas Gleixner might_fault(); \
2334002571SThomas Gleixner \
2434002571SThomas Gleixner asm volatile(ASM_STAC "\n" \
2534002571SThomas Gleixner "1: " #insn "\n" \
2634002571SThomas Gleixner "2: " ASM_CLAC "\n" \
2734002571SThomas Gleixner _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_MCE_SAFE) \
2834002571SThomas Gleixner : [err] "=a" (err), output \
2934002571SThomas Gleixner : "0"(0), input); \
3034002571SThomas Gleixner err; \
3134002571SThomas Gleixner })
3234002571SThomas Gleixner
3334002571SThomas Gleixner #define kernel_insn_err(insn, output, input...) \
3434002571SThomas Gleixner ({ \
3534002571SThomas Gleixner int err; \
3634002571SThomas Gleixner asm volatile("1:" #insn "\n\t" \
3734002571SThomas Gleixner "2:\n" \
38*1c3b9091SPeter Zijlstra _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %[err]) \
3934002571SThomas Gleixner : [err] "=r" (err), output \
4034002571SThomas Gleixner : "0"(0), input); \
4134002571SThomas Gleixner err; \
4234002571SThomas Gleixner })
4334002571SThomas Gleixner
4434002571SThomas Gleixner #define kernel_insn(insn, output, input...) \
4534002571SThomas Gleixner asm volatile("1:" #insn "\n\t" \
4634002571SThomas Gleixner "2:\n" \
4734002571SThomas Gleixner _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FPU_RESTORE) \
4834002571SThomas Gleixner : output : input)
4934002571SThomas Gleixner
fnsave_to_user_sigframe(struct fregs_state __user * fx)5034002571SThomas Gleixner static inline int fnsave_to_user_sigframe(struct fregs_state __user *fx)
5134002571SThomas Gleixner {
5234002571SThomas Gleixner return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
5334002571SThomas Gleixner }
5434002571SThomas Gleixner
fxsave_to_user_sigframe(struct fxregs_state __user * fx)5534002571SThomas Gleixner static inline int fxsave_to_user_sigframe(struct fxregs_state __user *fx)
5634002571SThomas Gleixner {
5734002571SThomas Gleixner if (IS_ENABLED(CONFIG_X86_32))
5834002571SThomas Gleixner return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
5934002571SThomas Gleixner else
6034002571SThomas Gleixner return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
6134002571SThomas Gleixner
6234002571SThomas Gleixner }
6334002571SThomas Gleixner
fxrstor(struct fxregs_state * fx)6434002571SThomas Gleixner static inline void fxrstor(struct fxregs_state *fx)
6534002571SThomas Gleixner {
6634002571SThomas Gleixner if (IS_ENABLED(CONFIG_X86_32))
6734002571SThomas Gleixner kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
6834002571SThomas Gleixner else
6934002571SThomas Gleixner kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
7034002571SThomas Gleixner }
7134002571SThomas Gleixner
fxrstor_safe(struct fxregs_state * fx)7234002571SThomas Gleixner static inline int fxrstor_safe(struct fxregs_state *fx)
7334002571SThomas Gleixner {
7434002571SThomas Gleixner if (IS_ENABLED(CONFIG_X86_32))
7534002571SThomas Gleixner return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
7634002571SThomas Gleixner else
7734002571SThomas Gleixner return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
7834002571SThomas Gleixner }
7934002571SThomas Gleixner
fxrstor_from_user_sigframe(struct fxregs_state __user * fx)8034002571SThomas Gleixner static inline int fxrstor_from_user_sigframe(struct fxregs_state __user *fx)
8134002571SThomas Gleixner {
8234002571SThomas Gleixner if (IS_ENABLED(CONFIG_X86_32))
8334002571SThomas Gleixner return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
8434002571SThomas Gleixner else
8534002571SThomas Gleixner return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
8634002571SThomas Gleixner }
8734002571SThomas Gleixner
frstor(struct fregs_state * fx)8834002571SThomas Gleixner static inline void frstor(struct fregs_state *fx)
8934002571SThomas Gleixner {
9034002571SThomas Gleixner kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
9134002571SThomas Gleixner }
9234002571SThomas Gleixner
frstor_safe(struct fregs_state * fx)9334002571SThomas Gleixner static inline int frstor_safe(struct fregs_state *fx)
9434002571SThomas Gleixner {
9534002571SThomas Gleixner return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
9634002571SThomas Gleixner }
9734002571SThomas Gleixner
frstor_from_user_sigframe(struct fregs_state __user * fx)9834002571SThomas Gleixner static inline int frstor_from_user_sigframe(struct fregs_state __user *fx)
9934002571SThomas Gleixner {
10034002571SThomas Gleixner return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
10134002571SThomas Gleixner }
10234002571SThomas Gleixner
fxsave(struct fxregs_state * fx)10334002571SThomas Gleixner static inline void fxsave(struct fxregs_state *fx)
10434002571SThomas Gleixner {
10534002571SThomas Gleixner if (IS_ENABLED(CONFIG_X86_32))
10634002571SThomas Gleixner asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
10734002571SThomas Gleixner else
10834002571SThomas Gleixner asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
10934002571SThomas Gleixner }
11034002571SThomas Gleixner
11134002571SThomas Gleixner #endif
112