diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/x86/include/asm/i387.h | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/x86/include/asm/i387.h')
-rw-r--r-- | arch/x86/include/asm/i387.h | 205 |
1 files changed, 72 insertions, 133 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index a73a8d5a5e69..c9e09ea05644 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h | |||
@@ -55,6 +55,12 @@ extern int save_i387_xstate_ia32(void __user *buf); | |||
55 | extern int restore_i387_xstate_ia32(void __user *buf); | 55 | extern int restore_i387_xstate_ia32(void __user *buf); |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | #ifdef CONFIG_MATH_EMULATION | ||
59 | extern void finit_soft_fpu(struct i387_soft_struct *soft); | ||
60 | #else | ||
61 | static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} | ||
62 | #endif | ||
63 | |||
58 | #define X87_FSW_ES (1 << 7) /* Exception Summary */ | 64 | #define X87_FSW_ES (1 << 7) /* Exception Summary */ |
59 | 65 | ||
60 | static __always_inline __pure bool use_xsaveopt(void) | 66 | static __always_inline __pure bool use_xsaveopt(void) |
@@ -67,6 +73,11 @@ static __always_inline __pure bool use_xsave(void) | |||
67 | return static_cpu_has(X86_FEATURE_XSAVE); | 73 | return static_cpu_has(X86_FEATURE_XSAVE); |
68 | } | 74 | } |
69 | 75 | ||
76 | static __always_inline __pure bool use_fxsr(void) | ||
77 | { | ||
78 | return static_cpu_has(X86_FEATURE_FXSR); | ||
79 | } | ||
80 | |||
70 | extern void __sanitize_i387_state(struct task_struct *); | 81 | extern void __sanitize_i387_state(struct task_struct *); |
71 | 82 | ||
72 | static inline void sanitize_i387_state(struct task_struct *tsk) | 83 | static inline void sanitize_i387_state(struct task_struct *tsk) |
@@ -77,20 +88,13 @@ static inline void sanitize_i387_state(struct task_struct *tsk) | |||
77 | } | 88 | } |
78 | 89 | ||
79 | #ifdef CONFIG_X86_64 | 90 | #ifdef CONFIG_X86_64 |
80 | |||
81 | /* Ignore delayed exceptions from user space */ | ||
82 | static inline void tolerant_fwait(void) | ||
83 | { | ||
84 | asm volatile("1: fwait\n" | ||
85 | "2:\n" | ||
86 | _ASM_EXTABLE(1b, 2b)); | ||
87 | } | ||
88 | |||
89 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | 91 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) |
90 | { | 92 | { |
91 | int err; | 93 | int err; |
92 | 94 | ||
93 | asm volatile("1: rex64/fxrstor (%[fx])\n\t" | 95 | /* See comment in fxsave() below. */ |
96 | #ifdef CONFIG_AS_FXSAVEQ | ||
97 | asm volatile("1: fxrstorq %[fx]\n\t" | ||
94 | "2:\n" | 98 | "2:\n" |
95 | ".section .fixup,\"ax\"\n" | 99 | ".section .fixup,\"ax\"\n" |
96 | "3: movl $-1,%[err]\n" | 100 | "3: movl $-1,%[err]\n" |
@@ -98,44 +102,21 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | |||
98 | ".previous\n" | 102 | ".previous\n" |
99 | _ASM_EXTABLE(1b, 3b) | 103 | _ASM_EXTABLE(1b, 3b) |
100 | : [err] "=r" (err) | 104 | : [err] "=r" (err) |
101 | #if 0 /* See comment in fxsave() below. */ | 105 | : [fx] "m" (*fx), "0" (0)); |
102 | : [fx] "r" (fx), "m" (*fx), "0" (0)); | ||
103 | #else | 106 | #else |
104 | : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0)); | 107 | asm volatile("1: rex64/fxrstor (%[fx])\n\t" |
108 | "2:\n" | ||
109 | ".section .fixup,\"ax\"\n" | ||
110 | "3: movl $-1,%[err]\n" | ||
111 | " jmp 2b\n" | ||
112 | ".previous\n" | ||
113 | _ASM_EXTABLE(1b, 3b) | ||
114 | : [err] "=r" (err) | ||
115 | : [fx] "R" (fx), "m" (*fx), "0" (0)); | ||
105 | #endif | 116 | #endif |
106 | return err; | 117 | return err; |
107 | } | 118 | } |
108 | 119 | ||
109 | /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception | ||
110 | is pending. Clear the x87 state here by setting it to fixed | ||
111 | values. The kernel data segment can be sometimes 0 and sometimes | ||
112 | new user value. Both should be ok. | ||
113 | Use the PDA as safe address because it should be already in L1. */ | ||
114 | static inline void fpu_clear(struct fpu *fpu) | ||
115 | { | ||
116 | struct xsave_struct *xstate = &fpu->state->xsave; | ||
117 | struct i387_fxsave_struct *fx = &fpu->state->fxsave; | ||
118 | |||
119 | /* | ||
120 | * xsave header may indicate the init state of the FP. | ||
121 | */ | ||
122 | if (use_xsave() && | ||
123 | !(xstate->xsave_hdr.xstate_bv & XSTATE_FP)) | ||
124 | return; | ||
125 | |||
126 | if (unlikely(fx->swd & X87_FSW_ES)) | ||
127 | asm volatile("fnclex"); | ||
128 | alternative_input(ASM_NOP8 ASM_NOP2, | ||
129 | " emms\n" /* clear stack tags */ | ||
130 | " fildl %%gs:0", /* load to clear state */ | ||
131 | X86_FEATURE_FXSAVE_LEAK); | ||
132 | } | ||
133 | |||
134 | static inline void clear_fpu_state(struct task_struct *tsk) | ||
135 | { | ||
136 | fpu_clear(&tsk->thread.fpu); | ||
137 | } | ||
138 | |||
139 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | 120 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) |
140 | { | 121 | { |
141 | int err; | 122 | int err; |
@@ -149,6 +130,18 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | |||
149 | if (unlikely(err)) | 130 | if (unlikely(err)) |
150 | return -EFAULT; | 131 | return -EFAULT; |
151 | 132 | ||
133 | /* See comment in fxsave() below. */ | ||
134 | #ifdef CONFIG_AS_FXSAVEQ | ||
135 | asm volatile("1: fxsaveq %[fx]\n\t" | ||
136 | "2:\n" | ||
137 | ".section .fixup,\"ax\"\n" | ||
138 | "3: movl $-1,%[err]\n" | ||
139 | " jmp 2b\n" | ||
140 | ".previous\n" | ||
141 | _ASM_EXTABLE(1b, 3b) | ||
142 | : [err] "=r" (err), [fx] "=m" (*fx) | ||
143 | : "0" (0)); | ||
144 | #else | ||
152 | asm volatile("1: rex64/fxsave (%[fx])\n\t" | 145 | asm volatile("1: rex64/fxsave (%[fx])\n\t" |
153 | "2:\n" | 146 | "2:\n" |
154 | ".section .fixup,\"ax\"\n" | 147 | ".section .fixup,\"ax\"\n" |
@@ -157,10 +150,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | |||
157 | ".previous\n" | 150 | ".previous\n" |
158 | _ASM_EXTABLE(1b, 3b) | 151 | _ASM_EXTABLE(1b, 3b) |
159 | : [err] "=r" (err), "=m" (*fx) | 152 | : [err] "=r" (err), "=m" (*fx) |
160 | #if 0 /* See comment in fxsave() below. */ | 153 | : [fx] "R" (fx), "0" (0)); |
161 | : [fx] "r" (fx), "0" (0)); | ||
162 | #else | ||
163 | : [fx] "cdaSDb" (fx), "0" (0)); | ||
164 | #endif | 154 | #endif |
165 | if (unlikely(err) && | 155 | if (unlikely(err) && |
166 | __clear_user(fx, sizeof(struct i387_fxsave_struct))) | 156 | __clear_user(fx, sizeof(struct i387_fxsave_struct))) |
@@ -175,56 +165,29 @@ static inline void fpu_fxsave(struct fpu *fpu) | |||
175 | uses any extended registers for addressing, a second REX prefix | 165 | uses any extended registers for addressing, a second REX prefix |
176 | will be generated (to the assembler, rex64 followed by semicolon | 166 | will be generated (to the assembler, rex64 followed by semicolon |
177 | is a separate instruction), and hence the 64-bitness is lost. */ | 167 | is a separate instruction), and hence the 64-bitness is lost. */ |
178 | #if 0 | 168 | |
169 | #ifdef CONFIG_AS_FXSAVEQ | ||
179 | /* Using "fxsaveq %0" would be the ideal choice, but is only supported | 170 | /* Using "fxsaveq %0" would be the ideal choice, but is only supported |
180 | starting with gas 2.16. */ | 171 | starting with gas 2.16. */ |
181 | __asm__ __volatile__("fxsaveq %0" | 172 | __asm__ __volatile__("fxsaveq %0" |
182 | : "=m" (fpu->state->fxsave)); | 173 | : "=m" (fpu->state->fxsave)); |
183 | #elif 0 | 174 | #else |
184 | /* Using, as a workaround, the properly prefixed form below isn't | 175 | /* Using, as a workaround, the properly prefixed form below isn't |
185 | accepted by any binutils version so far released, complaining that | 176 | accepted by any binutils version so far released, complaining that |
186 | the same type of prefix is used twice if an extended register is | 177 | the same type of prefix is used twice if an extended register is |
187 | needed for addressing (fix submitted to mainline 2005-11-21). */ | 178 | needed for addressing (fix submitted to mainline 2005-11-21). |
188 | __asm__ __volatile__("rex64/fxsave %0" | 179 | asm volatile("rex64/fxsave %0" |
189 | : "=m" (fpu->state->fxsave)); | 180 | : "=m" (fpu->state->fxsave)); |
190 | #else | 181 | This, however, we can work around by forcing the compiler to select |
191 | /* This, however, we can work around by forcing the compiler to select | ||
192 | an addressing mode that doesn't require extended registers. */ | 182 | an addressing mode that doesn't require extended registers. */ |
193 | __asm__ __volatile__("rex64/fxsave (%1)" | 183 | asm volatile("rex64/fxsave (%[fx])" |
194 | : "=m" (fpu->state->fxsave) | 184 | : "=m" (fpu->state->fxsave) |
195 | : "cdaSDb" (&fpu->state->fxsave)); | 185 | : [fx] "R" (&fpu->state->fxsave)); |
196 | #endif | 186 | #endif |
197 | } | 187 | } |
198 | 188 | ||
199 | static inline void fpu_save_init(struct fpu *fpu) | ||
200 | { | ||
201 | if (use_xsave()) | ||
202 | fpu_xsave(fpu); | ||
203 | else | ||
204 | fpu_fxsave(fpu); | ||
205 | |||
206 | fpu_clear(fpu); | ||
207 | } | ||
208 | |||
209 | static inline void __save_init_fpu(struct task_struct *tsk) | ||
210 | { | ||
211 | fpu_save_init(&tsk->thread.fpu); | ||
212 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | ||
213 | } | ||
214 | |||
215 | #else /* CONFIG_X86_32 */ | 189 | #else /* CONFIG_X86_32 */ |
216 | 190 | ||
217 | #ifdef CONFIG_MATH_EMULATION | ||
218 | extern void finit_soft_fpu(struct i387_soft_struct *soft); | ||
219 | #else | ||
220 | static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} | ||
221 | #endif | ||
222 | |||
223 | static inline void tolerant_fwait(void) | ||
224 | { | ||
225 | asm volatile("fnclex ; fwait"); | ||
226 | } | ||
227 | |||
228 | /* perform fxrstor iff the processor has extended states, otherwise frstor */ | 191 | /* perform fxrstor iff the processor has extended states, otherwise frstor */ |
229 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | 192 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) |
230 | { | 193 | { |
@@ -241,6 +204,14 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | |||
241 | return 0; | 204 | return 0; |
242 | } | 205 | } |
243 | 206 | ||
207 | static inline void fpu_fxsave(struct fpu *fpu) | ||
208 | { | ||
209 | asm volatile("fxsave %[fx]" | ||
210 | : [fx] "=m" (fpu->state->fxsave)); | ||
211 | } | ||
212 | |||
213 | #endif /* CONFIG_X86_64 */ | ||
214 | |||
244 | /* We need a safe address that is cheap to find and that is already | 215 | /* We need a safe address that is cheap to find and that is already |
245 | in L1 during context switch. The best choices are unfortunately | 216 | in L1 during context switch. The best choices are unfortunately |
246 | different for UP and SMP */ | 217 | different for UP and SMP */ |
@@ -256,47 +227,33 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | |||
256 | static inline void fpu_save_init(struct fpu *fpu) | 227 | static inline void fpu_save_init(struct fpu *fpu) |
257 | { | 228 | { |
258 | if (use_xsave()) { | 229 | if (use_xsave()) { |
259 | struct xsave_struct *xstate = &fpu->state->xsave; | ||
260 | struct i387_fxsave_struct *fx = &fpu->state->fxsave; | ||
261 | |||
262 | fpu_xsave(fpu); | 230 | fpu_xsave(fpu); |
263 | 231 | ||
264 | /* | 232 | /* |
265 | * xsave header may indicate the init state of the FP. | 233 | * xsave header may indicate the init state of the FP. |
266 | */ | 234 | */ |
267 | if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP)) | 235 | if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP)) |
268 | goto end; | 236 | return; |
269 | 237 | } else if (use_fxsr()) { | |
270 | if (unlikely(fx->swd & X87_FSW_ES)) | 238 | fpu_fxsave(fpu); |
271 | asm volatile("fnclex"); | 239 | } else { |
272 | 240 | asm volatile("fnsave %[fx]; fwait" | |
273 | /* | 241 | : [fx] "=m" (fpu->state->fsave)); |
274 | * we can do a simple return here or be paranoid :) | 242 | return; |
275 | */ | ||
276 | goto clear_state; | ||
277 | } | 243 | } |
278 | 244 | ||
279 | /* Use more nops than strictly needed in case the compiler | 245 | if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) |
280 | varies code */ | 246 | asm volatile("fnclex"); |
281 | alternative_input( | 247 | |
282 | "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4, | ||
283 | "fxsave %[fx]\n" | ||
284 | "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:", | ||
285 | X86_FEATURE_FXSR, | ||
286 | [fx] "m" (fpu->state->fxsave), | ||
287 | [fsw] "m" (fpu->state->fxsave.swd) : "memory"); | ||
288 | clear_state: | ||
289 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | 248 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception |
290 | is pending. Clear the x87 state here by setting it to fixed | 249 | is pending. Clear the x87 state here by setting it to fixed |
291 | values. safe_address is a random variable that should be in L1 */ | 250 | values. safe_address is a random variable that should be in L1 */ |
292 | alternative_input( | 251 | alternative_input( |
293 | GENERIC_NOP8 GENERIC_NOP2, | 252 | ASM_NOP8 ASM_NOP2, |
294 | "emms\n\t" /* clear stack tags */ | 253 | "emms\n\t" /* clear stack tags */ |
295 | "fildl %[addr]", /* set F?P to defined value */ | 254 | "fildl %P[addr]", /* set F?P to defined value */ |
296 | X86_FEATURE_FXSAVE_LEAK, | 255 | X86_FEATURE_FXSAVE_LEAK, |
297 | [addr] "m" (safe_address)); | 256 | [addr] "m" (safe_address)); |
298 | end: | ||
299 | ; | ||
300 | } | 257 | } |
301 | 258 | ||
302 | static inline void __save_init_fpu(struct task_struct *tsk) | 259 | static inline void __save_init_fpu(struct task_struct *tsk) |
@@ -305,9 +262,6 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
305 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 262 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
306 | } | 263 | } |
307 | 264 | ||
308 | |||
309 | #endif /* CONFIG_X86_64 */ | ||
310 | |||
311 | static inline int fpu_fxrstor_checking(struct fpu *fpu) | 265 | static inline int fpu_fxrstor_checking(struct fpu *fpu) |
312 | { | 266 | { |
313 | return fxrstor_checking(&fpu->state->fxsave); | 267 | return fxrstor_checking(&fpu->state->fxsave); |
@@ -344,7 +298,10 @@ static inline void __unlazy_fpu(struct task_struct *tsk) | |||
344 | static inline void __clear_fpu(struct task_struct *tsk) | 298 | static inline void __clear_fpu(struct task_struct *tsk) |
345 | { | 299 | { |
346 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | 300 | if (task_thread_info(tsk)->status & TS_USEDFPU) { |
347 | tolerant_fwait(); | 301 | /* Ignore delayed exceptions from user space */ |
302 | asm volatile("1: fwait\n" | ||
303 | "2:\n" | ||
304 | _ASM_EXTABLE(1b, 2b)); | ||
348 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 305 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
349 | stts(); | 306 | stts(); |
350 | } | 307 | } |
@@ -405,19 +362,6 @@ static inline void irq_ts_restore(int TS_state) | |||
405 | stts(); | 362 | stts(); |
406 | } | 363 | } |
407 | 364 | ||
408 | #ifdef CONFIG_X86_64 | ||
409 | |||
410 | static inline void save_init_fpu(struct task_struct *tsk) | ||
411 | { | ||
412 | __save_init_fpu(tsk); | ||
413 | stts(); | ||
414 | } | ||
415 | |||
416 | #define unlazy_fpu __unlazy_fpu | ||
417 | #define clear_fpu __clear_fpu | ||
418 | |||
419 | #else /* CONFIG_X86_32 */ | ||
420 | |||
421 | /* | 365 | /* |
422 | * These disable preemption on their own and are safe | 366 | * These disable preemption on their own and are safe |
423 | */ | 367 | */ |
@@ -443,8 +387,6 @@ static inline void clear_fpu(struct task_struct *tsk) | |||
443 | preempt_enable(); | 387 | preempt_enable(); |
444 | } | 388 | } |
445 | 389 | ||
446 | #endif /* CONFIG_X86_64 */ | ||
447 | |||
448 | /* | 390 | /* |
449 | * i387 state interaction | 391 | * i387 state interaction |
450 | */ | 392 | */ |
@@ -508,7 +450,4 @@ extern void fpu_finit(struct fpu *fpu); | |||
508 | 450 | ||
509 | #endif /* __ASSEMBLY__ */ | 451 | #endif /* __ASSEMBLY__ */ |
510 | 452 | ||
511 | #define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5 | ||
512 | #define PSHUFB_XMM5_XMM6 .byte 0x66, 0x0f, 0x38, 0x00, 0xf5 | ||
513 | |||
514 | #endif /* _ASM_X86_I387_H */ | 453 | #endif /* _ASM_X86_I387_H */ |