xsave.h 3.0 KB
Newer Older
1 2 3
#ifndef __ASM_X86_XSAVE_H
#define __ASM_X86_XSAVE_H

4
#include <linux/types.h>
5 6 7 8 9
#include <asm/processor.h>
#include <asm/i387.h>

#define XSTATE_FP	0x1
#define XSTATE_SSE	0x2
10
#define XSTATE_YMM	0x4
11 12 13 14 15 16 17 18

#define XSTATE_FPSSE	(XSTATE_FP | XSTATE_SSE)

#define FXSAVE_SIZE	512

/*
 * These are the features that the OS can handle currently.
 */
19
#define XCNTXT_MASK	(XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
20

21 22 23 24 25 26
#ifdef CONFIG_X86_64
#define REX_PREFIX	"0x48, "
#else
#define REX_PREFIX
#endif

27 28
extern unsigned int xstate_size;
extern u64 pcntxt_mask;
29 30 31 32
extern struct xsave_struct *init_xstate_buf;

extern void xsave_cntxt_init(void);
extern void xsave_init(void);
33
extern int init_fpu(struct task_struct *child);
34 35 36
extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
			    void __user *fpstate,
			    struct _fpx_sw_bytes *sw);
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

static inline int xrstor_checking(struct xsave_struct *fx)
{
	int err;

	asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\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)
		     : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0)
		     : "memory");

	return err;
}

56
static inline int xsave_user(struct xsave_struct __user *buf)
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
{
	int err;
	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
			     "2:\n"
			     ".section .fixup,\"ax\"\n"
			     "3:  movl $-1,%[err]\n"
			     "    jmp  2b\n"
			     ".previous\n"
			     ".section __ex_table,\"a\"\n"
			     _ASM_ALIGN "\n"
			     _ASM_PTR "1b,3b\n"
			     ".previous"
			     : [err] "=r" (err)
			     : "D" (buf), "a" (-1), "d" (-1), "0" (0)
			     : "memory");
	if (unlikely(err) && __clear_user(buf, xstate_size))
		err = -EFAULT;
	/* No need to clear here because the caller clears USED_MATH */
	return err;
}

78
static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
79 80 81
{
	int err;
	struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
82 83
	u32 lmask = mask;
	u32 hmask = mask >> 32;
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
			     "2:\n"
			     ".section .fixup,\"ax\"\n"
			     "3:  movl $-1,%[err]\n"
			     "    jmp  2b\n"
			     ".previous\n"
			     ".section __ex_table,\"a\"\n"
			     _ASM_ALIGN "\n"
			     _ASM_PTR "1b,3b\n"
			     ".previous"
			     : [err] "=r" (err)
			     : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
			     : "memory");	/* memory required? */
	return err;
}

101
static inline void xrstor_state(struct xsave_struct *fx, u64 mask)
102
{
103 104 105
	u32 lmask = mask;
	u32 hmask = mask >> 32;

106 107 108 109 110
	asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
		     : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
		     :   "memory");
}

111 112 113 114 115 116 117 118
static inline void xsave(struct task_struct *tsk)
{
	/* This, however, we can work around by forcing the compiler to select
	   an addressing mode that doesn't require extended registers. */
	__asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27"
			     : : "D" (&(tsk->thread.xstate->xsave)),
				 "a" (-1), "d"(-1) : "memory");
}
119
#endif