aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/i387.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r--arch/x86/kernel/i387.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 739d8598f78..17b7549c413 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -32,6 +32,86 @@
32# define user32_fxsr_struct user_fxsr_struct 32# define user32_fxsr_struct user_fxsr_struct
33#endif 33#endif
34 34
35/*
36 * Were we in an interrupt that interrupted kernel mode?
37 *
38 * We can do a kernel_fpu_begin/end() pair *ONLY* if that
39 * pair does nothing at all: the thread must not have fpu (so
40 * that we don't try to save the FPU state), and TS must
41 * be set (so that the clts/stts pair does nothing that is
42 * visible in the interrupted kernel thread).
43 */
44static inline bool interrupted_kernel_fpu_idle(void)
45{
46 return !__thread_has_fpu(current) &&
47 (read_cr0() & X86_CR0_TS);
48}
49
50/*
51 * Were we in user mode (or vm86 mode) when we were
52 * interrupted?
53 *
54 * Doing kernel_fpu_begin/end() is ok if we are running
55 * in an interrupt context from user mode - we'll just
56 * save the FPU state as required.
57 */
58static inline bool interrupted_user_mode(void)
59{
60 struct pt_regs *regs = get_irq_regs();
61 return regs && user_mode_vm(regs);
62}
63
64/*
65 * Can we use the FPU in kernel mode with the
66 * whole "kernel_fpu_begin/end()" sequence?
67 *
68 * It's always ok in process context (ie "not interrupt")
69 * but it is sometimes ok even from an irq.
70 */
71bool irq_fpu_usable(void)
72{
73 return !in_interrupt() ||
74 interrupted_user_mode() ||
75 interrupted_kernel_fpu_idle();
76}
77EXPORT_SYMBOL(irq_fpu_usable);
78
79void kernel_fpu_begin(void)
80{
81 struct task_struct *me = current;
82
83 WARN_ON_ONCE(!irq_fpu_usable());
84 preempt_disable();
85 if (__thread_has_fpu(me)) {
86 __save_init_fpu(me);
87 __thread_clear_has_fpu(me);
88 /* We do 'stts()' in kernel_fpu_end() */
89 } else {
90 percpu_write(fpu_owner_task, NULL);
91 clts();
92 }
93}
94EXPORT_SYMBOL(kernel_fpu_begin);
95
96void kernel_fpu_end(void)
97{
98 stts();
99 preempt_enable();
100}
101EXPORT_SYMBOL(kernel_fpu_end);
102
103void unlazy_fpu(struct task_struct *tsk)
104{
105 preempt_disable();
106 if (__thread_has_fpu(tsk)) {
107 __save_init_fpu(tsk);
108 __thread_fpu_end(tsk);
109 } else
110 tsk->fpu_counter = 0;
111 preempt_enable();
112}
113EXPORT_SYMBOL(unlazy_fpu);
114
35#ifdef CONFIG_MATH_EMULATION 115#ifdef CONFIG_MATH_EMULATION
36# define HAVE_HWFP (boot_cpu_data.hard_math) 116# define HAVE_HWFP (boot_cpu_data.hard_math)
37#else 117#else