diff options
Diffstat (limited to 'include/asm-x86/i387.h')
-rw-r--r-- | include/asm-x86/i387.h | 91 |
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 | ||
24 | extern unsigned int sig_xstate_size; | ||
23 | extern void fpu_init(void); | 25 | extern void fpu_init(void); |
24 | extern void mxcsr_feature_mask_init(void); | 26 | extern void mxcsr_feature_mask_init(void); |
25 | extern int init_fpu(struct task_struct *child); | 27 | extern int init_fpu(struct task_struct *child); |
26 | extern asmlinkage void math_state_restore(void); | 28 | extern asmlinkage void math_state_restore(void); |
27 | extern void init_thread_xstate(void); | 29 | extern void init_thread_xstate(void); |
30 | extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); | ||
28 | 31 | ||
29 | extern user_regset_active_fn fpregs_active, xfpregs_active; | 32 | extern user_regset_active_fn fpregs_active, xfpregs_active; |
30 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; | 33 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; |
31 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; | 34 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; |
32 | 35 | ||
36 | extern struct _fpx_sw_bytes fx_sw_reserved; | ||
33 | #ifdef CONFIG_IA32_EMULATION | 37 | #ifdef CONFIG_IA32_EMULATION |
38 | extern unsigned int sig_xstate_ia32_size; | ||
39 | extern struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
34 | struct _fpstate_ia32; | 40 | struct _fpstate_ia32; |
35 | extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); | 41 | struct _xstate_ia32; |
36 | extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); | 42 | extern int save_i387_xstate_ia32(void __user *buf); |
43 | extern 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 | ||
49 | static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | 58 | static 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 */ | 78 | static 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. */ |
76 | static inline void clear_fpu_state(struct i387_fxsave_struct *fx) | 91 | static 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 | ||
86 | static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | 111 | static 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 | ||
110 | static inline void __save_init_fpu(struct task_struct *tsk) | 135 | static 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 | |||
162 | static 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 | ||
148 | static inline void restore_fpu(struct task_struct *tsk) | 182 | static 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 | */ |
173 | static inline void __save_init_fpu(struct task_struct *tsk) | 211 | static 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"); |
243 | clear_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)); |
253 | end: | ||
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 | */ |
199 | extern int save_i387(struct _fpstate __user *buf); | 262 | extern int save_i387_xstate(void __user *buf); |
200 | extern int restore_i387(struct _fpstate __user *buf); | 263 | extern int restore_i387_xstate(void __user *buf); |
201 | |||
202 | #endif /* CONFIG_X86_64 */ | ||
203 | 264 | ||
204 | static inline void __unlazy_fpu(struct task_struct *tsk) | 265 | static 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 */ |