mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-07-19 12:19:01 +02:00

So the handling of init_xstate_ctx has a layering violation: both 'struct xsave_struct' and 'union thread_xstate' have a 'struct i387_fxsave_struct' member: xsave_struct::i387 thread_xstate::fxsave The handling of init_xstate_ctx is generic, it is used on all CPUs, with or without XSAVE instruction. So it's confusing how the generic code passes around and handles an XSAVE specific format. What we really want is for init_xstate_ctx to be a proper fpstate and we use its ::fxsave and ::xsave members, as appropriate. Since the xsave_struct::i387 and thread_xstate::fxsave aliases each other this is not a functional problem. So implement this, and move init_xstate_ctx to the generic FPU code in the process. Also, since init_xstate_ctx is not XSAVE specific anymore, rename it to init_fpstate, and mark it __read_mostly, because it's only modified once during bootup, and used as a reference fpstate later on. There's no change in functionality. Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org>
241 lines
5.7 KiB
C
241 lines
5.7 KiB
C
#ifndef __ASM_X86_XSAVE_H
|
|
#define __ASM_X86_XSAVE_H
|
|
|
|
#include <linux/types.h>
|
|
#include <asm/processor.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
/* Bit 63 of XCR0 is reserved for future expansion */
|
|
#define XSTATE_EXTEND_MASK (~(XSTATE_FPSSE | (1ULL << 63)))
|
|
|
|
#define XSTATE_CPUID 0x0000000d
|
|
|
|
#define FXSAVE_SIZE 512
|
|
|
|
#define XSAVE_HDR_SIZE 64
|
|
#define XSAVE_HDR_OFFSET FXSAVE_SIZE
|
|
|
|
#define XSAVE_YMM_SIZE 256
|
|
#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
|
|
|
|
/* Supported features which support lazy state saving */
|
|
#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
|
|
| XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
|
|
|
|
/* Supported features which require eager state saving */
|
|
#define XSTATE_EAGER (XSTATE_BNDREGS | XSTATE_BNDCSR)
|
|
|
|
/* All currently supported features */
|
|
#define XCNTXT_MASK (XSTATE_LAZY | XSTATE_EAGER)
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#define REX_PREFIX "0x48, "
|
|
#else
|
|
#define REX_PREFIX
|
|
#endif
|
|
|
|
extern unsigned int xstate_size;
|
|
extern u64 xfeatures_mask;
|
|
extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
|
|
|
|
extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
|
|
|
|
/* These macros all use (%edi)/(%rdi) as the single memory argument. */
|
|
#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
|
|
#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
|
|
#define XSAVES ".byte " REX_PREFIX "0x0f,0xc7,0x2f"
|
|
#define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f"
|
|
#define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
|
|
|
|
#define xstate_fault ".section .fixup,\"ax\"\n" \
|
|
"3: movl $-1,%[err]\n" \
|
|
" jmp 2b\n" \
|
|
".previous\n" \
|
|
_ASM_EXTABLE(1b, 3b) \
|
|
: [err] "=r" (err)
|
|
|
|
/*
|
|
* This function is called only during boot time when x86 caps are not set
|
|
* up and alternative can not be used yet.
|
|
*/
|
|
static inline int xsave_state_booting(struct xsave_struct *fx)
|
|
{
|
|
u64 mask = -1;
|
|
u32 lmask = mask;
|
|
u32 hmask = mask >> 32;
|
|
int err = 0;
|
|
|
|
WARN_ON(system_state != SYSTEM_BOOTING);
|
|
|
|
if (boot_cpu_has(X86_FEATURE_XSAVES))
|
|
asm volatile("1:"XSAVES"\n\t"
|
|
"2:\n\t"
|
|
xstate_fault
|
|
: "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
|
|
: "memory");
|
|
else
|
|
asm volatile("1:"XSAVE"\n\t"
|
|
"2:\n\t"
|
|
xstate_fault
|
|
: "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
|
|
: "memory");
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* This function is called only during boot time when x86 caps are not set
|
|
* up and alternative can not be used yet.
|
|
*/
|
|
static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask)
|
|
{
|
|
u32 lmask = mask;
|
|
u32 hmask = mask >> 32;
|
|
int err = 0;
|
|
|
|
WARN_ON(system_state != SYSTEM_BOOTING);
|
|
|
|
if (boot_cpu_has(X86_FEATURE_XSAVES))
|
|
asm volatile("1:"XRSTORS"\n\t"
|
|
"2:\n\t"
|
|
xstate_fault
|
|
: "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
|
|
: "memory");
|
|
else
|
|
asm volatile("1:"XRSTOR"\n\t"
|
|
"2:\n\t"
|
|
xstate_fault
|
|
: "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
|
|
: "memory");
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Save processor xstate to xsave area.
|
|
*/
|
|
static inline int xsave_state(struct xsave_struct *fx)
|
|
{
|
|
u64 mask = -1;
|
|
u32 lmask = mask;
|
|
u32 hmask = mask >> 32;
|
|
int err = 0;
|
|
|
|
WARN_ON(!alternatives_patched);
|
|
|
|
/*
|
|
* If xsaves is enabled, xsaves replaces xsaveopt because
|
|
* it supports compact format and supervisor states in addition to
|
|
* modified optimization in xsaveopt.
|
|
*
|
|
* Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
|
|
* because xsaveopt supports modified optimization which is not
|
|
* supported by xsave.
|
|
*
|
|
* If none of xsaves and xsaveopt is enabled, use xsave.
|
|
*/
|
|
alternative_input_2(
|
|
"1:"XSAVE,
|
|
XSAVEOPT,
|
|
X86_FEATURE_XSAVEOPT,
|
|
XSAVES,
|
|
X86_FEATURE_XSAVES,
|
|
[fx] "D" (fx), "a" (lmask), "d" (hmask) :
|
|
"memory");
|
|
asm volatile("2:\n\t"
|
|
xstate_fault
|
|
: "0" (0)
|
|
: "memory");
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Restore processor xstate from xsave area.
|
|
*/
|
|
static inline int xrstor_state(struct xsave_struct *fx, u64 mask)
|
|
{
|
|
int err = 0;
|
|
u32 lmask = mask;
|
|
u32 hmask = mask >> 32;
|
|
|
|
/*
|
|
* Use xrstors to restore context if it is enabled. xrstors supports
|
|
* compacted format of xsave area which is not supported by xrstor.
|
|
*/
|
|
alternative_input(
|
|
"1: " XRSTOR,
|
|
XRSTORS,
|
|
X86_FEATURE_XSAVES,
|
|
"D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
|
|
: "memory");
|
|
|
|
asm volatile("2:\n"
|
|
xstate_fault
|
|
: "0" (0)
|
|
: "memory");
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Restore xstate context for new process during context switch.
|
|
*/
|
|
static inline int fpu_xrstor_checking(struct xsave_struct *fx)
|
|
{
|
|
return xrstor_state(fx, -1);
|
|
}
|
|
|
|
/*
|
|
* Save xstate to user space xsave area.
|
|
*
|
|
* We don't use modified optimization because xrstor/xrstors might track
|
|
* a different application.
|
|
*
|
|
* We don't use compacted format xsave area for
|
|
* backward compatibility for old applications which don't understand
|
|
* compacted format of xsave area.
|
|
*/
|
|
static inline int xsave_user(struct xsave_struct __user *buf)
|
|
{
|
|
int err;
|
|
|
|
/*
|
|
* Clear the xsave header first, so that reserved fields are
|
|
* initialized to zero.
|
|
*/
|
|
err = __clear_user(&buf->header, sizeof(buf->header));
|
|
if (unlikely(err))
|
|
return -EFAULT;
|
|
|
|
__asm__ __volatile__(ASM_STAC "\n"
|
|
"1:"XSAVE"\n"
|
|
"2: " ASM_CLAC "\n"
|
|
xstate_fault
|
|
: "D" (buf), "a" (-1), "d" (-1), "0" (0)
|
|
: "memory");
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Restore xstate from user space xsave area.
|
|
*/
|
|
static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
|
|
{
|
|
int err = 0;
|
|
struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
|
|
u32 lmask = mask;
|
|
u32 hmask = mask >> 32;
|
|
|
|
__asm__ __volatile__(ASM_STAC "\n"
|
|
"1:"XRSTOR"\n"
|
|
"2: " ASM_CLAC "\n"
|
|
xstate_fault
|
|
: "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
|
|
: "memory"); /* memory required? */
|
|
return err;
|
|
}
|
|
|
|
void *get_xsave_addr(struct xsave_struct *xsave, int xstate);
|
|
void setup_xstate_comp(void);
|
|
|
|
#endif
|