diff options
Diffstat (limited to 'include/asm-x86/i387.h')
-rw-r--r-- | include/asm-x86/i387.h | 60 |
1 files changed, 31 insertions, 29 deletions
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h index f377b76b2f34..da2adb45f6e3 100644 --- a/include/asm-x86/i387.h +++ b/include/asm-x86/i387.h | |||
@@ -21,8 +21,9 @@ | |||
21 | 21 | ||
22 | extern void fpu_init(void); | 22 | extern void fpu_init(void); |
23 | extern void mxcsr_feature_mask_init(void); | 23 | extern void mxcsr_feature_mask_init(void); |
24 | extern void init_fpu(struct task_struct *child); | 24 | extern int init_fpu(struct task_struct *child); |
25 | extern asmlinkage void math_state_restore(void); | 25 | extern asmlinkage void math_state_restore(void); |
26 | extern void init_thread_xstate(void); | ||
26 | 27 | ||
27 | extern user_regset_active_fn fpregs_active, xfpregs_active; | 28 | extern user_regset_active_fn fpregs_active, xfpregs_active; |
28 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; | 29 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; |
@@ -41,7 +42,7 @@ static inline void tolerant_fwait(void) | |||
41 | { | 42 | { |
42 | asm volatile("1: fwait\n" | 43 | asm volatile("1: fwait\n" |
43 | "2:\n" | 44 | "2:\n" |
44 | _ASM_EXTABLE(1b,2b)); | 45 | _ASM_EXTABLE(1b, 2b)); |
45 | } | 46 | } |
46 | 47 | ||
47 | static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | 48 | static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) |
@@ -54,7 +55,7 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | |||
54 | "3: movl $-1,%[err]\n" | 55 | "3: movl $-1,%[err]\n" |
55 | " jmp 2b\n" | 56 | " jmp 2b\n" |
56 | ".previous\n" | 57 | ".previous\n" |
57 | _ASM_EXTABLE(1b,3b) | 58 | _ASM_EXTABLE(1b, 3b) |
58 | : [err] "=r" (err) | 59 | : [err] "=r" (err) |
59 | #if 0 /* See comment in __save_init_fpu() below. */ | 60 | #if 0 /* See comment in __save_init_fpu() below. */ |
60 | : [fx] "r" (fx), "m" (*fx), "0" (0)); | 61 | : [fx] "r" (fx), "m" (*fx), "0" (0)); |
@@ -76,11 +77,11 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | |||
76 | static inline void clear_fpu_state(struct i387_fxsave_struct *fx) | 77 | static inline void clear_fpu_state(struct i387_fxsave_struct *fx) |
77 | { | 78 | { |
78 | if (unlikely(fx->swd & X87_FSW_ES)) | 79 | if (unlikely(fx->swd & X87_FSW_ES)) |
79 | asm volatile("fnclex"); | 80 | asm volatile("fnclex"); |
80 | alternative_input(ASM_NOP8 ASM_NOP2, | 81 | alternative_input(ASM_NOP8 ASM_NOP2, |
81 | " emms\n" /* clear stack tags */ | 82 | " emms\n" /* clear stack tags */ |
82 | " fildl %%gs:0", /* load to clear state */ | 83 | " fildl %%gs:0", /* load to clear state */ |
83 | X86_FEATURE_FXSAVE_LEAK); | 84 | X86_FEATURE_FXSAVE_LEAK); |
84 | } | 85 | } |
85 | 86 | ||
86 | static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | 87 | static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) |
@@ -93,14 +94,15 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | |||
93 | "3: movl $-1,%[err]\n" | 94 | "3: movl $-1,%[err]\n" |
94 | " jmp 2b\n" | 95 | " jmp 2b\n" |
95 | ".previous\n" | 96 | ".previous\n" |
96 | _ASM_EXTABLE(1b,3b) | 97 | _ASM_EXTABLE(1b, 3b) |
97 | : [err] "=r" (err), "=m" (*fx) | 98 | : [err] "=r" (err), "=m" (*fx) |
98 | #if 0 /* See comment in __fxsave_clear() below. */ | 99 | #if 0 /* See comment in __fxsave_clear() below. */ |
99 | : [fx] "r" (fx), "0" (0)); | 100 | : [fx] "r" (fx), "0" (0)); |
100 | #else | 101 | #else |
101 | : [fx] "cdaSDb" (fx), "0" (0)); | 102 | : [fx] "cdaSDb" (fx), "0" (0)); |
102 | #endif | 103 | #endif |
103 | if (unlikely(err) && __clear_user(fx, sizeof(struct i387_fxsave_struct))) | 104 | if (unlikely(err) && |
105 | __clear_user(fx, sizeof(struct i387_fxsave_struct))) | ||
104 | err = -EFAULT; | 106 | err = -EFAULT; |
105 | /* No need to clear here because the caller clears USED_MATH */ | 107 | /* No need to clear here because the caller clears USED_MATH */ |
106 | return err; | 108 | return err; |
@@ -116,24 +118,22 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
116 | /* Using "fxsaveq %0" would be the ideal choice, but is only supported | 118 | /* Using "fxsaveq %0" would be the ideal choice, but is only supported |
117 | starting with gas 2.16. */ | 119 | starting with gas 2.16. */ |
118 | __asm__ __volatile__("fxsaveq %0" | 120 | __asm__ __volatile__("fxsaveq %0" |
119 | : "=m" (tsk->thread.i387.fxsave)); | 121 | : "=m" (tsk->thread.xstate->fxsave)); |
120 | #elif 0 | 122 | #elif 0 |
121 | /* Using, as a workaround, the properly prefixed form below isn't | 123 | /* Using, as a workaround, the properly prefixed form below isn't |
122 | accepted by any binutils version so far released, complaining that | 124 | accepted by any binutils version so far released, complaining that |
123 | the same type of prefix is used twice if an extended register is | 125 | the same type of prefix is used twice if an extended register is |
124 | needed for addressing (fix submitted to mainline 2005-11-21). */ | 126 | needed for addressing (fix submitted to mainline 2005-11-21). */ |
125 | __asm__ __volatile__("rex64/fxsave %0" | 127 | __asm__ __volatile__("rex64/fxsave %0" |
126 | : "=m" (tsk->thread.i387.fxsave)); | 128 | : "=m" (tsk->thread.xstate->fxsave)); |
127 | #else | 129 | #else |
128 | /* This, however, we can work around by forcing the compiler to select | 130 | /* This, however, we can work around by forcing the compiler to select |
129 | an addressing mode that doesn't require extended registers. */ | 131 | an addressing mode that doesn't require extended registers. */ |
130 | __asm__ __volatile__("rex64/fxsave %P2(%1)" | 132 | __asm__ __volatile__("rex64/fxsave (%1)" |
131 | : "=m" (tsk->thread.i387.fxsave) | 133 | : "=m" (tsk->thread.xstate->fxsave) |
132 | : "cdaSDb" (tsk), | 134 | : "cdaSDb" (&tsk->thread.xstate->fxsave)); |
133 | "i" (offsetof(__typeof__(*tsk), | ||
134 | thread.i387.fxsave))); | ||
135 | #endif | 135 | #endif |
136 | clear_fpu_state(&tsk->thread.i387.fxsave); | 136 | clear_fpu_state(&tsk->thread.xstate->fxsave); |
137 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 137 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
138 | } | 138 | } |
139 | 139 | ||
@@ -147,7 +147,7 @@ static inline int save_i387(struct _fpstate __user *buf) | |||
147 | int err = 0; | 147 | int err = 0; |
148 | 148 | ||
149 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != | 149 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != |
150 | sizeof(tsk->thread.i387.fxsave)); | 150 | sizeof(tsk->thread.xstate->fxsave)); |
151 | 151 | ||
152 | if ((unsigned long)buf % 16) | 152 | if ((unsigned long)buf % 16) |
153 | printk("save_i387: bad fpstate %p\n", buf); | 153 | printk("save_i387: bad fpstate %p\n", buf); |
@@ -156,12 +156,14 @@ static inline int save_i387(struct _fpstate __user *buf) | |||
156 | return 0; | 156 | return 0; |
157 | clear_used_math(); /* trigger finit */ | 157 | clear_used_math(); /* trigger finit */ |
158 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | 158 | if (task_thread_info(tsk)->status & TS_USEDFPU) { |
159 | err = save_i387_checking((struct i387_fxsave_struct __user *)buf); | 159 | err = save_i387_checking((struct i387_fxsave_struct __user *) |
160 | if (err) return err; | 160 | buf); |
161 | if (err) | ||
162 | return err; | ||
161 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 163 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
162 | stts(); | 164 | stts(); |
163 | } else { | 165 | } else { |
164 | if (__copy_to_user(buf, &tsk->thread.i387.fxsave, | 166 | if (__copy_to_user(buf, &tsk->thread.xstate->fxsave, |
165 | sizeof(struct i387_fxsave_struct))) | 167 | sizeof(struct i387_fxsave_struct))) |
166 | return -1; | 168 | return -1; |
167 | } | 169 | } |
@@ -198,7 +200,7 @@ static inline void restore_fpu(struct task_struct *tsk) | |||
198 | "nop ; frstor %1", | 200 | "nop ; frstor %1", |
199 | "fxrstor %1", | 201 | "fxrstor %1", |
200 | X86_FEATURE_FXSR, | 202 | X86_FEATURE_FXSR, |
201 | "m" ((tsk)->thread.i387.fxsave)); | 203 | "m" (tsk->thread.xstate->fxsave)); |
202 | } | 204 | } |
203 | 205 | ||
204 | /* We need a safe address that is cheap to find and that is already | 206 | /* We need a safe address that is cheap to find and that is already |
@@ -222,8 +224,8 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
222 | "fxsave %[fx]\n" | 224 | "fxsave %[fx]\n" |
223 | "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:", | 225 | "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:", |
224 | X86_FEATURE_FXSR, | 226 | X86_FEATURE_FXSR, |
225 | [fx] "m" (tsk->thread.i387.fxsave), | 227 | [fx] "m" (tsk->thread.xstate->fxsave), |
226 | [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory"); | 228 | [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); |
227 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | 229 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception |
228 | is pending. Clear the x87 state here by setting it to fixed | 230 | is pending. Clear the x87 state here by setting it to fixed |
229 | values. safe_address is a random variable that should be in L1 */ | 231 | values. safe_address is a random variable that should be in L1 */ |
@@ -324,25 +326,25 @@ static inline void clear_fpu(struct task_struct *tsk) | |||
324 | static inline unsigned short get_fpu_cwd(struct task_struct *tsk) | 326 | static inline unsigned short get_fpu_cwd(struct task_struct *tsk) |
325 | { | 327 | { |
326 | if (cpu_has_fxsr) { | 328 | if (cpu_has_fxsr) { |
327 | return tsk->thread.i387.fxsave.cwd; | 329 | return tsk->thread.xstate->fxsave.cwd; |
328 | } else { | 330 | } else { |
329 | return (unsigned short)tsk->thread.i387.fsave.cwd; | 331 | return (unsigned short)tsk->thread.xstate->fsave.cwd; |
330 | } | 332 | } |
331 | } | 333 | } |
332 | 334 | ||
333 | static inline unsigned short get_fpu_swd(struct task_struct *tsk) | 335 | static inline unsigned short get_fpu_swd(struct task_struct *tsk) |
334 | { | 336 | { |
335 | if (cpu_has_fxsr) { | 337 | if (cpu_has_fxsr) { |
336 | return tsk->thread.i387.fxsave.swd; | 338 | return tsk->thread.xstate->fxsave.swd; |
337 | } else { | 339 | } else { |
338 | return (unsigned short)tsk->thread.i387.fsave.swd; | 340 | return (unsigned short)tsk->thread.xstate->fsave.swd; |
339 | } | 341 | } |
340 | } | 342 | } |
341 | 343 | ||
342 | static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk) | 344 | static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk) |
343 | { | 345 | { |
344 | if (cpu_has_xmm) { | 346 | if (cpu_has_xmm) { |
345 | return tsk->thread.i387.fxsave.mxcsr; | 347 | return tsk->thread.xstate->fxsave.mxcsr; |
346 | } else { | 348 | } else { |
347 | return MXCSR_DEFAULT; | 349 | return MXCSR_DEFAULT; |
348 | } | 350 | } |