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>
This commit is contained in:
Suresh Siddha 2012-07-24 16:05:28 -07:00 committed by H. Peter Anvin
parent 050902c011
commit 0ca5bd0d88
3 changed files with 80 additions and 112 deletions

View file

@ -97,34 +97,24 @@ static inline void sanitize_i387_state(struct task_struct *tsk)
__sanitize_i387_state(tsk); __sanitize_i387_state(tsk);
} }
#ifdef CONFIG_X86_64 #define check_insn(insn, output, input...) \
static inline int fxrstor_checking(struct i387_fxsave_struct *fx) ({ \
{ int err; \
int err; asm volatile("1:" #insn "\n\t" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movl $-1,%[err]\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE(1b, 3b) \
: [err] "=r" (err), output \
: "0"(0), input); \
err; \
})
/* See comment in fxsave() below. */ static inline int fsave_user(struct i387_fsave_struct __user *fx)
#ifdef CONFIG_AS_FXSAVEQ {
asm volatile("1: fxrstorq %[fx]\n\t" return check_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
"2:\n"
".section .fixup,\"ax\"\n"
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
_ASM_EXTABLE(1b, 3b)
: [err] "=r" (err)
: [fx] "m" (*fx), "0" (0));
#else
asm volatile("1: rex64/fxrstor (%[fx])\n\t"
"2:\n"
".section .fixup,\"ax\"\n"
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
_ASM_EXTABLE(1b, 3b)
: [err] "=r" (err)
: [fx] "R" (fx), "m" (*fx), "0" (0));
#endif
return err;
} }
static inline int fxsave_user(struct i387_fxsave_struct __user *fx) static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
@ -140,61 +130,66 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
if (unlikely(err)) if (unlikely(err))
return -EFAULT; return -EFAULT;
/* See comment in fxsave() below. */ if (config_enabled(CONFIG_X86_32))
#ifdef CONFIG_AS_FXSAVEQ return check_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
asm volatile("1: fxsaveq %[fx]\n\t" else if (config_enabled(CONFIG_AS_FXSAVEQ))
"2:\n" return check_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
".section .fixup,\"ax\"\n"
"3: movl $-1,%[err]\n" /* See comment in fpu_fxsave() below. */
" jmp 2b\n" return check_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx));
".previous\n" }
_ASM_EXTABLE(1b, 3b)
: [err] "=r" (err), [fx] "=m" (*fx) static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
: "0" (0)); {
#else if (config_enabled(CONFIG_X86_32))
asm volatile("1: rex64/fxsave (%[fx])\n\t" return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
"2:\n" else if (config_enabled(CONFIG_AS_FXSAVEQ))
".section .fixup,\"ax\"\n" return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
"3: movl $-1,%[err]\n"
" jmp 2b\n" /* See comment in fpu_fxsave() below. */
".previous\n" return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
_ASM_EXTABLE(1b, 3b) "m" (*fx));
: [err] "=r" (err), "=m" (*fx) }
: [fx] "R" (fx), "0" (0));
#endif static inline int frstor_checking(struct i387_fsave_struct *fx)
if (unlikely(err) && {
__clear_user(fx, sizeof(struct i387_fxsave_struct))) return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
err = -EFAULT;
/* No need to clear here because the caller clears USED_MATH */
return err;
} }
static inline void fpu_fxsave(struct fpu *fpu) static inline void fpu_fxsave(struct fpu *fpu)
{ {
/* Using "rex64; fxsave %0" is broken because, if the memory operand if (config_enabled(CONFIG_X86_32))
uses any extended registers for addressing, a second REX prefix asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave));
will be generated (to the assembler, rex64 followed by semicolon else if (config_enabled(CONFIG_AS_FXSAVEQ))
is a separate instruction), and hence the 64-bitness is lost. */ asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave));
else {
#ifdef CONFIG_AS_FXSAVEQ /* Using "rex64; fxsave %0" is broken because, if the memory
/* Using "fxsaveq %0" would be the ideal choice, but is only supported * operand uses any extended registers for addressing, a second
starting with gas 2.16. */ * REX prefix will be generated (to the assembler, rex64
__asm__ __volatile__("fxsaveq %0" * followed by semicolon is a separate instruction), and hence
: "=m" (fpu->state->fxsave)); * the 64-bitness is lost.
#else *
/* Using, as a workaround, the properly prefixed form below isn't * Using "fxsaveq %0" would be the ideal choice, but is only
accepted by any binutils version so far released, complaining that * supported starting with gas 2.16.
the same type of prefix is used twice if an extended register is *
needed for addressing (fix submitted to mainline 2005-11-21). * Using, as a workaround, the properly prefixed form below
asm volatile("rex64/fxsave %0" * isn't accepted by any binutils version so far released,
: "=m" (fpu->state->fxsave)); * complaining that the same type of prefix is used twice if
This, however, we can work around by forcing the compiler to select * an extended register is needed for addressing (fix submitted
an addressing mode that doesn't require extended registers. */ * to mainline 2005-11-21).
asm volatile("rex64/fxsave (%[fx])" *
: "=m" (fpu->state->fxsave) * asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave));
: [fx] "R" (&fpu->state->fxsave)); *
#endif * This, however, we can work around by forcing the compiler to
* select an addressing mode that doesn't require extended
* registers.
*/
asm volatile( "rex64/fxsave (%[fx])"
: "=m" (fpu->state->fxsave)
: [fx] "R" (&fpu->state->fxsave));
}
} }
#ifdef CONFIG_X86_64
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
compat_sigset_t *set, struct pt_regs *regs); compat_sigset_t *set, struct pt_regs *regs);
@ -203,28 +198,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
#else /* CONFIG_X86_32 */ #else /* CONFIG_X86_32 */
/* perform fxrstor iff the processor has extended states, otherwise frstor */
static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
{
/*
* The "nop" is needed to make the instructions the same
* length.
*/
alternative_input(
"nop ; frstor %1",
"fxrstor %1",
X86_FEATURE_FXSR,
"m" (*fx));
return 0;
}
static inline void fpu_fxsave(struct fpu *fpu)
{
asm volatile("fxsave %[fx]"
: [fx] "=m" (fpu->state->fxsave));
}
#define ia32_setup_frame __setup_frame #define ia32_setup_frame __setup_frame
#define ia32_setup_rt_frame __setup_rt_frame #define ia32_setup_rt_frame __setup_rt_frame
@ -272,17 +245,14 @@ static inline int __save_init_fpu(struct task_struct *tsk)
return fpu_save_init(&tsk->thread.fpu); return fpu_save_init(&tsk->thread.fpu);
} }
static inline int fpu_fxrstor_checking(struct fpu *fpu)
{
return fxrstor_checking(&fpu->state->fxsave);
}
static inline int fpu_restore_checking(struct fpu *fpu) static inline int fpu_restore_checking(struct fpu *fpu)
{ {
if (use_xsave()) if (use_xsave())
return fpu_xrstor_checking(fpu); return fpu_xrstor_checking(&fpu->state->xsave);
else if (use_fxsr())
return fxrstor_checking(&fpu->state->fxsave);
else else
return fpu_fxrstor_checking(fpu); return frstor_checking(&fpu->state->fsave);
} }
static inline int restore_fpu_checking(struct task_struct *tsk) static inline int restore_fpu_checking(struct task_struct *tsk)

View file

@ -42,9 +42,8 @@ extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
void __user *fpstate, void __user *fpstate,
struct _fpx_sw_bytes *sw); struct _fpx_sw_bytes *sw);
static inline int fpu_xrstor_checking(struct fpu *fpu) static inline int fpu_xrstor_checking(struct xsave_struct *fx)
{ {
struct xsave_struct *fx = &fpu->state->xsave;
int err; int err;
asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
@ -84,9 +83,6 @@ static inline int xsave_user(struct xsave_struct __user *buf)
: [err] "=r" (err) : [err] "=r" (err)
: "D" (buf), "a" (-1), "d" (-1), "0" (0) : "D" (buf), "a" (-1), "d" (-1), "0" (0)
: "memory"); : "memory");
if (unlikely(err) && __clear_user(buf, xstate_size))
err = -EFAULT;
/* No need to clear here because the caller clears USED_MATH */
return err; return err;
} }

View file

@ -176,8 +176,10 @@ int save_i387_xstate(void __user *buf)
else else
err = fxsave_user(buf); err = fxsave_user(buf);
if (err) if (unlikely(err)) {
__clear_user(buf, xstate_size);
return err; return err;
}
user_fpu_end(); user_fpu_end();
} else { } else {
sanitize_i387_state(tsk); sanitize_i387_state(tsk);