|
@@ -382,19 +382,48 @@ void fpu__resume_cpu(void)
|
|
|
* This is the API that is called to get xstate address in either
|
|
|
* standard format or compacted format of xsave area.
|
|
|
*
|
|
|
+ * Note that if there is no data for the field in the xsave buffer
|
|
|
+ * this will return NULL.
|
|
|
+ *
|
|
|
* Inputs:
|
|
|
- * xsave: base address of the xsave area;
|
|
|
- * xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE,
|
|
|
- * etc.)
|
|
|
+ * xstate: the thread's storage area for all FPU data
|
|
|
+ * xstate_feature: state which is defined in xsave.h (e.g.
|
|
|
+ * XSTATE_FP, XSTATE_SSE, etc...)
|
|
|
* Output:
|
|
|
- * address of the state in the xsave area.
|
|
|
+ * address of the state in the xsave area, or NULL if the
|
|
|
+ * field is not present in the xsave buffer.
|
|
|
*/
|
|
|
-void *get_xsave_addr(struct xregs_state *xsave, int xstate)
|
|
|
+void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
|
|
|
{
|
|
|
- int feature = fls64(xstate) - 1;
|
|
|
- if (!test_bit(feature, (unsigned long *)&xfeatures_mask))
|
|
|
+ int feature_nr = fls64(xstate_feature) - 1;
|
|
|
+ /*
|
|
|
+ * Do we even *have* xsave state?
|
|
|
+ */
|
|
|
+ if (!boot_cpu_has(X86_FEATURE_XSAVE))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ xsave = ¤t->thread.fpu.state.xsave;
|
|
|
+ /*
|
|
|
+ * We should not ever be requesting features that we
|
|
|
+ * have not enabled. Remember that pcntxt_mask is
|
|
|
+ * what we write to the XCR0 register.
|
|
|
+ */
|
|
|
+ WARN_ONCE(!(xfeatures_mask & xstate_feature),
|
|
|
+ "get of unsupported state");
|
|
|
+ /*
|
|
|
+ * This assumes the last 'xsave*' instruction to
|
|
|
+ * have requested that 'xstate_feature' be saved.
|
|
|
+ * If it did not, we might be seeing and old value
|
|
|
+ * of the field in the buffer.
|
|
|
+ *
|
|
|
+ * This can happen because the last 'xsave' did not
|
|
|
+ * request that this feature be saved (unlikely)
|
|
|
+ * or because the "init optimization" caused it
|
|
|
+ * to not be saved.
|
|
|
+ */
|
|
|
+ if (!(xsave->header.xfeatures & xstate_feature))
|
|
|
return NULL;
|
|
|
|
|
|
- return (void *)xsave + xstate_comp_offsets[feature];
|
|
|
+ return (void *)xsave + xstate_comp_offsets[feature_nr];
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(get_xsave_addr);
|