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 | |
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 | _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 | |
50 | static 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 | |
55 | static 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 | |
64 | static 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 | |
72 | static 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 | |
80 | static 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 | |
88 | static inline void frstor(struct fregs_state *fx) |
89 | { |
90 | kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); |
91 | } |
92 | |
93 | static inline int frstor_safe(struct fregs_state *fx) |
94 | { |
95 | return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); |
96 | } |
97 | |
98 | static 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 | |
103 | static 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 | |