x86: make restore_fpu() use alternative assembler instructions
[linux-2.6] / include / asm-i386 / i387.h
1 /*
2  * include/asm-i386/i387.h
3  *
4  * Copyright (C) 1994 Linus Torvalds
5  *
6  * Pentium III FXSR, SSE support
7  * General FPU state handling cleanups
8  *      Gareth Hughes <gareth@valinux.com>, May 2000
9  */
10
11 #ifndef __ASM_I386_I387_H
12 #define __ASM_I386_I387_H
13
14 #include <linux/sched.h>
15 #include <linux/init.h>
16 #include <asm/processor.h>
17 #include <asm/sigcontext.h>
18 #include <asm/user.h>
19
20 extern void mxcsr_feature_mask_init(void);
21 extern void init_fpu(struct task_struct *);
22
23 /*
24  * FPU lazy state save handling...
25  */
26
27 /*
28  * The "nop" is needed to make the instructions the same
29  * length.
30  */
31 #define restore_fpu(tsk)                        \
32         alternative_input(                      \
33                 "nop ; frstor %1",              \
34                 "fxrstor %1",                   \
35                 X86_FEATURE_FXSR,               \
36                 "m" ((tsk)->thread.i387.fsave))
37
38 extern void kernel_fpu_begin(void);
39 #define kernel_fpu_end() do { stts(); preempt_enable(); } while(0)
40
41 /*
42  * These must be called with preempt disabled
43  */
44 static inline void __save_init_fpu( struct task_struct *tsk )
45 {
46         if ( cpu_has_fxsr ) {
47                 asm volatile( "fxsave %0 ; fnclex"
48                               : "=m" (tsk->thread.i387.fxsave) );
49         } else {
50                 asm volatile( "fnsave %0 ; fwait"
51                               : "=m" (tsk->thread.i387.fsave) );
52         }
53         tsk->thread_info->status &= ~TS_USEDFPU;
54 }
55
56 #define __unlazy_fpu( tsk ) do { \
57         if ((tsk)->thread_info->status & TS_USEDFPU) \
58                 save_init_fpu( tsk ); \
59 } while (0)
60
61 #define __clear_fpu( tsk )                                      \
62 do {                                                            \
63         if ((tsk)->thread_info->status & TS_USEDFPU) {          \
64                 asm volatile("fnclex ; fwait");                         \
65                 (tsk)->thread_info->status &= ~TS_USEDFPU;      \
66                 stts();                                         \
67         }                                                       \
68 } while (0)
69
70
71 /*
72  * These disable preemption on their own and are safe
73  */
74 static inline void save_init_fpu( struct task_struct *tsk )
75 {
76         preempt_disable();
77         __save_init_fpu(tsk);
78         stts();
79         preempt_enable();
80 }
81
82 #define unlazy_fpu( tsk ) do {  \
83         preempt_disable();      \
84         __unlazy_fpu(tsk);      \
85         preempt_enable();       \
86 } while (0)
87
88 #define clear_fpu( tsk ) do {   \
89         preempt_disable();      \
90         __clear_fpu( tsk );     \
91         preempt_enable();       \
92 } while (0)
93                                         \
94 /*
95  * FPU state interaction...
96  */
97 extern unsigned short get_fpu_cwd( struct task_struct *tsk );
98 extern unsigned short get_fpu_swd( struct task_struct *tsk );
99 extern unsigned short get_fpu_mxcsr( struct task_struct *tsk );
100
101 /*
102  * Signal frame handlers...
103  */
104 extern int save_i387( struct _fpstate __user *buf );
105 extern int restore_i387( struct _fpstate __user *buf );
106
107 /*
108  * ptrace request handers...
109  */
110 extern int get_fpregs( struct user_i387_struct __user *buf,
111                        struct task_struct *tsk );
112 extern int set_fpregs( struct task_struct *tsk,
113                        struct user_i387_struct __user *buf );
114
115 extern int get_fpxregs( struct user_fxsr_struct __user *buf,
116                         struct task_struct *tsk );
117 extern int set_fpxregs( struct task_struct *tsk,
118                         struct user_fxsr_struct __user *buf );
119
120 /*
121  * FPU state for core dumps...
122  */
123 extern int dump_fpu( struct pt_regs *regs,
124                      struct user_i387_struct *fpu );
125
126 #endif /* __ASM_I386_I387_H */