aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/i387.c12
-rw-r--r--arch/x86/kernel/xsave.c45
-rw-r--r--include/asm-x86/xsave.h18
3 files changed, 33 insertions, 42 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index e0ed59f5c19f..45723f1fe198 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -552,18 +552,17 @@ static int restore_i387_xsave(void __user *buf)
552 (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0]; 552 (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
553 struct xsave_hdr_struct *xsave_hdr = 553 struct xsave_hdr_struct *xsave_hdr =
554 &current->thread.xstate->xsave.xsave_hdr; 554 &current->thread.xstate->xsave.xsave_hdr;
555 unsigned int lmask, hmask; 555 u64 mask;
556 int err; 556 int err;
557 557
558 if (check_for_xstate(fx, buf, &fx_sw_user)) 558 if (check_for_xstate(fx, buf, &fx_sw_user))
559 goto fx_only; 559 goto fx_only;
560 560
561 lmask = fx_sw_user.xstate_bv; 561 mask = fx_sw_user.xstate_bv;
562 hmask = fx_sw_user.xstate_bv >> 32;
563 562
564 err = restore_i387_fxsave(buf, fx_sw_user.xstate_size); 563 err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
565 564
566 xsave_hdr->xstate_bv &= (pcntxt_lmask | (((u64) pcntxt_hmask) << 32)); 565 xsave_hdr->xstate_bv &= pcntxt_mask;
567 /* 566 /*
568 * These bits must be zero. 567 * These bits must be zero.
569 */ 568 */
@@ -573,9 +572,8 @@ static int restore_i387_xsave(void __user *buf)
573 * Init the state that is not present in the memory layout 572 * Init the state that is not present in the memory layout
574 * and enabled by the OS. 573 * and enabled by the OS.
575 */ 574 */
576 lmask = ~(pcntxt_lmask & ~lmask); 575 mask = ~(pcntxt_mask & ~mask);
577 hmask = ~(pcntxt_hmask & ~hmask); 576 xsave_hdr->xstate_bv &= mask;
578 xsave_hdr->xstate_bv &= (lmask | (((u64) hmask) << 32));
579 577
580 return err; 578 return err;
581fx_only: 579fx_only:
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index dd66d0714c18..7415f3e38a51 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -9,11 +9,12 @@
9#ifdef CONFIG_IA32_EMULATION 9#ifdef CONFIG_IA32_EMULATION
10#include <asm/sigcontext32.h> 10#include <asm/sigcontext32.h>
11#endif 11#endif
12#include <asm/xcr.h>
12 13
13/* 14/*
14 * Supported feature mask by the CPU and the kernel. 15 * Supported feature mask by the CPU and the kernel.
15 */ 16 */
16unsigned int pcntxt_hmask, pcntxt_lmask; 17u64 pcntxt_mask;
17 18
18struct _fpx_sw_bytes fx_sw_reserved; 19struct _fpx_sw_bytes fx_sw_reserved;
19#ifdef CONFIG_IA32_EMULATION 20#ifdef CONFIG_IA32_EMULATION
@@ -127,30 +128,28 @@ int save_i387_xstate(void __user *buf)
127int restore_user_xstate(void __user *buf) 128int restore_user_xstate(void __user *buf)
128{ 129{
129 struct _fpx_sw_bytes fx_sw_user; 130 struct _fpx_sw_bytes fx_sw_user;
130 unsigned int lmask, hmask; 131 u64 mask;
131 int err; 132 int err;
132 133
133 if (((unsigned long)buf % 64) || 134 if (((unsigned long)buf % 64) ||
134 check_for_xstate(buf, buf, &fx_sw_user)) 135 check_for_xstate(buf, buf, &fx_sw_user))
135 goto fx_only; 136 goto fx_only;
136 137
137 lmask = fx_sw_user.xstate_bv; 138 mask = fx_sw_user.xstate_bv;
138 hmask = fx_sw_user.xstate_bv >> 32;
139 139
140 /* 140 /*
141 * restore the state passed by the user. 141 * restore the state passed by the user.
142 */ 142 */
143 err = xrestore_user(buf, lmask, hmask); 143 err = xrestore_user(buf, mask);
144 if (err) 144 if (err)
145 return err; 145 return err;
146 146
147 /* 147 /*
148 * init the state skipped by the user. 148 * init the state skipped by the user.
149 */ 149 */
150 lmask = pcntxt_lmask & ~lmask; 150 mask = pcntxt_mask & ~mask;
151 hmask = pcntxt_hmask & ~hmask;
152 151
153 xrstor_state(init_xstate_buf, lmask, hmask); 152 xrstor_state(init_xstate_buf, mask);
154 153
155 return 0; 154 return 0;
156 155
@@ -160,8 +159,7 @@ fx_only:
160 * memory layout. Restore just the FP/SSE and init all 159 * memory layout. Restore just the FP/SSE and init all
161 * the other extended state. 160 * the other extended state.
162 */ 161 */
163 xrstor_state(init_xstate_buf, pcntxt_lmask & ~XSTATE_FPSSE, 162 xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
164 pcntxt_hmask);
165 return fxrstor_checking((__force struct i387_fxsave_struct *)buf); 163 return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
166} 164}
167 165
@@ -231,8 +229,7 @@ void prepare_fx_sw_frame(void)
231 229
232 fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; 230 fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
233 fx_sw_reserved.extended_size = sig_xstate_size; 231 fx_sw_reserved.extended_size = sig_xstate_size;
234 fx_sw_reserved.xstate_bv = pcntxt_lmask | 232 fx_sw_reserved.xstate_bv = pcntxt_mask;
235 (((u64) (pcntxt_hmask)) << 32);
236 fx_sw_reserved.xstate_size = xstate_size; 233 fx_sw_reserved.xstate_size = xstate_size;
237#ifdef CONFIG_IA32_EMULATION 234#ifdef CONFIG_IA32_EMULATION
238 memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved, 235 memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
@@ -263,11 +260,8 @@ void __cpuinit xsave_init(void)
263 /* 260 /*
264 * Enable all the features that the HW is capable of 261 * Enable all the features that the HW is capable of
265 * and the Linux kernel is aware of. 262 * and the Linux kernel is aware of.
266 *
267 * xsetbv();
268 */ 263 */
269 asm volatile(".byte 0x0f,0x01,0xd1" : : "c" (0), 264 xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
270 "a" (pcntxt_lmask), "d" (pcntxt_hmask));
271} 265}
272 266
273/* 267/*
@@ -287,36 +281,31 @@ void __init xsave_cntxt_init(void)
287 unsigned int eax, ebx, ecx, edx; 281 unsigned int eax, ebx, ecx, edx;
288 282
289 cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); 283 cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
284 pcntxt_mask = eax + ((u64)edx << 32);
290 285
291 pcntxt_lmask = eax; 286 if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
292 pcntxt_hmask = edx; 287 printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
293 288 pcntxt_mask);
294 if ((pcntxt_lmask & XSTATE_FPSSE) != XSTATE_FPSSE) {
295 printk(KERN_ERR "FP/SSE not shown under xsave features %x\n",
296 pcntxt_lmask);
297 BUG(); 289 BUG();
298 } 290 }
299 291
300 /* 292 /*
301 * for now OS knows only about FP/SSE 293 * for now OS knows only about FP/SSE
302 */ 294 */
303 pcntxt_lmask = pcntxt_lmask & XCNTXT_LMASK; 295 pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
304 pcntxt_hmask = pcntxt_hmask & XCNTXT_HMASK;
305
306 xsave_init(); 296 xsave_init();
307 297
308 /* 298 /*
309 * Recompute the context size for enabled features 299 * Recompute the context size for enabled features
310 */ 300 */
311 cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); 301 cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
312
313 xstate_size = ebx; 302 xstate_size = ebx;
314 303
315 prepare_fx_sw_frame(); 304 prepare_fx_sw_frame();
316 305
317 setup_xstate_init(); 306 setup_xstate_init();
318 307
319 printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, " 308 printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
320 "cntxt size 0x%x\n", 309 "cntxt size 0x%x\n",
321 (pcntxt_lmask | ((u64) pcntxt_hmask << 32)), xstate_size); 310 pcntxt_mask, xstate_size);
322} 311}
diff --git a/include/asm-x86/xsave.h b/include/asm-x86/xsave.h
index b7f64b9fcd94..08e9a1ac07a9 100644
--- a/include/asm-x86/xsave.h
+++ b/include/asm-x86/xsave.h
@@ -1,6 +1,7 @@
1#ifndef __ASM_X86_XSAVE_H 1#ifndef __ASM_X86_XSAVE_H
2#define __ASM_X86_XSAVE_H 2#define __ASM_X86_XSAVE_H
3 3
4#include <linux/types.h>
4#include <asm/processor.h> 5#include <asm/processor.h>
5#include <asm/i387.h> 6#include <asm/i387.h>
6 7
@@ -14,8 +15,7 @@
14/* 15/*
15 * These are the features that the OS can handle currently. 16 * These are the features that the OS can handle currently.
16 */ 17 */
17#define XCNTXT_LMASK (XSTATE_FP | XSTATE_SSE) 18#define XCNTXT_MASK (XSTATE_FP | XSTATE_SSE)
18#define XCNTXT_HMASK 0x0
19 19
20#ifdef CONFIG_X86_64 20#ifdef CONFIG_X86_64
21#define REX_PREFIX "0x48, " 21#define REX_PREFIX "0x48, "
@@ -23,7 +23,8 @@
23#define REX_PREFIX 23#define REX_PREFIX
24#endif 24#endif
25 25
26extern unsigned int xstate_size, pcntxt_hmask, pcntxt_lmask; 26extern unsigned int xstate_size;
27extern u64 pcntxt_mask;
27extern struct xsave_struct *init_xstate_buf; 28extern struct xsave_struct *init_xstate_buf;
28 29
29extern void xsave_cntxt_init(void); 30extern void xsave_cntxt_init(void);
@@ -73,12 +74,12 @@ static inline int xsave_user(struct xsave_struct __user *buf)
73 return err; 74 return err;
74} 75}
75 76
76static inline int xrestore_user(struct xsave_struct __user *buf, 77static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
77 unsigned int lmask,
78 unsigned int hmask)
79{ 78{
80 int err; 79 int err;
81 struct xsave_struct *xstate = ((__force struct xsave_struct *)buf); 80 struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
81 u32 lmask = mask;
82 u32 hmask = mask >> 32;
82 83
83 __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n" 84 __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
84 "2:\n" 85 "2:\n"
@@ -96,8 +97,11 @@ static inline int xrestore_user(struct xsave_struct __user *buf,
96 return err; 97 return err;
97} 98}
98 99
99static inline void xrstor_state(struct xsave_struct *fx, int lmask, int hmask) 100static inline void xrstor_state(struct xsave_struct *fx, u64 mask)
100{ 101{
102 u32 lmask = mask;
103 u32 hmask = mask >> 32;
104
101 asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" 105 asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
102 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) 106 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
103 : "memory"); 107 : "memory");