diff options
-rw-r--r-- | arch/x86/kernel/i387.c | 12 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 45 | ||||
-rw-r--r-- | include/asm-x86/xsave.h | 18 |
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 | ¤t->thread.xstate->xsave.xsave_hdr; | 554 | ¤t->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; |
581 | fx_only: | 579 | fx_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 | */ |
16 | unsigned int pcntxt_hmask, pcntxt_lmask; | 17 | u64 pcntxt_mask; |
17 | 18 | ||
18 | struct _fpx_sw_bytes fx_sw_reserved; | 19 | struct _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) | |||
127 | int restore_user_xstate(void __user *buf) | 128 | int 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 | ||
26 | extern unsigned int xstate_size, pcntxt_hmask, pcntxt_lmask; | 26 | extern unsigned int xstate_size; |
27 | extern u64 pcntxt_mask; | ||
27 | extern struct xsave_struct *init_xstate_buf; | 28 | extern struct xsave_struct *init_xstate_buf; |
28 | 29 | ||
29 | extern void xsave_cntxt_init(void); | 30 | extern 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 | ||
76 | static inline int xrestore_user(struct xsave_struct __user *buf, | 77 | static 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 | ||
99 | static inline void xrstor_state(struct xsave_struct *fx, int lmask, int hmask) | 100 | static 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"); |