aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-x86/i387.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-x86/i387.h')
-rw-r--r--include/asm-x86/i387.h91
1 files changed, 76 insertions, 15 deletions
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h
index 56d00e31aec0..9ba862a4eac0 100644
--- a/include/asm-x86/i387.h
+++ b/include/asm-x86/i387.h
@@ -7,8 +7,8 @@
7 * x86-64 work by Andi Kleen 2002 7 * x86-64 work by Andi Kleen 2002
8 */ 8 */
9 9
10#ifndef _ASM_X86_I387_H 10#ifndef ASM_X86__I387_H
11#define _ASM_X86_I387_H 11#define ASM_X86__I387_H
12 12
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <linux/kernel_stat.h> 14#include <linux/kernel_stat.h>
@@ -19,23 +19,32 @@
19#include <asm/sigcontext.h> 19#include <asm/sigcontext.h>
20#include <asm/user.h> 20#include <asm/user.h>
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22#include <asm/xsave.h>
22 23
24extern unsigned int sig_xstate_size;
23extern void fpu_init(void); 25extern void fpu_init(void);
24extern void mxcsr_feature_mask_init(void); 26extern void mxcsr_feature_mask_init(void);
25extern int init_fpu(struct task_struct *child); 27extern int init_fpu(struct task_struct *child);
26extern asmlinkage void math_state_restore(void); 28extern asmlinkage void math_state_restore(void);
27extern void init_thread_xstate(void); 29extern void init_thread_xstate(void);
30extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
28 31
29extern user_regset_active_fn fpregs_active, xfpregs_active; 32extern user_regset_active_fn fpregs_active, xfpregs_active;
30extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; 33extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
31extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; 34extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
32 35
36extern struct _fpx_sw_bytes fx_sw_reserved;
33#ifdef CONFIG_IA32_EMULATION 37#ifdef CONFIG_IA32_EMULATION
38extern unsigned int sig_xstate_ia32_size;
39extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
34struct _fpstate_ia32; 40struct _fpstate_ia32;
35extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); 41struct _xstate_ia32;
36extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); 42extern int save_i387_xstate_ia32(void __user *buf);
43extern int restore_i387_xstate_ia32(void __user *buf);
37#endif 44#endif
38 45
46#define X87_FSW_ES (1 << 7) /* Exception Summary */
47
39#ifdef CONFIG_X86_64 48#ifdef CONFIG_X86_64
40 49
41/* Ignore delayed exceptions from user space */ 50/* Ignore delayed exceptions from user space */
@@ -46,7 +55,7 @@ static inline void tolerant_fwait(void)
46 _ASM_EXTABLE(1b, 2b)); 55 _ASM_EXTABLE(1b, 2b));
47} 56}
48 57
49static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) 58static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
50{ 59{
51 int err; 60 int err;
52 61
@@ -66,15 +75,31 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
66 return err; 75 return err;
67} 76}
68 77
69#define X87_FSW_ES (1 << 7) /* Exception Summary */ 78static inline int restore_fpu_checking(struct task_struct *tsk)
79{
80 if (task_thread_info(tsk)->status & TS_XSAVE)
81 return xrstor_checking(&tsk->thread.xstate->xsave);
82 else
83 return fxrstor_checking(&tsk->thread.xstate->fxsave);
84}
70 85
71/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception 86/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
72 is pending. Clear the x87 state here by setting it to fixed 87 is pending. Clear the x87 state here by setting it to fixed
73 values. The kernel data segment can be sometimes 0 and sometimes 88 values. The kernel data segment can be sometimes 0 and sometimes
74 new user value. Both should be ok. 89 new user value. Both should be ok.
75 Use the PDA as safe address because it should be already in L1. */ 90 Use the PDA as safe address because it should be already in L1. */
76static inline void clear_fpu_state(struct i387_fxsave_struct *fx) 91static inline void clear_fpu_state(struct task_struct *tsk)
77{ 92{
93 struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
94 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
95
96 /*
97 * xsave header may indicate the init state of the FP.
98 */
99 if ((task_thread_info(tsk)->status & TS_XSAVE) &&
100 !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
101 return;
102
78 if (unlikely(fx->swd & X87_FSW_ES)) 103 if (unlikely(fx->swd & X87_FSW_ES))
79 asm volatile("fnclex"); 104 asm volatile("fnclex");
80 alternative_input(ASM_NOP8 ASM_NOP2, 105 alternative_input(ASM_NOP8 ASM_NOP2,
@@ -83,7 +108,7 @@ static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
83 X86_FEATURE_FXSAVE_LEAK); 108 X86_FEATURE_FXSAVE_LEAK);
84} 109}
85 110
86static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) 111static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
87{ 112{
88 int err; 113 int err;
89 114
@@ -107,7 +132,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
107 return err; 132 return err;
108} 133}
109 134
110static inline void __save_init_fpu(struct task_struct *tsk) 135static inline void fxsave(struct task_struct *tsk)
111{ 136{
112 /* Using "rex64; fxsave %0" is broken because, if the memory operand 137 /* Using "rex64; fxsave %0" is broken because, if the memory operand
113 uses any extended registers for addressing, a second REX prefix 138 uses any extended registers for addressing, a second REX prefix
@@ -132,7 +157,16 @@ static inline void __save_init_fpu(struct task_struct *tsk)
132 : "=m" (tsk->thread.xstate->fxsave) 157 : "=m" (tsk->thread.xstate->fxsave)
133 : "cdaSDb" (&tsk->thread.xstate->fxsave)); 158 : "cdaSDb" (&tsk->thread.xstate->fxsave));
134#endif 159#endif
135 clear_fpu_state(&tsk->thread.xstate->fxsave); 160}
161
162static inline void __save_init_fpu(struct task_struct *tsk)
163{
164 if (task_thread_info(tsk)->status & TS_XSAVE)
165 xsave(tsk);
166 else
167 fxsave(tsk);
168
169 clear_fpu_state(tsk);
136 task_thread_info(tsk)->status &= ~TS_USEDFPU; 170 task_thread_info(tsk)->status &= ~TS_USEDFPU;
137} 171}
138 172
@@ -147,6 +181,10 @@ static inline void tolerant_fwait(void)
147 181
148static inline void restore_fpu(struct task_struct *tsk) 182static inline void restore_fpu(struct task_struct *tsk)
149{ 183{
184 if (task_thread_info(tsk)->status & TS_XSAVE) {
185 xrstor_checking(&tsk->thread.xstate->xsave);
186 return;
187 }
150 /* 188 /*
151 * The "nop" is needed to make the instructions the same 189 * The "nop" is needed to make the instructions the same
152 * length. 190 * length.
@@ -172,6 +210,27 @@ static inline void restore_fpu(struct task_struct *tsk)
172 */ 210 */
173static inline void __save_init_fpu(struct task_struct *tsk) 211static inline void __save_init_fpu(struct task_struct *tsk)
174{ 212{
213 if (task_thread_info(tsk)->status & TS_XSAVE) {
214 struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
215 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
216
217 xsave(tsk);
218
219 /*
220 * xsave header may indicate the init state of the FP.
221 */
222 if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
223 goto end;
224
225 if (unlikely(fx->swd & X87_FSW_ES))
226 asm volatile("fnclex");
227
228 /*
229 * we can do a simple return here or be paranoid :)
230 */
231 goto clear_state;
232 }
233
175 /* Use more nops than strictly needed in case the compiler 234 /* Use more nops than strictly needed in case the compiler
176 varies code */ 235 varies code */
177 alternative_input( 236 alternative_input(
@@ -181,6 +240,7 @@ static inline void __save_init_fpu(struct task_struct *tsk)
181 X86_FEATURE_FXSR, 240 X86_FEATURE_FXSR,
182 [fx] "m" (tsk->thread.xstate->fxsave), 241 [fx] "m" (tsk->thread.xstate->fxsave),
183 [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); 242 [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory");
243clear_state:
184 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception 244 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
185 is pending. Clear the x87 state here by setting it to fixed 245 is pending. Clear the x87 state here by setting it to fixed
186 values. safe_address is a random variable that should be in L1 */ 246 values. safe_address is a random variable that should be in L1 */
@@ -190,16 +250,17 @@ static inline void __save_init_fpu(struct task_struct *tsk)
190 "fildl %[addr]", /* set F?P to defined value */ 250 "fildl %[addr]", /* set F?P to defined value */
191 X86_FEATURE_FXSAVE_LEAK, 251 X86_FEATURE_FXSAVE_LEAK,
192 [addr] "m" (safe_address)); 252 [addr] "m" (safe_address));
253end:
193 task_thread_info(tsk)->status &= ~TS_USEDFPU; 254 task_thread_info(tsk)->status &= ~TS_USEDFPU;
194} 255}
195 256
257#endif /* CONFIG_X86_64 */
258
196/* 259/*
197 * Signal frame handlers... 260 * Signal frame handlers...
198 */ 261 */
199extern int save_i387(struct _fpstate __user *buf); 262extern int save_i387_xstate(void __user *buf);
200extern int restore_i387(struct _fpstate __user *buf); 263extern int restore_i387_xstate(void __user *buf);
201
202#endif /* CONFIG_X86_64 */
203 264
204static inline void __unlazy_fpu(struct task_struct *tsk) 265static inline void __unlazy_fpu(struct task_struct *tsk)
205{ 266{
@@ -336,4 +397,4 @@ static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
336 } 397 }
337} 398}
338 399
339#endif /* _ASM_X86_I387_H */ 400#endif /* ASM_X86__I387_H */