diff options
Diffstat (limited to 'arch/x86/kernel/fpu/core.c')
-rw-r--r-- | arch/x86/kernel/fpu/core.c | 155 |
1 files changed, 43 insertions, 112 deletions
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index e1114f070c2d..f92a6593de1e 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c | |||
@@ -100,7 +100,7 @@ void __kernel_fpu_begin(void) | |||
100 | 100 | ||
101 | kernel_fpu_disable(); | 101 | kernel_fpu_disable(); |
102 | 102 | ||
103 | if (fpu->fpregs_active) { | 103 | if (fpu->initialized) { |
104 | /* | 104 | /* |
105 | * Ignore return value -- we don't care if reg state | 105 | * Ignore return value -- we don't care if reg state |
106 | * is clobbered. | 106 | * is clobbered. |
@@ -116,7 +116,7 @@ void __kernel_fpu_end(void) | |||
116 | { | 116 | { |
117 | struct fpu *fpu = ¤t->thread.fpu; | 117 | struct fpu *fpu = ¤t->thread.fpu; |
118 | 118 | ||
119 | if (fpu->fpregs_active) | 119 | if (fpu->initialized) |
120 | copy_kernel_to_fpregs(&fpu->state); | 120 | copy_kernel_to_fpregs(&fpu->state); |
121 | 121 | ||
122 | kernel_fpu_enable(); | 122 | kernel_fpu_enable(); |
@@ -148,7 +148,7 @@ void fpu__save(struct fpu *fpu) | |||
148 | 148 | ||
149 | preempt_disable(); | 149 | preempt_disable(); |
150 | trace_x86_fpu_before_save(fpu); | 150 | trace_x86_fpu_before_save(fpu); |
151 | if (fpu->fpregs_active) { | 151 | if (fpu->initialized) { |
152 | if (!copy_fpregs_to_fpstate(fpu)) { | 152 | if (!copy_fpregs_to_fpstate(fpu)) { |
153 | copy_kernel_to_fpregs(&fpu->state); | 153 | copy_kernel_to_fpregs(&fpu->state); |
154 | } | 154 | } |
@@ -189,10 +189,9 @@ EXPORT_SYMBOL_GPL(fpstate_init); | |||
189 | 189 | ||
190 | int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | 190 | int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) |
191 | { | 191 | { |
192 | dst_fpu->fpregs_active = 0; | ||
193 | dst_fpu->last_cpu = -1; | 192 | dst_fpu->last_cpu = -1; |
194 | 193 | ||
195 | if (!src_fpu->fpstate_active || !static_cpu_has(X86_FEATURE_FPU)) | 194 | if (!src_fpu->initialized || !static_cpu_has(X86_FEATURE_FPU)) |
196 | return 0; | 195 | return 0; |
197 | 196 | ||
198 | WARN_ON_FPU(src_fpu != ¤t->thread.fpu); | 197 | WARN_ON_FPU(src_fpu != ¤t->thread.fpu); |
@@ -206,26 +205,14 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | |||
206 | /* | 205 | /* |
207 | * Save current FPU registers directly into the child | 206 | * Save current FPU registers directly into the child |
208 | * FPU context, without any memory-to-memory copying. | 207 | * FPU context, without any memory-to-memory copying. |
209 | * In lazy mode, if the FPU context isn't loaded into | ||
210 | * fpregs, CR0.TS will be set and do_device_not_available | ||
211 | * will load the FPU context. | ||
212 | * | 208 | * |
213 | * We have to do all this with preemption disabled, | 209 | * ( The function 'fails' in the FNSAVE case, which destroys |
214 | * mostly because of the FNSAVE case, because in that | 210 | * register contents so we have to copy them back. ) |
215 | * case we must not allow preemption in the window | ||
216 | * between the FNSAVE and us marking the context lazy. | ||
217 | * | ||
218 | * It shouldn't be an issue as even FNSAVE is plenty | ||
219 | * fast in terms of critical section length. | ||
220 | */ | 211 | */ |
221 | preempt_disable(); | ||
222 | if (!copy_fpregs_to_fpstate(dst_fpu)) { | 212 | if (!copy_fpregs_to_fpstate(dst_fpu)) { |
223 | memcpy(&src_fpu->state, &dst_fpu->state, | 213 | memcpy(&src_fpu->state, &dst_fpu->state, fpu_kernel_xstate_size); |
224 | fpu_kernel_xstate_size); | ||
225 | |||
226 | copy_kernel_to_fpregs(&src_fpu->state); | 214 | copy_kernel_to_fpregs(&src_fpu->state); |
227 | } | 215 | } |
228 | preempt_enable(); | ||
229 | 216 | ||
230 | trace_x86_fpu_copy_src(src_fpu); | 217 | trace_x86_fpu_copy_src(src_fpu); |
231 | trace_x86_fpu_copy_dst(dst_fpu); | 218 | trace_x86_fpu_copy_dst(dst_fpu); |
@@ -237,45 +224,48 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | |||
237 | * Activate the current task's in-memory FPU context, | 224 | * Activate the current task's in-memory FPU context, |
238 | * if it has not been used before: | 225 | * if it has not been used before: |
239 | */ | 226 | */ |
240 | void fpu__activate_curr(struct fpu *fpu) | 227 | void fpu__initialize(struct fpu *fpu) |
241 | { | 228 | { |
242 | WARN_ON_FPU(fpu != ¤t->thread.fpu); | 229 | WARN_ON_FPU(fpu != ¤t->thread.fpu); |
243 | 230 | ||
244 | if (!fpu->fpstate_active) { | 231 | if (!fpu->initialized) { |
245 | fpstate_init(&fpu->state); | 232 | fpstate_init(&fpu->state); |
246 | trace_x86_fpu_init_state(fpu); | 233 | trace_x86_fpu_init_state(fpu); |
247 | 234 | ||
248 | trace_x86_fpu_activate_state(fpu); | 235 | trace_x86_fpu_activate_state(fpu); |
249 | /* Safe to do for the current task: */ | 236 | /* Safe to do for the current task: */ |
250 | fpu->fpstate_active = 1; | 237 | fpu->initialized = 1; |
251 | } | 238 | } |
252 | } | 239 | } |
253 | EXPORT_SYMBOL_GPL(fpu__activate_curr); | 240 | EXPORT_SYMBOL_GPL(fpu__initialize); |
254 | 241 | ||
255 | /* | 242 | /* |
256 | * This function must be called before we read a task's fpstate. | 243 | * This function must be called before we read a task's fpstate. |
257 | * | 244 | * |
258 | * If the task has not used the FPU before then initialize its | 245 | * There's two cases where this gets called: |
259 | * fpstate. | 246 | * |
247 | * - for the current task (when coredumping), in which case we have | ||
248 | * to save the latest FPU registers into the fpstate, | ||
249 | * | ||
250 | * - or it's called for stopped tasks (ptrace), in which case the | ||
251 | * registers were already saved by the context-switch code when | ||
252 | * the task scheduled out - we only have to initialize the registers | ||
253 | * if they've never been initialized. | ||
260 | * | 254 | * |
261 | * If the task has used the FPU before then save it. | 255 | * If the task has used the FPU before then save it. |
262 | */ | 256 | */ |
263 | void fpu__activate_fpstate_read(struct fpu *fpu) | 257 | void fpu__prepare_read(struct fpu *fpu) |
264 | { | 258 | { |
265 | /* | 259 | if (fpu == ¤t->thread.fpu) { |
266 | * If fpregs are active (in the current CPU), then | ||
267 | * copy them to the fpstate: | ||
268 | */ | ||
269 | if (fpu->fpregs_active) { | ||
270 | fpu__save(fpu); | 260 | fpu__save(fpu); |
271 | } else { | 261 | } else { |
272 | if (!fpu->fpstate_active) { | 262 | if (!fpu->initialized) { |
273 | fpstate_init(&fpu->state); | 263 | fpstate_init(&fpu->state); |
274 | trace_x86_fpu_init_state(fpu); | 264 | trace_x86_fpu_init_state(fpu); |
275 | 265 | ||
276 | trace_x86_fpu_activate_state(fpu); | 266 | trace_x86_fpu_activate_state(fpu); |
277 | /* Safe to do for current and for stopped child tasks: */ | 267 | /* Safe to do for current and for stopped child tasks: */ |
278 | fpu->fpstate_active = 1; | 268 | fpu->initialized = 1; |
279 | } | 269 | } |
280 | } | 270 | } |
281 | } | 271 | } |
@@ -283,17 +273,17 @@ void fpu__activate_fpstate_read(struct fpu *fpu) | |||
283 | /* | 273 | /* |
284 | * This function must be called before we write a task's fpstate. | 274 | * This function must be called before we write a task's fpstate. |
285 | * | 275 | * |
286 | * If the task has used the FPU before then unlazy it. | 276 | * If the task has used the FPU before then invalidate any cached FPU registers. |
287 | * If the task has not used the FPU before then initialize its fpstate. | 277 | * If the task has not used the FPU before then initialize its fpstate. |
288 | * | 278 | * |
289 | * After this function call, after registers in the fpstate are | 279 | * After this function call, after registers in the fpstate are |
290 | * modified and the child task has woken up, the child task will | 280 | * modified and the child task has woken up, the child task will |
291 | * restore the modified FPU state from the modified context. If we | 281 | * restore the modified FPU state from the modified context. If we |
292 | * didn't clear its lazy status here then the lazy in-registers | 282 | * didn't clear its cached status here then the cached in-registers |
293 | * state pending on its former CPU could be restored, corrupting | 283 | * state pending on its former CPU could be restored, corrupting |
294 | * the modifications. | 284 | * the modifications. |
295 | */ | 285 | */ |
296 | void fpu__activate_fpstate_write(struct fpu *fpu) | 286 | void fpu__prepare_write(struct fpu *fpu) |
297 | { | 287 | { |
298 | /* | 288 | /* |
299 | * Only stopped child tasks can be used to modify the FPU | 289 | * Only stopped child tasks can be used to modify the FPU |
@@ -301,8 +291,8 @@ void fpu__activate_fpstate_write(struct fpu *fpu) | |||
301 | */ | 291 | */ |
302 | WARN_ON_FPU(fpu == ¤t->thread.fpu); | 292 | WARN_ON_FPU(fpu == ¤t->thread.fpu); |
303 | 293 | ||
304 | if (fpu->fpstate_active) { | 294 | if (fpu->initialized) { |
305 | /* Invalidate any lazy state: */ | 295 | /* Invalidate any cached state: */ |
306 | __fpu_invalidate_fpregs_state(fpu); | 296 | __fpu_invalidate_fpregs_state(fpu); |
307 | } else { | 297 | } else { |
308 | fpstate_init(&fpu->state); | 298 | fpstate_init(&fpu->state); |
@@ -310,74 +300,11 @@ void fpu__activate_fpstate_write(struct fpu *fpu) | |||
310 | 300 | ||
311 | trace_x86_fpu_activate_state(fpu); | 301 | trace_x86_fpu_activate_state(fpu); |
312 | /* Safe to do for stopped child tasks: */ | 302 | /* Safe to do for stopped child tasks: */ |
313 | fpu->fpstate_active = 1; | 303 | fpu->initialized = 1; |
314 | } | 304 | } |
315 | } | 305 | } |
316 | 306 | ||
317 | /* | 307 | /* |
318 | * This function must be called before we write the current | ||
319 | * task's fpstate. | ||
320 | * | ||
321 | * This call gets the current FPU register state and moves | ||
322 | * it in to the 'fpstate'. Preemption is disabled so that | ||
323 | * no writes to the 'fpstate' can occur from context | ||
324 | * swiches. | ||
325 | * | ||
326 | * Must be followed by a fpu__current_fpstate_write_end(). | ||
327 | */ | ||
328 | void fpu__current_fpstate_write_begin(void) | ||
329 | { | ||
330 | struct fpu *fpu = ¤t->thread.fpu; | ||
331 | |||
332 | /* | ||
333 | * Ensure that the context-switching code does not write | ||
334 | * over the fpstate while we are doing our update. | ||
335 | */ | ||
336 | preempt_disable(); | ||
337 | |||
338 | /* | ||
339 | * Move the fpregs in to the fpu's 'fpstate'. | ||
340 | */ | ||
341 | fpu__activate_fpstate_read(fpu); | ||
342 | |||
343 | /* | ||
344 | * The caller is about to write to 'fpu'. Ensure that no | ||
345 | * CPU thinks that its fpregs match the fpstate. This | ||
346 | * ensures we will not be lazy and skip a XRSTOR in the | ||
347 | * future. | ||
348 | */ | ||
349 | __fpu_invalidate_fpregs_state(fpu); | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * This function must be paired with fpu__current_fpstate_write_begin() | ||
354 | * | ||
355 | * This will ensure that the modified fpstate gets placed back in | ||
356 | * the fpregs if necessary. | ||
357 | * | ||
358 | * Note: This function may be called whether or not an _actual_ | ||
359 | * write to the fpstate occurred. | ||
360 | */ | ||
361 | void fpu__current_fpstate_write_end(void) | ||
362 | { | ||
363 | struct fpu *fpu = ¤t->thread.fpu; | ||
364 | |||
365 | /* | ||
366 | * 'fpu' now has an updated copy of the state, but the | ||
367 | * registers may still be out of date. Update them with | ||
368 | * an XRSTOR if they are active. | ||
369 | */ | ||
370 | if (fpregs_active()) | ||
371 | copy_kernel_to_fpregs(&fpu->state); | ||
372 | |||
373 | /* | ||
374 | * Our update is done and the fpregs/fpstate are in sync | ||
375 | * if necessary. Context switches can happen again. | ||
376 | */ | ||
377 | preempt_enable(); | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * 'fpu__restore()' is called to copy FPU registers from | 308 | * 'fpu__restore()' is called to copy FPU registers from |
382 | * the FPU fpstate to the live hw registers and to activate | 309 | * the FPU fpstate to the live hw registers and to activate |
383 | * access to the hardware registers, so that FPU instructions | 310 | * access to the hardware registers, so that FPU instructions |
@@ -389,7 +316,7 @@ void fpu__current_fpstate_write_end(void) | |||
389 | */ | 316 | */ |
390 | void fpu__restore(struct fpu *fpu) | 317 | void fpu__restore(struct fpu *fpu) |
391 | { | 318 | { |
392 | fpu__activate_curr(fpu); | 319 | fpu__initialize(fpu); |
393 | 320 | ||
394 | /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ | 321 | /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ |
395 | kernel_fpu_disable(); | 322 | kernel_fpu_disable(); |
@@ -414,15 +341,17 @@ void fpu__drop(struct fpu *fpu) | |||
414 | { | 341 | { |
415 | preempt_disable(); | 342 | preempt_disable(); |
416 | 343 | ||
417 | if (fpu->fpregs_active) { | 344 | if (fpu == ¤t->thread.fpu) { |
418 | /* Ignore delayed exceptions from user space */ | 345 | if (fpu->initialized) { |
419 | asm volatile("1: fwait\n" | 346 | /* Ignore delayed exceptions from user space */ |
420 | "2:\n" | 347 | asm volatile("1: fwait\n" |
421 | _ASM_EXTABLE(1b, 2b)); | 348 | "2:\n" |
422 | fpregs_deactivate(fpu); | 349 | _ASM_EXTABLE(1b, 2b)); |
350 | fpregs_deactivate(fpu); | ||
351 | } | ||
423 | } | 352 | } |
424 | 353 | ||
425 | fpu->fpstate_active = 0; | 354 | fpu->initialized = 0; |
426 | 355 | ||
427 | trace_x86_fpu_dropped(fpu); | 356 | trace_x86_fpu_dropped(fpu); |
428 | 357 | ||
@@ -462,9 +391,11 @@ void fpu__clear(struct fpu *fpu) | |||
462 | * Make sure fpstate is cleared and initialized. | 391 | * Make sure fpstate is cleared and initialized. |
463 | */ | 392 | */ |
464 | if (static_cpu_has(X86_FEATURE_FPU)) { | 393 | if (static_cpu_has(X86_FEATURE_FPU)) { |
465 | fpu__activate_curr(fpu); | 394 | preempt_disable(); |
395 | fpu__initialize(fpu); | ||
466 | user_fpu_begin(); | 396 | user_fpu_begin(); |
467 | copy_init_fpstate_to_fpregs(); | 397 | copy_init_fpstate_to_fpregs(); |
398 | preempt_enable(); | ||
468 | } | 399 | } |
469 | } | 400 | } |
470 | 401 | ||