diff options
| -rw-r--r-- | arch/x86/include/asm/i387.h | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/i387.c | 11 | ||||
| -rw-r--r-- | arch/x86/kernel/traps.c | 12 |
3 files changed, 20 insertions, 7 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 5e275d31802e..6eb6fcb83f63 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h | |||
| @@ -51,6 +51,10 @@ static inline void kernel_fpu_end(void) | |||
| 51 | preempt_enable(); | 51 | preempt_enable(); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | /* Must be called with preempt disabled */ | ||
| 55 | extern void kernel_fpu_disable(void); | ||
| 56 | extern void kernel_fpu_enable(void); | ||
| 57 | |||
| 54 | /* | 58 | /* |
| 55 | * Some instructions like VIA's padlock instructions generate a spurious | 59 | * Some instructions like VIA's padlock instructions generate a spurious |
| 56 | * DNA fault but don't modify SSE registers. And these instructions | 60 | * DNA fault but don't modify SSE registers. And these instructions |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 12088a3f459f..81049ffab2d6 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
| @@ -21,6 +21,17 @@ | |||
| 21 | 21 | ||
| 22 | static DEFINE_PER_CPU(bool, in_kernel_fpu); | 22 | static DEFINE_PER_CPU(bool, in_kernel_fpu); |
| 23 | 23 | ||
| 24 | void kernel_fpu_disable(void) | ||
| 25 | { | ||
| 26 | WARN_ON(this_cpu_read(in_kernel_fpu)); | ||
| 27 | this_cpu_write(in_kernel_fpu, true); | ||
| 28 | } | ||
| 29 | |||
| 30 | void kernel_fpu_enable(void) | ||
| 31 | { | ||
| 32 | this_cpu_write(in_kernel_fpu, false); | ||
| 33 | } | ||
| 34 | |||
| 24 | /* | 35 | /* |
| 25 | * Were we in an interrupt that interrupted kernel mode? | 36 | * Were we in an interrupt that interrupted kernel mode? |
| 26 | * | 37 | * |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 88900e288021..fb4cb6adf225 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
| @@ -788,18 +788,16 @@ void math_state_restore(void) | |||
| 788 | local_irq_disable(); | 788 | local_irq_disable(); |
| 789 | } | 789 | } |
| 790 | 790 | ||
| 791 | /* Avoid __kernel_fpu_begin() right after __thread_fpu_begin() */ | ||
| 792 | kernel_fpu_disable(); | ||
| 791 | __thread_fpu_begin(tsk); | 793 | __thread_fpu_begin(tsk); |
| 792 | |||
| 793 | /* | ||
| 794 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
| 795 | */ | ||
| 796 | if (unlikely(restore_fpu_checking(tsk))) { | 794 | if (unlikely(restore_fpu_checking(tsk))) { |
| 797 | drop_init_fpu(tsk); | 795 | drop_init_fpu(tsk); |
| 798 | force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); | 796 | force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); |
| 799 | return; | 797 | } else { |
| 798 | tsk->thread.fpu_counter++; | ||
| 800 | } | 799 | } |
| 801 | 800 | kernel_fpu_enable(); | |
| 802 | tsk->thread.fpu_counter++; | ||
| 803 | } | 801 | } |
| 804 | EXPORT_SYMBOL_GPL(math_state_restore); | 802 | EXPORT_SYMBOL_GPL(math_state_restore); |
| 805 | 803 | ||
