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
7extern unsigned int mxcsr_feature_mask;
8
9static 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		     _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %[err]) \
39		     : [err] "=r" (err), output				\
40		     : "0"(0), input);					\
41	err;								\
42})
43
44#define kernel_insn(insn, output, input...)				\
45	asm volatile("1:" #insn "\n\t"					\
46		     "2:\n"						\
47		     _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FPU_RESTORE)	\
48		     : output : input)
49
50static inline int fnsave_to_user_sigframe(struct fregs_state __user *fx)
51{
52	return user_insn(fnsave %[fx]; fwait,  [fx] "=m" (*fx), "m" (*fx));
53}
54
55static inline int fxsave_to_user_sigframe(struct fxregs_state __user *fx)
56{
57	if (IS_ENABLED(CONFIG_X86_32))
58		return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
59	else
60		return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
61
62}
63
64static inline void fxrstor(struct fxregs_state *fx)
65{
66	if (IS_ENABLED(CONFIG_X86_32))
67		kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
68	else
69		kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
70}
71
72static inline int fxrstor_safe(struct fxregs_state *fx)
73{
74	if (IS_ENABLED(CONFIG_X86_32))
75		return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
76	else
77		return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
78}
79
80static inline int fxrstor_from_user_sigframe(struct fxregs_state __user *fx)
81{
82	if (IS_ENABLED(CONFIG_X86_32))
83		return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
84	else
85		return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
86}
87
88static inline void frstor(struct fregs_state *fx)
89{
90	kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
91}
92
93static inline int frstor_safe(struct fregs_state *fx)
94{
95	return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
96}
97
98static inline int frstor_from_user_sigframe(struct fregs_state __user *fx)
99{
100	return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
101}
102
103static inline void fxsave(struct fxregs_state *fx)
104{
105	if (IS_ENABLED(CONFIG_X86_32))
106		asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
107	else
108		asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
109}
110
111#endif
112