diff options
Diffstat (limited to 'arch/x86/include/asm/xsave.h')
-rw-r--r-- | arch/x86/include/asm/xsave.h | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h index 32c36668fa7b..c6ce2452f10c 100644 --- a/arch/x86/include/asm/xsave.h +++ b/arch/x86/include/asm/xsave.h | |||
@@ -3,7 +3,8 @@ | |||
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <asm/processor.h> | 5 | #include <asm/processor.h> |
6 | #include <asm/i387.h> | 6 | |
7 | #define XSTATE_CPUID 0x0000000d | ||
7 | 8 | ||
8 | #define XSTATE_FP 0x1 | 9 | #define XSTATE_FP 0x1 |
9 | #define XSTATE_SSE 0x2 | 10 | #define XSTATE_SSE 0x2 |
@@ -32,10 +33,8 @@ | |||
32 | 33 | ||
33 | extern unsigned int xstate_size; | 34 | extern unsigned int xstate_size; |
34 | extern u64 pcntxt_mask; | 35 | extern u64 pcntxt_mask; |
35 | extern struct xsave_struct *init_xstate_buf; | ||
36 | extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; | 36 | extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; |
37 | 37 | ||
38 | extern void xsave_cntxt_init(void); | ||
39 | extern void xsave_init(void); | 38 | extern void xsave_init(void); |
40 | extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); | 39 | extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); |
41 | extern int init_fpu(struct task_struct *child); | 40 | extern int init_fpu(struct task_struct *child); |
@@ -65,6 +64,16 @@ static inline int fpu_xrstor_checking(struct fpu *fpu) | |||
65 | static inline int xsave_user(struct xsave_struct __user *buf) | 64 | static inline int xsave_user(struct xsave_struct __user *buf) |
66 | { | 65 | { |
67 | int err; | 66 | int err; |
67 | |||
68 | /* | ||
69 | * Clear the xsave header first, so that reserved fields are | ||
70 | * initialized to zero. | ||
71 | */ | ||
72 | err = __clear_user(&buf->xsave_hdr, | ||
73 | sizeof(struct xsave_hdr_struct)); | ||
74 | if (unlikely(err)) | ||
75 | return -EFAULT; | ||
76 | |||
68 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" | 77 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" |
69 | "2:\n" | 78 | "2:\n" |
70 | ".section .fixup,\"ax\"\n" | 79 | ".section .fixup,\"ax\"\n" |
@@ -117,12 +126,25 @@ static inline void xrstor_state(struct xsave_struct *fx, u64 mask) | |||
117 | : "memory"); | 126 | : "memory"); |
118 | } | 127 | } |
119 | 128 | ||
129 | static inline void xsave_state(struct xsave_struct *fx, u64 mask) | ||
130 | { | ||
131 | u32 lmask = mask; | ||
132 | u32 hmask = mask >> 32; | ||
133 | |||
134 | asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x27\n\t" | ||
135 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
136 | : "memory"); | ||
137 | } | ||
138 | |||
120 | static inline void fpu_xsave(struct fpu *fpu) | 139 | static inline void fpu_xsave(struct fpu *fpu) |
121 | { | 140 | { |
122 | /* This, however, we can work around by forcing the compiler to select | 141 | /* This, however, we can work around by forcing the compiler to select |
123 | an addressing mode that doesn't require extended registers. */ | 142 | an addressing mode that doesn't require extended registers. */ |
124 | __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27" | 143 | alternative_input( |
125 | : : "D" (&(fpu->state->xsave)), | 144 | ".byte " REX_PREFIX "0x0f,0xae,0x27", |
126 | "a" (-1), "d"(-1) : "memory"); | 145 | ".byte " REX_PREFIX "0x0f,0xae,0x37", |
146 | X86_FEATURE_XSAVEOPT, | ||
147 | [fx] "D" (&fpu->state->xsave), "a" (-1), "d" (-1) : | ||
148 | "memory"); | ||
127 | } | 149 | } |
128 | #endif | 150 | #endif |