aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-07-29 20:23:16 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-30 13:50:35 -0400
commit6152e4b1c99a3689fc318d092cd144597f7dbd14 (patch)
tree8d0590b7ea931da237d037db1bbff5aa0bf1ef34 /arch/x86/kernel
parentb4a091a62c8e91d6077e575600363cff73fa02ef (diff)
x86, xsave: keep the XSAVE feature mask as an u64
The XSAVE feature mask is a 64-bit number; keep it that way, in order to avoid the mistake done with rdmsr/wrmsr. Use the xsetbv() function provided in the previous patch. Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/i387.c12
-rw-r--r--arch/x86/kernel/xsave.c45
2 files changed, 22 insertions, 35 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}