diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2012-07-24 19:05:28 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-09-18 18:51:26 -0400 |
commit | 0ca5bd0d886578ad0afeceaa83458c0f35cb3c6b (patch) | |
tree | 97c8e2c62d1be5fd66c2a6da28d439255bd37ed1 /arch/x86/include/asm/fpu-internal.h | |
parent | 050902c011712ad4703038fa4489ec4edd87d396 (diff) |
x86, fpu: Consolidate inline asm routines for saving/restoring fpu state
Consolidate x86, x86_64 inline asm routines saving/restoring fpu state
using config_enabled().
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Link: http://lkml.kernel.org/r/1343171129-2747-3-git-send-email-suresh.b.siddha@intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/include/asm/fpu-internal.h')
-rw-r--r-- | arch/x86/include/asm/fpu-internal.h | 184 |
1 files changed, 77 insertions, 107 deletions
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index 6f595435ff9e..016acb30fa4a 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h | |||
@@ -97,34 +97,24 @@ static inline void sanitize_i387_state(struct task_struct *tsk) | |||
97 | __sanitize_i387_state(tsk); | 97 | __sanitize_i387_state(tsk); |
98 | } | 98 | } |
99 | 99 | ||
100 | #ifdef CONFIG_X86_64 | 100 | #define check_insn(insn, output, input...) \ |
101 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | 101 | ({ \ |
102 | { | 102 | int err; \ |
103 | int err; | 103 | asm volatile("1:" #insn "\n\t" \ |
104 | 104 | "2:\n" \ | |
105 | /* See comment in fxsave() below. */ | 105 | ".section .fixup,\"ax\"\n" \ |
106 | #ifdef CONFIG_AS_FXSAVEQ | 106 | "3: movl $-1,%[err]\n" \ |
107 | asm volatile("1: fxrstorq %[fx]\n\t" | 107 | " jmp 2b\n" \ |
108 | "2:\n" | 108 | ".previous\n" \ |
109 | ".section .fixup,\"ax\"\n" | 109 | _ASM_EXTABLE(1b, 3b) \ |
110 | "3: movl $-1,%[err]\n" | 110 | : [err] "=r" (err), output \ |
111 | " jmp 2b\n" | 111 | : "0"(0), input); \ |
112 | ".previous\n" | 112 | err; \ |
113 | _ASM_EXTABLE(1b, 3b) | 113 | }) |
114 | : [err] "=r" (err) | 114 | |
115 | : [fx] "m" (*fx), "0" (0)); | 115 | static inline int fsave_user(struct i387_fsave_struct __user *fx) |
116 | #else | 116 | { |
117 | asm volatile("1: rex64/fxrstor (%[fx])\n\t" | 117 | return check_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx)); |
118 | "2:\n" | ||
119 | ".section .fixup,\"ax\"\n" | ||
120 | "3: movl $-1,%[err]\n" | ||
121 | " jmp 2b\n" | ||
122 | ".previous\n" | ||
123 | _ASM_EXTABLE(1b, 3b) | ||
124 | : [err] "=r" (err) | ||
125 | : [fx] "R" (fx), "m" (*fx), "0" (0)); | ||
126 | #endif | ||
127 | return err; | ||
128 | } | 118 | } |
129 | 119 | ||
130 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | 120 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) |
@@ -140,90 +130,73 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | |||
140 | if (unlikely(err)) | 130 | if (unlikely(err)) |
141 | return -EFAULT; | 131 | return -EFAULT; |
142 | 132 | ||
143 | /* See comment in fxsave() below. */ | 133 | if (config_enabled(CONFIG_X86_32)) |
144 | #ifdef CONFIG_AS_FXSAVEQ | 134 | return check_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx)); |
145 | asm volatile("1: fxsaveq %[fx]\n\t" | 135 | else if (config_enabled(CONFIG_AS_FXSAVEQ)) |
146 | "2:\n" | 136 | return check_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx)); |
147 | ".section .fixup,\"ax\"\n" | 137 | |
148 | "3: movl $-1,%[err]\n" | 138 | /* See comment in fpu_fxsave() below. */ |
149 | " jmp 2b\n" | 139 | return check_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx)); |
150 | ".previous\n" | ||
151 | _ASM_EXTABLE(1b, 3b) | ||
152 | : [err] "=r" (err), [fx] "=m" (*fx) | ||
153 | : "0" (0)); | ||
154 | #else | ||
155 | asm volatile("1: rex64/fxsave (%[fx])\n\t" | ||
156 | "2:\n" | ||
157 | ".section .fixup,\"ax\"\n" | ||
158 | "3: movl $-1,%[err]\n" | ||
159 | " jmp 2b\n" | ||
160 | ".previous\n" | ||
161 | _ASM_EXTABLE(1b, 3b) | ||
162 | : [err] "=r" (err), "=m" (*fx) | ||
163 | : [fx] "R" (fx), "0" (0)); | ||
164 | #endif | ||
165 | if (unlikely(err) && | ||
166 | __clear_user(fx, sizeof(struct i387_fxsave_struct))) | ||
167 | err = -EFAULT; | ||
168 | /* No need to clear here because the caller clears USED_MATH */ | ||
169 | return err; | ||
170 | } | 140 | } |
171 | 141 | ||
172 | static inline void fpu_fxsave(struct fpu *fpu) | 142 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) |
173 | { | 143 | { |
174 | /* Using "rex64; fxsave %0" is broken because, if the memory operand | 144 | if (config_enabled(CONFIG_X86_32)) |
175 | uses any extended registers for addressing, a second REX prefix | 145 | return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); |
176 | will be generated (to the assembler, rex64 followed by semicolon | 146 | else if (config_enabled(CONFIG_AS_FXSAVEQ)) |
177 | is a separate instruction), and hence the 64-bitness is lost. */ | 147 | return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); |
178 | 148 | ||
179 | #ifdef CONFIG_AS_FXSAVEQ | 149 | /* See comment in fpu_fxsave() below. */ |
180 | /* Using "fxsaveq %0" would be the ideal choice, but is only supported | 150 | return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), |
181 | starting with gas 2.16. */ | 151 | "m" (*fx)); |
182 | __asm__ __volatile__("fxsaveq %0" | ||
183 | : "=m" (fpu->state->fxsave)); | ||
184 | #else | ||
185 | /* Using, as a workaround, the properly prefixed form below isn't | ||
186 | accepted by any binutils version so far released, complaining that | ||
187 | the same type of prefix is used twice if an extended register is | ||
188 | needed for addressing (fix submitted to mainline 2005-11-21). | ||
189 | asm volatile("rex64/fxsave %0" | ||
190 | : "=m" (fpu->state->fxsave)); | ||
191 | This, however, we can work around by forcing the compiler to select | ||
192 | an addressing mode that doesn't require extended registers. */ | ||
193 | asm volatile("rex64/fxsave (%[fx])" | ||
194 | : "=m" (fpu->state->fxsave) | ||
195 | : [fx] "R" (&fpu->state->fxsave)); | ||
196 | #endif | ||
197 | } | 152 | } |
198 | 153 | ||
199 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 154 | static inline int frstor_checking(struct i387_fsave_struct *fx) |
200 | compat_sigset_t *set, struct pt_regs *regs); | ||
201 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
202 | compat_sigset_t *set, struct pt_regs *regs); | ||
203 | |||
204 | #else /* CONFIG_X86_32 */ | ||
205 | |||
206 | /* perform fxrstor iff the processor has extended states, otherwise frstor */ | ||
207 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) | ||
208 | { | 155 | { |
209 | /* | 156 | return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); |
210 | * The "nop" is needed to make the instructions the same | ||
211 | * length. | ||
212 | */ | ||
213 | alternative_input( | ||
214 | "nop ; frstor %1", | ||
215 | "fxrstor %1", | ||
216 | X86_FEATURE_FXSR, | ||
217 | "m" (*fx)); | ||
218 | |||
219 | return 0; | ||
220 | } | 157 | } |
221 | 158 | ||
222 | static inline void fpu_fxsave(struct fpu *fpu) | 159 | static inline void fpu_fxsave(struct fpu *fpu) |
223 | { | 160 | { |
224 | asm volatile("fxsave %[fx]" | 161 | if (config_enabled(CONFIG_X86_32)) |
225 | : [fx] "=m" (fpu->state->fxsave)); | 162 | asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave)); |
163 | else if (config_enabled(CONFIG_AS_FXSAVEQ)) | ||
164 | asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave)); | ||
165 | else { | ||
166 | /* Using "rex64; fxsave %0" is broken because, if the memory | ||
167 | * operand uses any extended registers for addressing, a second | ||
168 | * REX prefix will be generated (to the assembler, rex64 | ||
169 | * followed by semicolon is a separate instruction), and hence | ||
170 | * the 64-bitness is lost. | ||
171 | * | ||
172 | * Using "fxsaveq %0" would be the ideal choice, but is only | ||
173 | * supported starting with gas 2.16. | ||
174 | * | ||
175 | * Using, as a workaround, the properly prefixed form below | ||
176 | * isn't accepted by any binutils version so far released, | ||
177 | * complaining that the same type of prefix is used twice if | ||
178 | * an extended register is needed for addressing (fix submitted | ||
179 | * to mainline 2005-11-21). | ||
180 | * | ||
181 | * asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave)); | ||
182 | * | ||
183 | * This, however, we can work around by forcing the compiler to | ||
184 | * select an addressing mode that doesn't require extended | ||
185 | * registers. | ||
186 | */ | ||
187 | asm volatile( "rex64/fxsave (%[fx])" | ||
188 | : "=m" (fpu->state->fxsave) | ||
189 | : [fx] "R" (&fpu->state->fxsave)); | ||
190 | } | ||
226 | } | 191 | } |
192 | #ifdef CONFIG_X86_64 | ||
193 | |||
194 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
195 | compat_sigset_t *set, struct pt_regs *regs); | ||
196 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
197 | compat_sigset_t *set, struct pt_regs *regs); | ||
198 | |||
199 | #else /* CONFIG_X86_32 */ | ||
227 | 200 | ||
228 | #define ia32_setup_frame __setup_frame | 201 | #define ia32_setup_frame __setup_frame |
229 | #define ia32_setup_rt_frame __setup_rt_frame | 202 | #define ia32_setup_rt_frame __setup_rt_frame |
@@ -272,17 +245,14 @@ static inline int __save_init_fpu(struct task_struct *tsk) | |||
272 | return fpu_save_init(&tsk->thread.fpu); | 245 | return fpu_save_init(&tsk->thread.fpu); |
273 | } | 246 | } |
274 | 247 | ||
275 | static inline int fpu_fxrstor_checking(struct fpu *fpu) | ||
276 | { | ||
277 | return fxrstor_checking(&fpu->state->fxsave); | ||
278 | } | ||
279 | |||
280 | static inline int fpu_restore_checking(struct fpu *fpu) | 248 | static inline int fpu_restore_checking(struct fpu *fpu) |
281 | { | 249 | { |
282 | if (use_xsave()) | 250 | if (use_xsave()) |
283 | return fpu_xrstor_checking(fpu); | 251 | return fpu_xrstor_checking(&fpu->state->xsave); |
252 | else if (use_fxsr()) | ||
253 | return fxrstor_checking(&fpu->state->fxsave); | ||
284 | else | 254 | else |
285 | return fpu_fxrstor_checking(fpu); | 255 | return frstor_checking(&fpu->state->fsave); |
286 | } | 256 | } |
287 | 257 | ||
288 | static inline int restore_fpu_checking(struct task_struct *tsk) | 258 | static inline int restore_fpu_checking(struct task_struct *tsk) |