diff options
author | Yu-cheng Yu <yu-cheng.yu@intel.com> | 2016-06-17 16:07:16 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-07-10 11:12:10 -0400 |
commit | 1499ce2dd45afddea2e84f9f920890cf88384c4e (patch) | |
tree | 7e16a59bacb5752087ea420debf041c84f92e991 | |
parent | 03482e08a87d24e5c8c23e6981c482e832cf3bdc (diff) |
x86/fpu/xstate: Fix supervisor xstate component offset
CPUID function 0x0d, sub function (i, i > 1) returns in ebx the offset of
xstate component i. Zero is returned for a supervisor state. A supervisor
state can only be saved by XSAVES and XSAVES uses a compacted format.
There is no fixed offset for a supervisor state. This patch checks and
makes sure a supervisor state offset is not recorded or mis-used. This has
no effect in practice as we currently use no supervisor states, but it
would be good to fix.
Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Cc: Ravi V. Shankar <ravi.v.shankar@intel.com>
Cc: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/81b29e40d35d4cec9f2511a856fe769f34935a3f.1466179491.git.yu-cheng.yu@intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/fpu/types.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/fpu/xstate.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/xstate.c | 62 |
3 files changed, 43 insertions, 23 deletions
diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h index 36b90bbfc69f..12dd648735b6 100644 --- a/arch/x86/include/asm/fpu/types.h +++ b/arch/x86/include/asm/fpu/types.h | |||
@@ -122,6 +122,7 @@ enum xfeature { | |||
122 | #define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK) | 122 | #define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK) |
123 | #define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256) | 123 | #define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256) |
124 | #define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM) | 124 | #define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM) |
125 | #define XFEATURE_MASK_PT (1 << XFEATURE_PT_UNIMPLEMENTED_SO_FAR) | ||
125 | #define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU) | 126 | #define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU) |
126 | 127 | ||
127 | #define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE) | 128 | #define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE) |
diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index d812cf361282..92f376ccc999 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h | |||
@@ -18,6 +18,9 @@ | |||
18 | #define XSAVE_YMM_SIZE 256 | 18 | #define XSAVE_YMM_SIZE 256 |
19 | #define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET) | 19 | #define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET) |
20 | 20 | ||
21 | /* Supervisor features */ | ||
22 | #define XFEATURE_MASK_SUPERVISOR (XFEATURE_MASK_PT) | ||
23 | |||
21 | /* Supported features which support lazy state saving */ | 24 | /* Supported features which support lazy state saving */ |
22 | #define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \ | 25 | #define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \ |
23 | XFEATURE_MASK_SSE | \ | 26 | XFEATURE_MASK_SSE | \ |
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 7963029cb4ad..02786fb7a1e8 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c | |||
@@ -112,6 +112,27 @@ int cpu_has_xfeatures(u64 xfeatures_needed, const char **feature_name) | |||
112 | } | 112 | } |
113 | EXPORT_SYMBOL_GPL(cpu_has_xfeatures); | 113 | EXPORT_SYMBOL_GPL(cpu_has_xfeatures); |
114 | 114 | ||
115 | static int xfeature_is_supervisor(int xfeature_nr) | ||
116 | { | ||
117 | /* | ||
118 | * We currently do not support supervisor states, but if | ||
119 | * we did, we could find out like this. | ||
120 | * | ||
121 | * SDM says: If state component 'i' is a user state component, | ||
122 | * ECX[0] return 0; if state component i is a supervisor | ||
123 | * state component, ECX[0] returns 1. | ||
124 | */ | ||
125 | u32 eax, ebx, ecx, edx; | ||
126 | |||
127 | cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); | ||
128 | return !!(ecx & 1); | ||
129 | } | ||
130 | |||
131 | static int xfeature_is_user(int xfeature_nr) | ||
132 | { | ||
133 | return !xfeature_is_supervisor(xfeature_nr); | ||
134 | } | ||
135 | |||
115 | /* | 136 | /* |
116 | * When executing XSAVEOPT (or other optimized XSAVE instructions), if | 137 | * When executing XSAVEOPT (or other optimized XSAVE instructions), if |
117 | * a processor implementation detects that an FPU state component is still | 138 | * a processor implementation detects that an FPU state component is still |
@@ -230,7 +251,14 @@ static void __init setup_xstate_features(void) | |||
230 | continue; | 251 | continue; |
231 | 252 | ||
232 | cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); | 253 | cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); |
233 | xstate_offsets[i] = ebx; | 254 | |
255 | /* | ||
256 | * If an xfeature is supervisor state, the offset | ||
257 | * in EBX is invalid. We leave it to -1. | ||
258 | */ | ||
259 | if (xfeature_is_user(i)) | ||
260 | xstate_offsets[i] = ebx; | ||
261 | |||
234 | xstate_sizes[i] = eax; | 262 | xstate_sizes[i] = eax; |
235 | /* | 263 | /* |
236 | * In our xstate size checks, we assume that the | 264 | * In our xstate size checks, we assume that the |
@@ -375,32 +403,20 @@ static void __init setup_init_fpu_buf(void) | |||
375 | copy_xregs_to_kernel_booting(&init_fpstate.xsave); | 403 | copy_xregs_to_kernel_booting(&init_fpstate.xsave); |
376 | } | 404 | } |
377 | 405 | ||
378 | static int xfeature_is_supervisor(int xfeature_nr) | ||
379 | { | ||
380 | /* | ||
381 | * We currently do not support supervisor states, but if | ||
382 | * we did, we could find out like this. | ||
383 | * | ||
384 | * SDM says: If state component i is a user state component, | ||
385 | * ECX[0] return 0; if state component i is a supervisor | ||
386 | * state component, ECX[0] returns 1. | ||
387 | u32 eax, ebx, ecx, edx; | ||
388 | cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx; | ||
389 | return !!(ecx & 1); | ||
390 | */ | ||
391 | return 0; | ||
392 | } | ||
393 | /* | ||
394 | static int xfeature_is_user(int xfeature_nr) | ||
395 | { | ||
396 | return !xfeature_is_supervisor(xfeature_nr); | ||
397 | } | ||
398 | */ | ||
399 | |||
400 | static int xfeature_uncompacted_offset(int xfeature_nr) | 406 | static int xfeature_uncompacted_offset(int xfeature_nr) |
401 | { | 407 | { |
402 | u32 eax, ebx, ecx, edx; | 408 | u32 eax, ebx, ecx, edx; |
403 | 409 | ||
410 | /* | ||
411 | * Only XSAVES supports supervisor states and it uses compacted | ||
412 | * format. Checking a supervisor state's uncompacted offset is | ||
413 | * an error. | ||
414 | */ | ||
415 | if (XFEATURE_MASK_SUPERVISOR & (1 << xfeature_nr)) { | ||
416 | WARN_ONCE(1, "No fixed offset for xstate %d\n", xfeature_nr); | ||
417 | return -1; | ||
418 | } | ||
419 | |||
404 | CHECK_XFEATURE(xfeature_nr); | 420 | CHECK_XFEATURE(xfeature_nr); |
405 | cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); | 421 | cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); |
406 | return ebx; | 422 | return ebx; |