blob: b45abefb89f2a8c513abb12b73a18ba246eb5fcc [file] [log] [blame]
Roland McGrath1eeaed72008-01-30 13:31:51 +01001/*
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
H. Peter Anvin1965aae2008-10-22 22:26:29 -070010#ifndef _ASM_X86_I387_H
11#define _ASM_X86_I387_H
Roland McGrath1eeaed72008-01-30 13:31:51 +010012
Herbert Xu3b0d6592009-11-03 09:11:15 -050013#ifndef __ASSEMBLY__
14
Roland McGrath1eeaed72008-01-30 13:31:51 +010015#include <linux/sched.h>
16#include <linux/kernel_stat.h>
17#include <linux/regset.h>
Suresh Siddhae4914012008-08-13 22:02:26 +100018#include <linux/hardirq.h>
Avi Kivity86603282010-05-06 11:45:46 +030019#include <linux/slab.h>
H. Peter Anvin92c37fa2008-02-04 16:47:58 +010020#include <asm/asm.h>
H. Peter Anvinc9775b42010-05-11 17:49:54 -070021#include <asm/cpufeature.h>
Roland McGrath1eeaed72008-01-30 13:31:51 +010022#include <asm/processor.h>
23#include <asm/sigcontext.h>
24#include <asm/user.h>
25#include <asm/uaccess.h>
Suresh Siddhadc1e35c2008-07-29 10:29:19 -070026#include <asm/xsave.h>
Roland McGrath1eeaed72008-01-30 13:31:51 +010027
Suresh Siddha3c1c7f12008-07-29 10:29:21 -070028extern unsigned int sig_xstate_size;
Roland McGrath1eeaed72008-01-30 13:31:51 +010029extern void fpu_init(void);
Roland McGrath1eeaed72008-01-30 13:31:51 +010030extern void mxcsr_feature_mask_init(void);
Suresh Siddhaaa283f42008-03-10 15:28:05 -070031extern int init_fpu(struct task_struct *child);
Roland McGrath1eeaed72008-01-30 13:31:51 +010032extern asmlinkage void math_state_restore(void);
Jeremy Fitzhardingee6e9cac2009-04-24 00:40:59 -070033extern void __math_state_restore(void);
Jaswinder Singh36454932008-07-21 22:31:57 +053034extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
Roland McGrath1eeaed72008-01-30 13:31:51 +010035
36extern user_regset_active_fn fpregs_active, xfpregs_active;
Suresh Siddha5b3efd52010-02-11 11:50:59 -080037extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
38 xstateregs_get;
39extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
40 xstateregs_set;
41
42/*
43 * xstateregs_active == fpregs_active. Please refer to the comment
44 * at the definition of fpregs_active.
45 */
46#define xstateregs_active fpregs_active
Roland McGrath1eeaed72008-01-30 13:31:51 +010047
Suresh Siddhac37b5ef2008-07-29 10:29:25 -070048extern struct _fpx_sw_bytes fx_sw_reserved;
Roland McGrath1eeaed72008-01-30 13:31:51 +010049#ifdef CONFIG_IA32_EMULATION
Suresh Siddha3c1c7f12008-07-29 10:29:21 -070050extern unsigned int sig_xstate_ia32_size;
Suresh Siddhac37b5ef2008-07-29 10:29:25 -070051extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
Roland McGrath1eeaed72008-01-30 13:31:51 +010052struct _fpstate_ia32;
Suresh Siddhaab513702008-07-29 10:29:22 -070053struct _xstate_ia32;
54extern int save_i387_xstate_ia32(void __user *buf);
55extern int restore_i387_xstate_ia32(void __user *buf);
Roland McGrath1eeaed72008-01-30 13:31:51 +010056#endif
57
Brian Gerst8eb91a52010-09-03 21:17:16 -040058#ifdef CONFIG_MATH_EMULATION
59extern void finit_soft_fpu(struct i387_soft_struct *soft);
60#else
61static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
62#endif
63
Suresh Siddhab359e8a2008-07-29 10:29:20 -070064#define X87_FSW_ES (1 << 7) /* Exception Summary */
65
Suresh Siddha29104e12010-07-19 16:05:49 -070066static __always_inline __pure bool use_xsaveopt(void)
67{
Suresh Siddha6bad06b2010-07-19 16:05:52 -070068 return static_cpu_has(X86_FEATURE_XSAVEOPT);
Suresh Siddha29104e12010-07-19 16:05:49 -070069}
70
H. Peter Anvinc9775b42010-05-11 17:49:54 -070071static __always_inline __pure bool use_xsave(void)
Avi Kivityc9ad4882010-05-06 11:45:45 +030072{
H. Peter Anvinc9775b42010-05-11 17:49:54 -070073 return static_cpu_has(X86_FEATURE_XSAVE);
Avi Kivityc9ad4882010-05-06 11:45:45 +030074}
75
Brian Gerst58a992b2010-09-03 21:17:18 -040076static __always_inline __pure bool use_fxsr(void)
77{
78 return static_cpu_has(X86_FEATURE_FXSR);
79}
80
Suresh Siddha29104e12010-07-19 16:05:49 -070081extern void __sanitize_i387_state(struct task_struct *);
82
83static inline void sanitize_i387_state(struct task_struct *tsk)
84{
85 if (!use_xsaveopt())
86 return;
87 __sanitize_i387_state(tsk);
88}
89
Roland McGrath1eeaed72008-01-30 13:31:51 +010090#ifdef CONFIG_X86_64
Suresh Siddhab359e8a2008-07-29 10:29:20 -070091static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
Roland McGrath1eeaed72008-01-30 13:31:51 +010092{
93 int err;
94
Brian Gerst82024132010-09-03 21:17:14 -040095 /* See comment in fxsave() below. */
Roland McGrath1eeaed72008-01-30 13:31:51 +010096 asm volatile("1: rex64/fxrstor (%[fx])\n\t"
97 "2:\n"
98 ".section .fixup,\"ax\"\n"
99 "3: movl $-1,%[err]\n"
100 " jmp 2b\n"
101 ".previous\n"
Joe Perchesaffe6632008-03-23 01:02:18 -0700102 _ASM_EXTABLE(1b, 3b)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100103 : [err] "=r" (err)
Brian Gerst82024132010-09-03 21:17:14 -0400104 : [fx] "R" (fx), "m" (*fx), "0" (0));
Roland McGrath1eeaed72008-01-30 13:31:51 +0100105 return err;
106}
107
Roland McGrath1eeaed72008-01-30 13:31:51 +0100108/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
109 is pending. Clear the x87 state here by setting it to fixed
110 values. The kernel data segment can be sometimes 0 and sometimes
111 new user value. Both should be ok.
112 Use the PDA as safe address because it should be already in L1. */
Avi Kivity86603282010-05-06 11:45:46 +0300113static inline void fpu_clear(struct fpu *fpu)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100114{
Avi Kivity86603282010-05-06 11:45:46 +0300115 struct xsave_struct *xstate = &fpu->state->xsave;
116 struct i387_fxsave_struct *fx = &fpu->state->fxsave;
Suresh Siddhab359e8a2008-07-29 10:29:20 -0700117
118 /*
119 * xsave header may indicate the init state of the FP.
120 */
Avi Kivityc9ad4882010-05-06 11:45:45 +0300121 if (use_xsave() &&
Suresh Siddhab359e8a2008-07-29 10:29:20 -0700122 !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
123 return;
124
Roland McGrath1eeaed72008-01-30 13:31:51 +0100125 if (unlikely(fx->swd & X87_FSW_ES))
Joe Perchesaffe6632008-03-23 01:02:18 -0700126 asm volatile("fnclex");
Roland McGrath1eeaed72008-01-30 13:31:51 +0100127 alternative_input(ASM_NOP8 ASM_NOP2,
Joe Perchesaffe6632008-03-23 01:02:18 -0700128 " emms\n" /* clear stack tags */
129 " fildl %%gs:0", /* load to clear state */
130 X86_FEATURE_FXSAVE_LEAK);
Roland McGrath1eeaed72008-01-30 13:31:51 +0100131}
132
Avi Kivity86603282010-05-06 11:45:46 +0300133static inline void clear_fpu_state(struct task_struct *tsk)
134{
135 fpu_clear(&tsk->thread.fpu);
136}
137
Suresh Siddhac37b5ef2008-07-29 10:29:25 -0700138static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100139{
140 int err;
141
Suresh Siddha8e221b62010-06-22 16:23:37 -0700142 /*
143 * Clear the bytes not touched by the fxsave and reserved
144 * for the SW usage.
145 */
146 err = __clear_user(&fx->sw_reserved,
147 sizeof(struct _fpx_sw_bytes));
148 if (unlikely(err))
149 return -EFAULT;
150
Brian Gerst82024132010-09-03 21:17:14 -0400151 /* See comment in fxsave() below. */
Roland McGrath1eeaed72008-01-30 13:31:51 +0100152 asm volatile("1: rex64/fxsave (%[fx])\n\t"
153 "2:\n"
154 ".section .fixup,\"ax\"\n"
155 "3: movl $-1,%[err]\n"
156 " jmp 2b\n"
157 ".previous\n"
Joe Perchesaffe6632008-03-23 01:02:18 -0700158 _ASM_EXTABLE(1b, 3b)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100159 : [err] "=r" (err), "=m" (*fx)
Brian Gerst82024132010-09-03 21:17:14 -0400160 : [fx] "R" (fx), "0" (0));
Joe Perchesaffe6632008-03-23 01:02:18 -0700161 if (unlikely(err) &&
162 __clear_user(fx, sizeof(struct i387_fxsave_struct)))
Roland McGrath1eeaed72008-01-30 13:31:51 +0100163 err = -EFAULT;
164 /* No need to clear here because the caller clears USED_MATH */
165 return err;
166}
167
Avi Kivity86603282010-05-06 11:45:46 +0300168static inline void fpu_fxsave(struct fpu *fpu)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100169{
170 /* Using "rex64; fxsave %0" is broken because, if the memory operand
171 uses any extended registers for addressing, a second REX prefix
172 will be generated (to the assembler, rex64 followed by semicolon
Brian Gerst82024132010-09-03 21:17:14 -0400173 is a separate instruction), and hence the 64-bitness is lost.
174 Using "fxsaveq %0" would be the ideal choice, but is only supported
175 starting with gas 2.16.
176 asm volatile("fxsaveq %0"
177 : "=m" (fpu->state->fxsave));
178 Using, as a workaround, the properly prefixed form below isn't
Roland McGrath1eeaed72008-01-30 13:31:51 +0100179 accepted by any binutils version so far released, complaining that
180 the same type of prefix is used twice if an extended register is
Brian Gerst82024132010-09-03 21:17:14 -0400181 needed for addressing (fix submitted to mainline 2005-11-21).
182 asm volatile("rex64/fxsave %0"
183 : "=m" (fpu->state->fxsave));
184 This, however, we can work around by forcing the compiler to select
Roland McGrath1eeaed72008-01-30 13:31:51 +0100185 an addressing mode that doesn't require extended registers. */
Brian Gerst82024132010-09-03 21:17:14 -0400186 asm volatile("rex64/fxsave (%[fx])"
187 : "=m" (fpu->state->fxsave)
188 : [fx] "R" (&fpu->state->fxsave));
Suresh Siddhab359e8a2008-07-29 10:29:20 -0700189}
190
Avi Kivity86603282010-05-06 11:45:46 +0300191static inline void fpu_save_init(struct fpu *fpu)
192{
193 if (use_xsave())
194 fpu_xsave(fpu);
195 else
196 fpu_fxsave(fpu);
197
198 fpu_clear(fpu);
199}
200
Roland McGrath1eeaed72008-01-30 13:31:51 +0100201#else /* CONFIG_X86_32 */
202
Jiri Slaby34ba4762009-04-08 13:31:59 +0200203/* perform fxrstor iff the processor has extended states, otherwise frstor */
204static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100205{
206 /*
207 * The "nop" is needed to make the instructions the same
208 * length.
209 */
210 alternative_input(
211 "nop ; frstor %1",
212 "fxrstor %1",
213 X86_FEATURE_FXSR,
Jiri Slaby34ba4762009-04-08 13:31:59 +0200214 "m" (*fx));
215
Jiri Slabyfcb2ac52009-04-08 13:31:58 +0200216 return 0;
Roland McGrath1eeaed72008-01-30 13:31:51 +0100217}
218
Brian Gerst58a992b2010-09-03 21:17:18 -0400219static inline void fpu_fxsave(struct fpu *fpu)
220{
221 asm volatile("fxsave %[fx]"
222 : [fx] "=m" (fpu->state->fxsave));
223}
224
Roland McGrath1eeaed72008-01-30 13:31:51 +0100225/* We need a safe address that is cheap to find and that is already
226 in L1 during context switch. The best choices are unfortunately
227 different for UP and SMP */
228#ifdef CONFIG_SMP
229#define safe_address (__per_cpu_offset[0])
230#else
231#define safe_address (kstat_cpu(0).cpustat.user)
232#endif
233
234/*
235 * These must be called with preempt disabled
236 */
Avi Kivity86603282010-05-06 11:45:46 +0300237static inline void fpu_save_init(struct fpu *fpu)
Roland McGrath1eeaed72008-01-30 13:31:51 +0100238{
Avi Kivityc9ad4882010-05-06 11:45:45 +0300239 if (use_xsave()) {
Avi Kivity86603282010-05-06 11:45:46 +0300240 fpu_xsave(fpu);
Suresh Siddhab359e8a2008-07-29 10:29:20 -0700241
242 /*
243 * xsave header may indicate the init state of the FP.
244 */
Brian Gerst58a992b2010-09-03 21:17:18 -0400245 if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
246 return;
247 } else if (use_fxsr()) {
248 fpu_fxsave(fpu);
249 } else {
250 asm volatile("fsave %[fx]; fwait"
251 : [fx] "=m" (fpu->state->fsave));
252 return;
Suresh Siddhab359e8a2008-07-29 10:29:20 -0700253 }
254
Brian Gerst58a992b2010-09-03 21:17:18 -0400255 if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES))
256 asm volatile("fnclex");
257
Roland McGrath1eeaed72008-01-30 13:31:51 +0100258 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
259 is pending. Clear the x87 state here by setting it to fixed
260 values. safe_address is a random variable that should be in L1 */
261 alternative_input(
262 GENERIC_NOP8 GENERIC_NOP2,
263 "emms\n\t" /* clear stack tags */
264 "fildl %[addr]", /* set F?P to defined value */
265 X86_FEATURE_FXSAVE_LEAK,
266 [addr] "m" (safe_address));
Avi Kivity86603282010-05-06 11:45:46 +0300267}
268
Brian Gerstbfd946c2010-09-03 21:17:11 -0400269#endif /* CONFIG_X86_64 */
270
Avi Kivity86603282010-05-06 11:45:46 +0300271static inline void __save_init_fpu(struct task_struct *tsk)
272{
273 fpu_save_init(&tsk->thread.fpu);
Roland McGrath1eeaed72008-01-30 13:31:51 +0100274 task_thread_info(tsk)->status &= ~TS_USEDFPU;
275}
276
Avi Kivity86603282010-05-06 11:45:46 +0300277static inline int fpu_fxrstor_checking(struct fpu *fpu)
278{
279 return fxrstor_checking(&fpu->state->fxsave);
280}
281
282static inline int fpu_restore_checking(struct fpu *fpu)
283{
284 if (use_xsave())
285 return fpu_xrstor_checking(fpu);
286 else
287 return fpu_fxrstor_checking(fpu);
288}
289
Jiri Slaby34ba4762009-04-08 13:31:59 +0200290static inline int restore_fpu_checking(struct task_struct *tsk)
291{
Avi Kivity86603282010-05-06 11:45:46 +0300292 return fpu_restore_checking(&tsk->thread.fpu);
Jiri Slaby34ba4762009-04-08 13:31:59 +0200293}
294
Roland McGrath1eeaed72008-01-30 13:31:51 +0100295/*
296 * Signal frame handlers...
297 */
Suresh Siddhaab513702008-07-29 10:29:22 -0700298extern int save_i387_xstate(void __user *buf);
299extern int restore_i387_xstate(void __user *buf);
Roland McGrath1eeaed72008-01-30 13:31:51 +0100300
301static inline void __unlazy_fpu(struct task_struct *tsk)
302{
303 if (task_thread_info(tsk)->status & TS_USEDFPU) {
304 __save_init_fpu(tsk);
305 stts();
306 } else
307 tsk->fpu_counter = 0;
308}
309
310static inline void __clear_fpu(struct task_struct *tsk)
311{
312 if (task_thread_info(tsk)->status & TS_USEDFPU) {
Brian Gerst51115d42010-09-03 21:17:10 -0400313 /* Ignore delayed exceptions from user space */
314 asm volatile("1: fwait\n"
315 "2:\n"
316 _ASM_EXTABLE(1b, 2b));
Roland McGrath1eeaed72008-01-30 13:31:51 +0100317 task_thread_info(tsk)->status &= ~TS_USEDFPU;
318 stts();
319 }
320}
321
322static inline void kernel_fpu_begin(void)
323{
324 struct thread_info *me = current_thread_info();
325 preempt_disable();
326 if (me->status & TS_USEDFPU)
327 __save_init_fpu(me->task);
328 else
329 clts();
330}
331
332static inline void kernel_fpu_end(void)
333{
334 stts();
335 preempt_enable();
336}
337
Huang Yingae4b6882009-08-31 13:11:54 +0800338static inline bool irq_fpu_usable(void)
339{
340 struct pt_regs *regs;
341
342 return !in_interrupt() || !(regs = get_irq_regs()) || \
343 user_mode(regs) || (read_cr0() & X86_CR0_TS);
344}
345
Suresh Siddhae4914012008-08-13 22:02:26 +1000346/*
347 * Some instructions like VIA's padlock instructions generate a spurious
348 * DNA fault but don't modify SSE registers. And these instructions
Chuck Ebbert0b8c3d52009-06-09 10:40:50 -0400349 * get used from interrupt context as well. To prevent these kernel instructions
350 * in interrupt context interacting wrongly with other user/kernel fpu usage, we
Suresh Siddhae4914012008-08-13 22:02:26 +1000351 * should use them only in the context of irq_ts_save/restore()
352 */
353static inline int irq_ts_save(void)
354{
355 /*
Chuck Ebbert0b8c3d52009-06-09 10:40:50 -0400356 * If in process context and not atomic, we can take a spurious DNA fault.
357 * Otherwise, doing clts() in process context requires disabling preemption
358 * or some heavy lifting like kernel_fpu_begin()
Suresh Siddhae4914012008-08-13 22:02:26 +1000359 */
Chuck Ebbert0b8c3d52009-06-09 10:40:50 -0400360 if (!in_atomic())
Suresh Siddhae4914012008-08-13 22:02:26 +1000361 return 0;
362
363 if (read_cr0() & X86_CR0_TS) {
364 clts();
365 return 1;
366 }
367
368 return 0;
369}
370
371static inline void irq_ts_restore(int TS_state)
372{
373 if (TS_state)
374 stts();
375}
376
Roland McGrath1eeaed72008-01-30 13:31:51 +0100377/*
378 * These disable preemption on their own and are safe
379 */
380static inline void save_init_fpu(struct task_struct *tsk)
381{
382 preempt_disable();
383 __save_init_fpu(tsk);
384 stts();
385 preempt_enable();
386}
387
388static inline void unlazy_fpu(struct task_struct *tsk)
389{
390 preempt_disable();
391 __unlazy_fpu(tsk);
392 preempt_enable();
393}
394
395static inline void clear_fpu(struct task_struct *tsk)
396{
397 preempt_disable();
398 __clear_fpu(tsk);
399 preempt_enable();
400}
401
Roland McGrath1eeaed72008-01-30 13:31:51 +0100402/*
Roland McGrath1eeaed72008-01-30 13:31:51 +0100403 * i387 state interaction
404 */
405static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
406{
407 if (cpu_has_fxsr) {
Avi Kivity86603282010-05-06 11:45:46 +0300408 return tsk->thread.fpu.state->fxsave.cwd;
Roland McGrath1eeaed72008-01-30 13:31:51 +0100409 } else {
Avi Kivity86603282010-05-06 11:45:46 +0300410 return (unsigned short)tsk->thread.fpu.state->fsave.cwd;
Roland McGrath1eeaed72008-01-30 13:31:51 +0100411 }
412}
413
414static inline unsigned short get_fpu_swd(struct task_struct *tsk)
415{
416 if (cpu_has_fxsr) {
Avi Kivity86603282010-05-06 11:45:46 +0300417 return tsk->thread.fpu.state->fxsave.swd;
Roland McGrath1eeaed72008-01-30 13:31:51 +0100418 } else {
Avi Kivity86603282010-05-06 11:45:46 +0300419 return (unsigned short)tsk->thread.fpu.state->fsave.swd;
Roland McGrath1eeaed72008-01-30 13:31:51 +0100420 }
421}
422
423static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
424{
425 if (cpu_has_xmm) {
Avi Kivity86603282010-05-06 11:45:46 +0300426 return tsk->thread.fpu.state->fxsave.mxcsr;
Roland McGrath1eeaed72008-01-30 13:31:51 +0100427 } else {
428 return MXCSR_DEFAULT;
429 }
430}
431
Avi Kivity86603282010-05-06 11:45:46 +0300432static bool fpu_allocated(struct fpu *fpu)
433{
434 return fpu->state != NULL;
435}
436
437static inline int fpu_alloc(struct fpu *fpu)
438{
439 if (fpu_allocated(fpu))
440 return 0;
441 fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
442 if (!fpu->state)
443 return -ENOMEM;
444 WARN_ON((unsigned long)fpu->state & 15);
445 return 0;
446}
447
448static inline void fpu_free(struct fpu *fpu)
449{
450 if (fpu->state) {
451 kmem_cache_free(task_xstate_cachep, fpu->state);
452 fpu->state = NULL;
453 }
454}
455
456static inline void fpu_copy(struct fpu *dst, struct fpu *src)
457{
458 memcpy(dst->state, src->state, xstate_size);
459}
460
Sheng Yang5ee481d2010-05-17 17:22:23 +0800461extern void fpu_finit(struct fpu *fpu);
462
Herbert Xu3b0d6592009-11-03 09:11:15 -0500463#endif /* __ASSEMBLY__ */
464
H. Peter Anvin1965aae2008-10-22 22:26:29 -0700465#endif /* _ASM_X86_I387_H */