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 | ||