aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/fpu-internal.h
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2012-07-24 19:05:28 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2012-09-18 18:51:26 -0400
commit0ca5bd0d886578ad0afeceaa83458c0f35cb3c6b (patch)
tree97c8e2c62d1be5fd66c2a6da28d439255bd37ed1 /arch/x86/include/asm/fpu-internal.h
parent050902c011712ad4703038fa4489ec4edd87d396 (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.h184
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...) \
101static 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)); 115static 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
130static inline int fxsave_user(struct i387_fxsave_struct __user *fx) 120static 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
172static inline void fpu_fxsave(struct fpu *fpu) 142static 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
199int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 154static inline int frstor_checking(struct i387_fsave_struct *fx)
200 compat_sigset_t *set, struct pt_regs *regs);
201int 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 */
207static 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
222static inline void fpu_fxsave(struct fpu *fpu) 159static 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
194int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
195 compat_sigset_t *set, struct pt_regs *regs);
196int 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
275static inline int fpu_fxrstor_checking(struct fpu *fpu)
276{
277 return fxrstor_checking(&fpu->state->fxsave);
278}
279
280static inline int fpu_restore_checking(struct fpu *fpu) 248static 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
288static inline int restore_fpu_checking(struct task_struct *tsk) 258static inline int restore_fpu_checking(struct task_struct *tsk)