aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2015-06-07 14:37:00 -0400
committerIngo Molnar <mingo@kernel.org>2015-06-09 06:24:29 -0400
commit0c4109bec0a6cde471bef3a21cd6f8384a614469 (patch)
treee7bf13898b3442c37998404f52258ac90a81f2ee
parent83242c515881cc8642d726c3e648e41bf6c24551 (diff)
x86/fpu/xstate: Fix up bad get_xsave_addr() assumptions
get_xsave_addr() assumes that if an xsave bit is present in the hardware (pcntxt_mask) that it is present in a given xsave buffer. Due to an bug in the xsave code on all of the systems that have MPX (and thus all the users of this code), that has been a true assumption. But, the bug is getting fixed, so our assumption is not going to hold any more. It's quite possible (and normal) for an enabled state to be present on 'pcntxt_mask', but *not* in 'xstate_bv'. We need to consult 'xstate_bv'. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Dave Hansen <dave@sr71.net> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20150607183700.1E739B34@viggo.jf.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/fpu/xstate.c45
1 files changed, 37 insertions, 8 deletions
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index a580eb5c7e52..af3700e0dbd2 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -382,19 +382,48 @@ void fpu__resume_cpu(void)
382 * This is the API that is called to get xstate address in either 382 * This is the API that is called to get xstate address in either
383 * standard format or compacted format of xsave area. 383 * standard format or compacted format of xsave area.
384 * 384 *
385 * Note that if there is no data for the field in the xsave buffer
386 * this will return NULL.
387 *
385 * Inputs: 388 * Inputs:
386 * xsave: base address of the xsave area; 389 * xstate: the thread's storage area for all FPU data
387 * xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE, 390 * xstate_feature: state which is defined in xsave.h (e.g.
388 * etc.) 391 * XSTATE_FP, XSTATE_SSE, etc...)
389 * Output: 392 * Output:
390 * address of the state in the xsave area. 393 * address of the state in the xsave area, or NULL if the
394 * field is not present in the xsave buffer.
391 */ 395 */
392void *get_xsave_addr(struct xregs_state *xsave, int xstate) 396void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
393{ 397{
394 int feature = fls64(xstate) - 1; 398 int feature_nr = fls64(xstate_feature) - 1;
395 if (!test_bit(feature, (unsigned long *)&xfeatures_mask)) 399 /*
400 * Do we even *have* xsave state?
401 */
402 if (!boot_cpu_has(X86_FEATURE_XSAVE))
403 return NULL;
404
405 xsave = &current->thread.fpu.state.xsave;
406 /*
407 * We should not ever be requesting features that we
408 * have not enabled. Remember that pcntxt_mask is
409 * what we write to the XCR0 register.
410 */
411 WARN_ONCE(!(xfeatures_mask & xstate_feature),
412 "get of unsupported state");
413 /*
414 * This assumes the last 'xsave*' instruction to
415 * have requested that 'xstate_feature' be saved.
416 * If it did not, we might be seeing and old value
417 * of the field in the buffer.
418 *
419 * This can happen because the last 'xsave' did not
420 * request that this feature be saved (unlikely)
421 * or because the "init optimization" caused it
422 * to not be saved.
423 */
424 if (!(xsave->header.xfeatures & xstate_feature))
396 return NULL; 425 return NULL;
397 426
398 return (void *)xsave + xstate_comp_offsets[feature]; 427 return (void *)xsave + xstate_comp_offsets[feature_nr];
399} 428}
400EXPORT_SYMBOL_GPL(get_xsave_addr); 429EXPORT_SYMBOL_GPL(get_xsave_addr);