1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __X86_KERNEL_FPU_LEGACY_H
3 #define __X86_KERNEL_FPU_LEGACY_H
4 
5 #include <asm/fpu/types.h>
6 
7 extern unsigned int mxcsr_feature_mask;
8 
ldmxcsr(u32 mxcsr)9 static inline void ldmxcsr(u32 mxcsr)
10 {
11 	asm volatile("ldmxcsr %0" :: "m" (mxcsr));
12 }
13 
14 /*
15  * Returns 0 on success or the trap number when the operation raises an
16  * exception.
17  */
18 #define user_insn(insn, output, input...)				\
19 ({									\
20 	int err;							\
21 									\
22 	might_fault();							\
23 									\
24 	asm volatile(ASM_STAC "\n"					\
25 		     "1: " #insn "\n"					\
26 		     "2: " ASM_CLAC "\n"				\
27 		     _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_MCE_SAFE)	\
28 		     : [err] "=a" (err), output				\
29 		     : "0"(0), input);					\
30 	err;								\
31 })
32 
33 #define kernel_insn_err(insn, output, input...)				\
34 ({									\
35 	int err;							\
36 	asm volatile("1:" #insn "\n\t"					\
37 		     "2:\n"						\
38 		     ".section .fixup,\"ax\"\n"				\
39 		     "3:  movl $-1,%[err]\n"				\
40 		     "    jmp  2b\n"					\
41 		     ".previous\n"					\
42 		     _ASM_EXTABLE(1b, 3b)				\
43 		     : [err] "=r" (err), output				\
44 		     : "0"(0), input);					\
45 	err;								\
46 })
47 
48 #define kernel_insn(insn, output, input...)				\
49 	asm volatile("1:" #insn "\n\t"					\
50 		     "2:\n"						\
51 		     _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FPU_RESTORE)	\
52 		     : output : input)
53 
fnsave_to_user_sigframe(struct fregs_state __user * fx)54 static inline int fnsave_to_user_sigframe(struct fregs_state __user *fx)
55 {
56 	return user_insn(fnsave %[fx]; fwait,  [fx] "=m" (*fx), "m" (*fx));
57 }
58 
fxsave_to_user_sigframe(struct fxregs_state __user * fx)59 static inline int fxsave_to_user_sigframe(struct fxregs_state __user *fx)
60 {
61 	if (IS_ENABLED(CONFIG_X86_32))
62 		return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
63 	else
64 		return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
65 
66 }
67 
fxrstor(struct fxregs_state * fx)68 static inline void fxrstor(struct fxregs_state *fx)
69 {
70 	if (IS_ENABLED(CONFIG_X86_32))
71 		kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
72 	else
73 		kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
74 }
75 
fxrstor_safe(struct fxregs_state * fx)76 static inline int fxrstor_safe(struct fxregs_state *fx)
77 {
78 	if (IS_ENABLED(CONFIG_X86_32))
79 		return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
80 	else
81 		return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
82 }
83 
fxrstor_from_user_sigframe(struct fxregs_state __user * fx)84 static inline int fxrstor_from_user_sigframe(struct fxregs_state __user *fx)
85 {
86 	if (IS_ENABLED(CONFIG_X86_32))
87 		return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
88 	else
89 		return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
90 }
91 
frstor(struct fregs_state * fx)92 static inline void frstor(struct fregs_state *fx)
93 {
94 	kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
95 }
96 
frstor_safe(struct fregs_state * fx)97 static inline int frstor_safe(struct fregs_state *fx)
98 {
99 	return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
100 }
101 
frstor_from_user_sigframe(struct fregs_state __user * fx)102 static inline int frstor_from_user_sigframe(struct fregs_state __user *fx)
103 {
104 	return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
105 }
106 
fxsave(struct fxregs_state * fx)107 static inline void fxsave(struct fxregs_state *fx)
108 {
109 	if (IS_ENABLED(CONFIG_X86_32))
110 		asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
111 	else
112 		asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
113 }
114 
115 #endif
116