Skip to content

Commit 0c4109b

Browse files
hansendcIngo Molnar
authored andcommitted
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 <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Dave Hansen <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 83242c5 commit 0c4109b

File tree

1 file changed

+37
-8
lines changed

1 file changed

+37
-8
lines changed

arch/x86/kernel/fpu/xstate.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -382,19 +382,48 @@ void fpu__resume_cpu(void)
382382
* This is the API that is called to get xstate address in either
383383
* standard format or compacted format of xsave area.
384384
*
385+
* Note that if there is no data for the field in the xsave buffer
386+
* this will return NULL.
387+
*
385388
* Inputs:
386-
* xsave: base address of the xsave area;
387-
* xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE,
388-
* etc.)
389+
* xstate: the thread's storage area for all FPU data
390+
* xstate_feature: state which is defined in xsave.h (e.g.
391+
* XSTATE_FP, XSTATE_SSE, etc...)
389392
* 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.
391395
*/
392-
void *get_xsave_addr(struct xregs_state *xsave, int xstate)
396+
void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
393397
{
394-
int feature = fls64(xstate) - 1;
395-
if (!test_bit(feature, (unsigned long *)&xfeatures_mask))
398+
int feature_nr = fls64(xstate_feature) - 1;
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))
396425
return NULL;
397426

398-
return (void *)xsave + xstate_comp_offsets[feature];
427+
return (void *)xsave + xstate_comp_offsets[feature_nr];
399428
}
400429
EXPORT_SYMBOL_GPL(get_xsave_addr);

0 commit comments

Comments
 (0)