diff options
| -rw-r--r-- | arch/x86/include/asm/i387.h | 17 | ||||
| -rw-r--r-- | arch/x86/kernel/traps.c | 40 |
2 files changed, 22 insertions, 35 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 8df95849721d..74c607b37e87 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h | |||
| @@ -29,7 +29,6 @@ extern unsigned int sig_xstate_size; | |||
| 29 | extern void fpu_init(void); | 29 | extern void fpu_init(void); |
| 30 | extern void mxcsr_feature_mask_init(void); | 30 | extern void mxcsr_feature_mask_init(void); |
| 31 | extern int init_fpu(struct task_struct *child); | 31 | extern int init_fpu(struct task_struct *child); |
| 32 | extern void __math_state_restore(struct task_struct *); | ||
| 33 | extern void math_state_restore(void); | 32 | extern void math_state_restore(void); |
| 34 | extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); | 33 | extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); |
| 35 | 34 | ||
| @@ -269,6 +268,16 @@ static inline int fpu_restore_checking(struct fpu *fpu) | |||
| 269 | 268 | ||
| 270 | static inline int restore_fpu_checking(struct task_struct *tsk) | 269 | static inline int restore_fpu_checking(struct task_struct *tsk) |
| 271 | { | 270 | { |
| 271 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | ||
| 272 | is pending. Clear the x87 state here by setting it to fixed | ||
| 273 | values. "m" is a random variable that should be in L1 */ | ||
| 274 | alternative_input( | ||
| 275 | ASM_NOP8 ASM_NOP2, | ||
| 276 | "emms\n\t" /* clear stack tags */ | ||
| 277 | "fildl %P[addr]", /* set F?P to defined value */ | ||
| 278 | X86_FEATURE_FXSAVE_LEAK, | ||
| 279 | [addr] "m" (tsk->thread.has_fpu)); | ||
| 280 | |||
| 272 | return fpu_restore_checking(&tsk->thread.fpu); | 281 | return fpu_restore_checking(&tsk->thread.fpu); |
| 273 | } | 282 | } |
| 274 | 283 | ||
| @@ -378,8 +387,10 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta | |||
| 378 | */ | 387 | */ |
| 379 | static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu) | 388 | static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu) |
| 380 | { | 389 | { |
| 381 | if (fpu.preload) | 390 | if (fpu.preload) { |
| 382 | __math_state_restore(new); | 391 | if (unlikely(restore_fpu_checking(new))) |
| 392 | __thread_fpu_end(new); | ||
| 393 | } | ||
| 383 | } | 394 | } |
| 384 | 395 | ||
| 385 | /* | 396 | /* |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 77da5b475ad2..4bbe04d96744 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
| @@ -571,37 +571,6 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) | |||
| 571 | } | 571 | } |
| 572 | 572 | ||
| 573 | /* | 573 | /* |
| 574 | * This gets called with the process already owning the | ||
| 575 | * FPU state, and with CR0.TS cleared. It just needs to | ||
| 576 | * restore the FPU register state. | ||
| 577 | */ | ||
| 578 | void __math_state_restore(struct task_struct *tsk) | ||
| 579 | { | ||
| 580 | /* We need a safe address that is cheap to find and that is already | ||
| 581 | in L1. We've just brought in "tsk->thread.has_fpu", so use that */ | ||
| 582 | #define safe_address (tsk->thread.has_fpu) | ||
| 583 | |||
| 584 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | ||
| 585 | is pending. Clear the x87 state here by setting it to fixed | ||
| 586 | values. safe_address is a random variable that should be in L1 */ | ||
| 587 | alternative_input( | ||
| 588 | ASM_NOP8 ASM_NOP2, | ||
| 589 | "emms\n\t" /* clear stack tags */ | ||
| 590 | "fildl %P[addr]", /* set F?P to defined value */ | ||
| 591 | X86_FEATURE_FXSAVE_LEAK, | ||
| 592 | [addr] "m" (safe_address)); | ||
| 593 | |||
| 594 | /* | ||
| 595 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
| 596 | */ | ||
| 597 | if (unlikely(restore_fpu_checking(tsk))) { | ||
| 598 | __thread_fpu_end(tsk); | ||
| 599 | force_sig(SIGSEGV, tsk); | ||
| 600 | return; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | /* | ||
| 605 | * 'math_state_restore()' saves the current math information in the | 574 | * 'math_state_restore()' saves the current math information in the |
| 606 | * old math state array, and gets the new ones from the current task | 575 | * old math state array, and gets the new ones from the current task |
| 607 | * | 576 | * |
| @@ -631,7 +600,14 @@ void math_state_restore(void) | |||
| 631 | } | 600 | } |
| 632 | 601 | ||
| 633 | __thread_fpu_begin(tsk); | 602 | __thread_fpu_begin(tsk); |
| 634 | __math_state_restore(tsk); | 603 | /* |
| 604 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
| 605 | */ | ||
| 606 | if (unlikely(restore_fpu_checking(tsk))) { | ||
| 607 | __thread_fpu_end(tsk); | ||
| 608 | force_sig(SIGSEGV, tsk); | ||
| 609 | return; | ||
| 610 | } | ||
| 635 | 611 | ||
| 636 | tsk->fpu_counter++; | 612 | tsk->fpu_counter++; |
| 637 | } | 613 | } |
