Commit | Line | Data |
---|---|---|
1da177e4 LT |
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> | |
18bd057b | 16 | #include <linux/kernel_stat.h> |
1da177e4 LT |
17 | #include <asm/processor.h> |
18 | #include <asm/sigcontext.h> | |
19 | #include <asm/user.h> | |
20 | ||
21 | extern void mxcsr_feature_mask_init(void); | |
22 | extern void init_fpu(struct task_struct *); | |
8ed1383f | 23 | |
1da177e4 LT |
24 | /* |
25 | * FPU lazy state save handling... | |
26 | */ | |
8ed1383f LT |
27 | |
28 | /* | |
29 | * The "nop" is needed to make the instructions the same | |
30 | * length. | |
31 | */ | |
32 | #define restore_fpu(tsk) \ | |
33 | alternative_input( \ | |
34 | "nop ; frstor %1", \ | |
35 | "fxrstor %1", \ | |
36 | X86_FEATURE_FXSR, \ | |
2847e347 | 37 | "m" ((tsk)->thread.i387.fxsave)) |
1da177e4 LT |
38 | |
39 | extern void kernel_fpu_begin(void); | |
40 | #define kernel_fpu_end() do { stts(); preempt_enable(); } while(0) | |
41 | ||
18bd057b AK |
42 | /* We need a safe address that is cheap to find and that is already |
43 | in L1 during context switch. The best choices are unfortunately | |
44 | different for UP and SMP */ | |
45 | #ifdef CONFIG_SMP | |
46 | #define safe_address (__per_cpu_offset[0]) | |
47 | #else | |
48 | #define safe_address (kstat_cpu(0).cpustat.user) | |
49 | #endif | |
50 | ||
1da177e4 LT |
51 | /* |
52 | * These must be called with preempt disabled | |
53 | */ | |
54 | static inline void __save_init_fpu( struct task_struct *tsk ) | |
55 | { | |
18bd057b AK |
56 | /* Use more nops than strictly needed in case the compiler |
57 | varies code */ | |
2847e347 | 58 | alternative_input( |
18bd057b AK |
59 | "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4, |
60 | "fxsave %[fx]\n" | |
543f2a33 | 61 | "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:", |
2847e347 | 62 | X86_FEATURE_FXSR, |
18bd057b AK |
63 | [fx] "m" (tsk->thread.i387.fxsave), |
64 | [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory"); | |
65 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | |
66 | is pending. Clear the x87 state here by setting it to fixed | |
543f2a33 | 67 | values. safe_address is a random variable that should be in L1 */ |
18bd057b AK |
68 | alternative_input( |
69 | GENERIC_NOP8 GENERIC_NOP2, | |
70 | "emms\n\t" /* clear stack tags */ | |
71 | "fildl %[addr]", /* set F?P to defined value */ | |
72 | X86_FEATURE_FXSAVE_LEAK, | |
73 | [addr] "m" (safe_address)); | |
06b425d8 | 74 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
1da177e4 LT |
75 | } |
76 | ||
c41bf8fa JK |
77 | #define __unlazy_fpu( tsk ) do { \ |
78 | if (task_thread_info(tsk)->status & TS_USEDFPU) { \ | |
79 | __save_init_fpu(tsk); \ | |
80 | stts(); \ | |
81 | } else \ | |
82 | tsk->fpu_counter = 0; \ | |
1da177e4 LT |
83 | } while (0) |
84 | ||
85 | #define __clear_fpu( tsk ) \ | |
86 | do { \ | |
02b64dab JK |
87 | if (task_thread_info(tsk)->status & TS_USEDFPU) { \ |
88 | asm volatile("fnclex ; fwait"); \ | |
06b425d8 | 89 | task_thread_info(tsk)->status &= ~TS_USEDFPU; \ |
1da177e4 LT |
90 | stts(); \ |
91 | } \ | |
92 | } while (0) | |
93 | ||
94 | ||
95 | /* | |
96 | * These disable preemption on their own and are safe | |
97 | */ | |
98 | static inline void save_init_fpu( struct task_struct *tsk ) | |
99 | { | |
100 | preempt_disable(); | |
101 | __save_init_fpu(tsk); | |
102 | stts(); | |
103 | preempt_enable(); | |
104 | } | |
105 | ||
106 | #define unlazy_fpu( tsk ) do { \ | |
107 | preempt_disable(); \ | |
108 | __unlazy_fpu(tsk); \ | |
109 | preempt_enable(); \ | |
110 | } while (0) | |
111 | ||
112 | #define clear_fpu( tsk ) do { \ | |
113 | preempt_disable(); \ | |
114 | __clear_fpu( tsk ); \ | |
115 | preempt_enable(); \ | |
116 | } while (0) | |
02b64dab | 117 | |
1da177e4 LT |
118 | /* |
119 | * FPU state interaction... | |
120 | */ | |
121 | extern unsigned short get_fpu_cwd( struct task_struct *tsk ); | |
122 | extern unsigned short get_fpu_swd( struct task_struct *tsk ); | |
123 | extern unsigned short get_fpu_mxcsr( struct task_struct *tsk ); | |
acc20761 | 124 | extern asmlinkage void math_state_restore(void); |
1da177e4 LT |
125 | |
126 | /* | |
127 | * Signal frame handlers... | |
128 | */ | |
129 | extern int save_i387( struct _fpstate __user *buf ); | |
130 | extern int restore_i387( struct _fpstate __user *buf ); | |
131 | ||
132 | /* | |
133 | * ptrace request handers... | |
134 | */ | |
135 | extern int get_fpregs( struct user_i387_struct __user *buf, | |
136 | struct task_struct *tsk ); | |
137 | extern int set_fpregs( struct task_struct *tsk, | |
138 | struct user_i387_struct __user *buf ); | |
139 | ||
140 | extern int get_fpxregs( struct user_fxsr_struct __user *buf, | |
141 | struct task_struct *tsk ); | |
142 | extern int set_fpxregs( struct task_struct *tsk, | |
143 | struct user_fxsr_struct __user *buf ); | |
144 | ||
145 | /* | |
146 | * FPU state for core dumps... | |
147 | */ | |
148 | extern int dump_fpu( struct pt_regs *regs, | |
149 | struct user_i387_struct *fpu ); | |
150 | ||
151 | #endif /* __ASM_I386_I387_H */ |