]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - include/asm-x86/i387.h
36dca8db166098e323137296f1c16894133f550d
[linux-2.6-omap-h63xx.git] / include / asm-x86 / i387.h
1 /*
2  * Copyright (C) 1994 Linus Torvalds
3  *
4  * Pentium III FXSR, SSE support
5  * General FPU state handling cleanups
6  *      Gareth Hughes <gareth@valinux.com>, May 2000
7  * x86-64 work by Andi Kleen 2002
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 #include <asm/xsave.h>
22
23 extern unsigned int sig_xstate_size;
24 extern void fpu_init(void);
25 extern void mxcsr_feature_mask_init(void);
26 extern int init_fpu(struct task_struct *child);
27 extern asmlinkage void math_state_restore(void);
28 extern void init_thread_xstate(void);
29
30 extern user_regset_active_fn fpregs_active, xfpregs_active;
31 extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
32 extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
33
34 #ifdef CONFIG_IA32_EMULATION
35 extern unsigned int sig_xstate_ia32_size;
36 struct _fpstate_ia32;
37 extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
38 extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
39 #endif
40
41 #define X87_FSW_ES (1 << 7)     /* Exception Summary */
42
43 #ifdef CONFIG_X86_64
44
45 /* Ignore delayed exceptions from user space */
46 static inline void tolerant_fwait(void)
47 {
48         asm volatile("1: fwait\n"
49                      "2:\n"
50                      _ASM_EXTABLE(1b, 2b));
51 }
52
53 static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
54 {
55         int err;
56
57         asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
58                      "2:\n"
59                      ".section .fixup,\"ax\"\n"
60                      "3:  movl $-1,%[err]\n"
61                      "    jmp  2b\n"
62                      ".previous\n"
63                      _ASM_EXTABLE(1b, 3b)
64                      : [err] "=r" (err)
65 #if 0 /* See comment in __save_init_fpu() below. */
66                      : [fx] "r" (fx), "m" (*fx), "0" (0));
67 #else
68                      : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
69 #endif
70         return err;
71 }
72
73 static inline int restore_fpu_checking(struct task_struct *tsk)
74 {
75         if (task_thread_info(tsk)->status & TS_XSAVE)
76                 return xrstor_checking(&tsk->thread.xstate->xsave);
77         else
78                 return fxrstor_checking(&tsk->thread.xstate->fxsave);
79 }
80
81 /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
82    is pending. Clear the x87 state here by setting it to fixed
83    values. The kernel data segment can be sometimes 0 and sometimes
84    new user value. Both should be ok.
85    Use the PDA as safe address because it should be already in L1. */
86 static inline void clear_fpu_state(struct task_struct *tsk)
87 {
88         struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
89         struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
90
91         /*
92          * xsave header may indicate the init state of the FP.
93          */
94         if ((task_thread_info(tsk)->status & TS_XSAVE) &&
95             !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
96                 return;
97
98         if (unlikely(fx->swd & X87_FSW_ES))
99                 asm volatile("fnclex");
100         alternative_input(ASM_NOP8 ASM_NOP2,
101                           "    emms\n"          /* clear stack tags */
102                           "    fildl %%gs:0",   /* load to clear state */
103                           X86_FEATURE_FXSAVE_LEAK);
104 }
105
106 static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
107 {
108         int err;
109
110         asm volatile("1:  rex64/fxsave (%[fx])\n\t"
111                      "2:\n"
112                      ".section .fixup,\"ax\"\n"
113                      "3:  movl $-1,%[err]\n"
114                      "    jmp  2b\n"
115                      ".previous\n"
116                      _ASM_EXTABLE(1b, 3b)
117                      : [err] "=r" (err), "=m" (*fx)
118 #if 0 /* See comment in __fxsave_clear() below. */
119                      : [fx] "r" (fx), "0" (0));
120 #else
121                      : [fx] "cdaSDb" (fx), "0" (0));
122 #endif
123         if (unlikely(err) &&
124             __clear_user(fx, sizeof(struct i387_fxsave_struct)))
125                 err = -EFAULT;
126         /* No need to clear here because the caller clears USED_MATH */
127         return err;
128 }
129
130 static inline void fxsave(struct task_struct *tsk)
131 {
132         /* Using "rex64; fxsave %0" is broken because, if the memory operand
133            uses any extended registers for addressing, a second REX prefix
134            will be generated (to the assembler, rex64 followed by semicolon
135            is a separate instruction), and hence the 64-bitness is lost. */
136 #if 0
137         /* Using "fxsaveq %0" would be the ideal choice, but is only supported
138            starting with gas 2.16. */
139         __asm__ __volatile__("fxsaveq %0"
140                              : "=m" (tsk->thread.xstate->fxsave));
141 #elif 0
142         /* Using, as a workaround, the properly prefixed form below isn't
143            accepted by any binutils version so far released, complaining that
144            the same type of prefix is used twice if an extended register is
145            needed for addressing (fix submitted to mainline 2005-11-21). */
146         __asm__ __volatile__("rex64/fxsave %0"
147                              : "=m" (tsk->thread.xstate->fxsave));
148 #else
149         /* This, however, we can work around by forcing the compiler to select
150            an addressing mode that doesn't require extended registers. */
151         __asm__ __volatile__("rex64/fxsave (%1)"
152                              : "=m" (tsk->thread.xstate->fxsave)
153                              : "cdaSDb" (&tsk->thread.xstate->fxsave));
154 #endif
155 }
156
157 static inline void __save_init_fpu(struct task_struct *tsk)
158 {
159         if (task_thread_info(tsk)->status & TS_XSAVE)
160                 xsave(tsk);
161         else
162                 fxsave(tsk);
163
164         clear_fpu_state(tsk);
165         task_thread_info(tsk)->status &= ~TS_USEDFPU;
166 }
167
168 #else  /* CONFIG_X86_32 */
169
170 extern void finit(void);
171
172 static inline void tolerant_fwait(void)
173 {
174         asm volatile("fnclex ; fwait");
175 }
176
177 static inline void restore_fpu(struct task_struct *tsk)
178 {
179         if (task_thread_info(tsk)->status & TS_XSAVE) {
180                 xrstor_checking(&tsk->thread.xstate->xsave);
181                 return;
182         }
183         /*
184          * The "nop" is needed to make the instructions the same
185          * length.
186          */
187         alternative_input(
188                 "nop ; frstor %1",
189                 "fxrstor %1",
190                 X86_FEATURE_FXSR,
191                 "m" (tsk->thread.xstate->fxsave));
192 }
193
194 /* We need a safe address that is cheap to find and that is already
195    in L1 during context switch. The best choices are unfortunately
196    different for UP and SMP */
197 #ifdef CONFIG_SMP
198 #define safe_address (__per_cpu_offset[0])
199 #else
200 #define safe_address (kstat_cpu(0).cpustat.user)
201 #endif
202
203 /*
204  * These must be called with preempt disabled
205  */
206 static inline void __save_init_fpu(struct task_struct *tsk)
207 {
208         if (task_thread_info(tsk)->status & TS_XSAVE) {
209                 struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
210                 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
211
212                 xsave(tsk);
213
214                 /*
215                  * xsave header may indicate the init state of the FP.
216                  */
217                 if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
218                         goto end;
219
220                 if (unlikely(fx->swd & X87_FSW_ES))
221                         asm volatile("fnclex");
222
223                 /*
224                  * we can do a simple return here or be paranoid :)
225                  */
226                 goto clear_state;
227         }
228
229         /* Use more nops than strictly needed in case the compiler
230            varies code */
231         alternative_input(
232                 "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
233                 "fxsave %[fx]\n"
234                 "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
235                 X86_FEATURE_FXSR,
236                 [fx] "m" (tsk->thread.xstate->fxsave),
237                 [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory");
238 clear_state:
239         /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
240            is pending.  Clear the x87 state here by setting it to fixed
241            values. safe_address is a random variable that should be in L1 */
242         alternative_input(
243                 GENERIC_NOP8 GENERIC_NOP2,
244                 "emms\n\t"              /* clear stack tags */
245                 "fildl %[addr]",        /* set F?P to defined value */
246                 X86_FEATURE_FXSAVE_LEAK,
247                 [addr] "m" (safe_address));
248 end:
249         task_thread_info(tsk)->status &= ~TS_USEDFPU;
250 }
251
252 /*
253  * Signal frame handlers...
254  */
255 extern int save_i387(struct _fpstate __user *buf);
256 extern int restore_i387(struct _fpstate __user *buf);
257
258 #endif  /* CONFIG_X86_64 */
259
260 static inline void __unlazy_fpu(struct task_struct *tsk)
261 {
262         if (task_thread_info(tsk)->status & TS_USEDFPU) {
263                 __save_init_fpu(tsk);
264                 stts();
265         } else
266                 tsk->fpu_counter = 0;
267 }
268
269 static inline void __clear_fpu(struct task_struct *tsk)
270 {
271         if (task_thread_info(tsk)->status & TS_USEDFPU) {
272                 tolerant_fwait();
273                 task_thread_info(tsk)->status &= ~TS_USEDFPU;
274                 stts();
275         }
276 }
277
278 static inline void kernel_fpu_begin(void)
279 {
280         struct thread_info *me = current_thread_info();
281         preempt_disable();
282         if (me->status & TS_USEDFPU)
283                 __save_init_fpu(me->task);
284         else
285                 clts();
286 }
287
288 static inline void kernel_fpu_end(void)
289 {
290         stts();
291         preempt_enable();
292 }
293
294 #ifdef CONFIG_X86_64
295
296 static inline void save_init_fpu(struct task_struct *tsk)
297 {
298         __save_init_fpu(tsk);
299         stts();
300 }
301
302 #define unlazy_fpu      __unlazy_fpu
303 #define clear_fpu       __clear_fpu
304
305 #else  /* CONFIG_X86_32 */
306
307 /*
308  * These disable preemption on their own and are safe
309  */
310 static inline void save_init_fpu(struct task_struct *tsk)
311 {
312         preempt_disable();
313         __save_init_fpu(tsk);
314         stts();
315         preempt_enable();
316 }
317
318 static inline void unlazy_fpu(struct task_struct *tsk)
319 {
320         preempt_disable();
321         __unlazy_fpu(tsk);
322         preempt_enable();
323 }
324
325 static inline void clear_fpu(struct task_struct *tsk)
326 {
327         preempt_disable();
328         __clear_fpu(tsk);
329         preempt_enable();
330 }
331
332 #endif  /* CONFIG_X86_64 */
333
334 /*
335  * i387 state interaction
336  */
337 static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
338 {
339         if (cpu_has_fxsr) {
340                 return tsk->thread.xstate->fxsave.cwd;
341         } else {
342                 return (unsigned short)tsk->thread.xstate->fsave.cwd;
343         }
344 }
345
346 static inline unsigned short get_fpu_swd(struct task_struct *tsk)
347 {
348         if (cpu_has_fxsr) {
349                 return tsk->thread.xstate->fxsave.swd;
350         } else {
351                 return (unsigned short)tsk->thread.xstate->fsave.swd;
352         }
353 }
354
355 static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
356 {
357         if (cpu_has_xmm) {
358                 return tsk->thread.xstate->fxsave.mxcsr;
359         } else {
360                 return MXCSR_DEFAULT;
361         }
362 }
363
364 #endif /* ASM_X86__I387_H */