112 lines
2.8 KiB
C
112 lines
2.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __X86_KERNEL_FPU_LEGACY_H
|
|
#define __X86_KERNEL_FPU_LEGACY_H
|
|
|
|
#include <asm/fpu/types.h>
|
|
|
|
extern unsigned int mxcsr_feature_mask;
|
|
|
|
static inline void ldmxcsr(u32 mxcsr)
|
|
{
|
|
asm volatile("ldmxcsr %0" :: "m" (mxcsr));
|
|
}
|
|
|
|
/*
|
|
* Returns 0 on success or the trap number when the operation raises an
|
|
* exception.
|
|
*/
|
|
#define user_insn(insn, output, input...) \
|
|
({ \
|
|
int err; \
|
|
\
|
|
might_fault(); \
|
|
\
|
|
asm volatile(ASM_STAC "\n" \
|
|
"1: " #insn "\n" \
|
|
"2: " ASM_CLAC "\n" \
|
|
_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_MCE_SAFE) \
|
|
: [err] "=a" (err), output \
|
|
: "0"(0), input); \
|
|
err; \
|
|
})
|
|
|
|
#define kernel_insn_err(insn, output, input...) \
|
|
({ \
|
|
int err; \
|
|
asm volatile("1:" #insn "\n\t" \
|
|
"2:\n" \
|
|
_ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %[err]) \
|
|
: [err] "=r" (err), output \
|
|
: "0"(0), input); \
|
|
err; \
|
|
})
|
|
|
|
#define kernel_insn(insn, output, input...) \
|
|
asm volatile("1:" #insn "\n\t" \
|
|
"2:\n" \
|
|
_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FPU_RESTORE) \
|
|
: output : input)
|
|
|
|
static inline int fnsave_to_user_sigframe(struct fregs_state __user *fx)
|
|
{
|
|
return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
|
|
}
|
|
|
|
static inline int fxsave_to_user_sigframe(struct fxregs_state __user *fx)
|
|
{
|
|
if (IS_ENABLED(CONFIG_X86_32))
|
|
return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
|
|
else
|
|
return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
|
|
|
|
}
|
|
|
|
static inline void fxrstor(struct fxregs_state *fx)
|
|
{
|
|
if (IS_ENABLED(CONFIG_X86_32))
|
|
kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
else
|
|
kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
}
|
|
|
|
static inline int fxrstor_safe(struct fxregs_state *fx)
|
|
{
|
|
if (IS_ENABLED(CONFIG_X86_32))
|
|
return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
else
|
|
return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
}
|
|
|
|
static inline int fxrstor_from_user_sigframe(struct fxregs_state __user *fx)
|
|
{
|
|
if (IS_ENABLED(CONFIG_X86_32))
|
|
return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
else
|
|
return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
}
|
|
|
|
static inline void frstor(struct fregs_state *fx)
|
|
{
|
|
kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
}
|
|
|
|
static inline int frstor_safe(struct fregs_state *fx)
|
|
{
|
|
return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
}
|
|
|
|
static inline int frstor_from_user_sigframe(struct fregs_state __user *fx)
|
|
{
|
|
return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
|
}
|
|
|
|
static inline void fxsave(struct fxregs_state *fx)
|
|
{
|
|
if (IS_ENABLED(CONFIG_X86_32))
|
|
asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
|
|
else
|
|
asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
|
|
}
|
|
|
|
#endif
|