1
2
3
4
5
6
7
8
9
10#ifndef _ASM_X86_I387_H
11#define _ASM_X86_I387_H
12
13#include <linux/sched.h>
14#include <linux/kernel_stat.h>
15#include <linux/regset.h>
16#include <asm/asm.h>
17#include <asm/processor.h>
18#include <asm/sigcontext.h>
19#include <asm/user.h>
20#include <asm/uaccess.h>
21
22extern void fpu_init(void);
23extern void mxcsr_feature_mask_init(void);
24extern void init_fpu(struct task_struct *child);
25extern asmlinkage void math_state_restore(void);
26
27extern user_regset_active_fn fpregs_active, xfpregs_active;
28extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
29extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
30
31#ifdef CONFIG_IA32_EMULATION
32struct _fpstate_ia32;
33extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
34extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
35#endif
36
37#ifdef CONFIG_X86_64
38
39
40static inline void tolerant_fwait(void)
41{
42 asm volatile("1: fwait\n"
43 "2:\n"
44 _ASM_EXTABLE(1b,2b));
45}
46
47static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
48{
49 int err;
50
51 asm volatile("1: rex64/fxrstor (%[fx])\n\t"
52 "2:\n"
53 ".section .fixup,\"ax\"\n"
54 "3: movl $-1,%[err]\n"
55 " jmp 2b\n"
56 ".previous\n"
57 _ASM_EXTABLE(1b,3b)
58 : [err] "=r" (err)
59#if 0
60 : [fx] "r" (fx), "m" (*fx), "0" (0));
61#else
62 : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
63#endif
64 if (unlikely(err))
65 init_fpu(current);
66 return err;
67}
68
69#define X87_FSW_ES (1 << 7)
70
71
72
73
74
75
76static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
77{
78 if (unlikely(fx->swd & X87_FSW_ES))
79 asm volatile("fnclex");
80 alternative_input(ASM_NOP8 ASM_NOP2,
81 " emms\n"
82 " fildl %%gs:0",
83 X86_FEATURE_FXSAVE_LEAK);
84}
85
86static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
87{
88 int err;
89
90 asm volatile("1: rex64/fxsave (%[fx])\n\t"
91 "2:\n"
92 ".section .fixup,\"ax\"\n"
93 "3: movl $-1,%[err]\n"
94 " jmp 2b\n"
95 ".previous\n"
96 _ASM_EXTABLE(1b,3b)
97 : [err] "=r" (err), "=m" (*fx)
98#if 0
99 : [fx] "r" (fx), "0" (0));
100#else
101 : [fx] "cdaSDb" (fx), "0" (0));
102#endif
103 if (unlikely(err) && __clear_user(fx, sizeof(struct i387_fxsave_struct)))
104 err = -EFAULT;
105
106 return err;
107}
108
109static inline void __save_init_fpu(struct task_struct *tsk)
110{
111
112
113
114
115#if 0
116
117
118 __asm__ __volatile__("fxsaveq %0"
119 : "=m" (tsk->thread.i387.fxsave));
120#elif 0
121
122
123
124
125 __asm__ __volatile__("rex64/fxsave %0"
126 : "=m" (tsk->thread.i387.fxsave));
127#else
128
129
130 __asm__ __volatile__("rex64/fxsave %P2(%1)"
131 : "=m" (tsk->thread.i387.fxsave)
132 : "cdaSDb" (tsk),
133 "i" (offsetof(__typeof__(*tsk),
134 thread.i387.fxsave)));
135#endif
136 clear_fpu_state(&tsk->thread.i387.fxsave);
137 task_thread_info(tsk)->status &= ~TS_USEDFPU;
138}
139
140
141
142
143
144static inline int save_i387(struct _fpstate __user *buf)
145{
146 struct task_struct *tsk = current;
147 int err = 0;
148
149 BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
150 sizeof(tsk->thread.i387.fxsave));
151
152 if ((unsigned long)buf % 16)
153 printk("save_i387: bad fpstate %p\n", buf);
154
155 if (!used_math())
156 return 0;
157 clear_used_math();
158 if (task_thread_info(tsk)->status & TS_USEDFPU) {
159 err = save_i387_checking((struct i387_fxsave_struct __user *)buf);
160 if (err) return err;
161 task_thread_info(tsk)->status &= ~TS_USEDFPU;
162 stts();
163 } else {
164 if (__copy_to_user(buf, &tsk->thread.i387.fxsave,
165 sizeof(struct i387_fxsave_struct)))
166 return -1;
167 }
168 return 1;
169}
170
171
172
173
174static inline int restore_i387(struct _fpstate __user *buf)
175{
176 set_used_math();
177 if (!(task_thread_info(current)->status & TS_USEDFPU)) {
178 clts();
179 task_thread_info(current)->status |= TS_USEDFPU;
180 }
181 return restore_fpu_checking((__force struct i387_fxsave_struct *)buf);
182}
183
184#else
185
186static inline void tolerant_fwait(void)
187{
188 asm volatile("fnclex ; fwait");
189}
190
191static inline void restore_fpu(struct task_struct *tsk)
192{
193
194
195
196
197 alternative_input(
198 "nop ; frstor %1",
199 "fxrstor %1",
200 X86_FEATURE_FXSR,
201 "m" ((tsk)->thread.i387.fxsave));
202}
203
204
205
206
207#ifdef CONFIG_SMP
208#define safe_address (__per_cpu_offset[0])
209#else
210#define safe_address (kstat_cpu(0).cpustat.user)
211#endif
212
213
214
215
216static inline void __save_init_fpu(struct task_struct *tsk)
217{
218
219
220 alternative_input(
221 "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
222 "fxsave %[fx]\n"
223 "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
224 X86_FEATURE_FXSR,
225 [fx] "m" (tsk->thread.i387.fxsave),
226 [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory");
227
228
229
230 alternative_input(
231 GENERIC_NOP8 GENERIC_NOP2,
232 "emms\n\t"
233 "fildl %[addr]",
234 X86_FEATURE_FXSAVE_LEAK,
235 [addr] "m" (safe_address));
236 task_thread_info(tsk)->status &= ~TS_USEDFPU;
237}
238
239
240
241
242extern int save_i387(struct _fpstate __user *buf);
243extern int restore_i387(struct _fpstate __user *buf);
244
245#endif
246
247static inline void __unlazy_fpu(struct task_struct *tsk)
248{
249 if (task_thread_info(tsk)->status & TS_USEDFPU) {
250 __save_init_fpu(tsk);
251 stts();
252 } else
253 tsk->fpu_counter = 0;
254}
255
256static inline void __clear_fpu(struct task_struct *tsk)
257{
258 if (task_thread_info(tsk)->status & TS_USEDFPU) {
259 tolerant_fwait();
260 task_thread_info(tsk)->status &= ~TS_USEDFPU;
261 stts();
262 }
263}
264
265static inline void kernel_fpu_begin(void)
266{
267 struct thread_info *me = current_thread_info();
268 preempt_disable();
269 if (me->status & TS_USEDFPU)
270 __save_init_fpu(me->task);
271 else
272 clts();
273}
274
275static inline void kernel_fpu_end(void)
276{
277 stts();
278 preempt_enable();
279}
280
281#ifdef CONFIG_X86_64
282
283static inline void save_init_fpu(struct task_struct *tsk)
284{
285 __save_init_fpu(tsk);
286 stts();
287}
288
289#define unlazy_fpu __unlazy_fpu
290#define clear_fpu __clear_fpu
291
292#else
293
294
295
296
297static inline void save_init_fpu(struct task_struct *tsk)
298{
299 preempt_disable();
300 __save_init_fpu(tsk);
301 stts();
302 preempt_enable();
303}
304
305static inline void unlazy_fpu(struct task_struct *tsk)
306{
307 preempt_disable();
308 __unlazy_fpu(tsk);
309 preempt_enable();
310}
311
312static inline void clear_fpu(struct task_struct *tsk)
313{
314 preempt_disable();
315 __clear_fpu(tsk);
316 preempt_enable();
317}
318
319#endif
320
321
322
323
324static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
325{
326 if (cpu_has_fxsr) {
327 return tsk->thread.i387.fxsave.cwd;
328 } else {
329 return (unsigned short)tsk->thread.i387.fsave.cwd;
330 }
331}
332
333static inline unsigned short get_fpu_swd(struct task_struct *tsk)
334{
335 if (cpu_has_fxsr) {
336 return tsk->thread.i387.fxsave.swd;
337 } else {
338 return (unsigned short)tsk->thread.i387.fsave.swd;
339 }
340}
341
342static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
343{
344 if (cpu_has_xmm) {
345 return tsk->thread.i387.fxsave.mxcsr;
346 } else {
347 return MXCSR_DEFAULT;
348 }
349}
350
351#endif
352