xref: /openbmc/linux/arch/x86/kernel/fpu/legacy.h (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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