Commit 6afbb58c authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Borislav Petkov

x86/fpu: Cache xfeature flags from CPUID

In preparation for runtime calculation of XSAVE offsets cache the feature
flags for each XSTATE component during feature enumeration via CPUID(0xD).

EDX has two relevant bits:
    0	Supervisor component
    1	Feature storage must be 64 byte aligned

These bits are currently only evaluated during init, but the alignment bit
must be cached to make runtime calculation of XSAVE offsets efficient.

Cache the full EDX content and use it for the existing alignment and
supervisor checks.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Link: https://lore.kernel.org/r/20220324134623.573656209@linutronix.de
parent 35a77d45
...@@ -83,6 +83,10 @@ static unsigned int xstate_sizes[XFEATURE_MAX] __ro_after_init = ...@@ -83,6 +83,10 @@ static unsigned int xstate_sizes[XFEATURE_MAX] __ro_after_init =
{ [ 0 ... XFEATURE_MAX - 1] = -1}; { [ 0 ... XFEATURE_MAX - 1] = -1};
static unsigned int xstate_comp_offsets[XFEATURE_MAX] __ro_after_init = static unsigned int xstate_comp_offsets[XFEATURE_MAX] __ro_after_init =
{ [ 0 ... XFEATURE_MAX - 1] = -1}; { [ 0 ... XFEATURE_MAX - 1] = -1};
static unsigned int xstate_flags[XFEATURE_MAX] __ro_after_init;
#define XSTATE_FLAG_SUPERVISOR BIT(0)
#define XSTATE_FLAG_ALIGNED64 BIT(1)
/* /*
* Return whether the system supports a given xfeature. * Return whether the system supports a given xfeature.
...@@ -122,17 +126,14 @@ int cpu_has_xfeatures(u64 xfeatures_needed, const char **feature_name) ...@@ -122,17 +126,14 @@ int cpu_has_xfeatures(u64 xfeatures_needed, const char **feature_name)
} }
EXPORT_SYMBOL_GPL(cpu_has_xfeatures); EXPORT_SYMBOL_GPL(cpu_has_xfeatures);
static bool xfeature_is_supervisor(int xfeature_nr) static bool xfeature_is_aligned64(int xfeature_nr)
{ {
/* return xstate_flags[xfeature_nr] & XSTATE_FLAG_ALIGNED64;
* Extended State Enumeration Sub-leaves (EAX = 0DH, ECX = n, n > 1) }
* returns ECX[0] set to (1) for a supervisor state, and cleared (0)
* for a user state.
*/
u32 eax, ebx, ecx, edx;
cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); static bool xfeature_is_supervisor(int xfeature_nr)
return ecx & 1; {
return xstate_flags[xfeature_nr] & XSTATE_FLAG_SUPERVISOR;
} }
/* /*
...@@ -203,6 +204,7 @@ static void __init setup_xstate_cache(void) ...@@ -203,6 +204,7 @@ static void __init setup_xstate_cache(void)
cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
xstate_sizes[i] = eax; xstate_sizes[i] = eax;
xstate_flags[i] = ecx;
/* /*
* If an xfeature is supervisor state, the offset in EBX is * If an xfeature is supervisor state, the offset in EBX is
...@@ -261,31 +263,6 @@ static void __init print_xstate_features(void) ...@@ -261,31 +263,6 @@ static void __init print_xstate_features(void)
WARN_ON(nr >= XFEATURE_MAX); \ WARN_ON(nr >= XFEATURE_MAX); \
} while (0) } while (0)
/*
* We could cache this like xstate_size[], but we only use
* it here, so it would be a waste of space.
*/
static int xfeature_is_aligned(int xfeature_nr)
{
u32 eax, ebx, ecx, edx;
CHECK_XFEATURE(xfeature_nr);
if (!xfeature_enabled(xfeature_nr)) {
WARN_ONCE(1, "Checking alignment of disabled xfeature %d\n",
xfeature_nr);
return 0;
}
cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx);
/*
* The value returned by ECX[1] indicates the alignment
* of state component 'i' when the compacted format
* of the extended region of an XSAVE area is used:
*/
return !!(ecx & 2);
}
/* /*
* This function sets up offsets and sizes of all extended states in * This function sets up offsets and sizes of all extended states in
* xsave area. This supports both standard format and compacted format * xsave area. This supports both standard format and compacted format
...@@ -314,7 +291,7 @@ static void __init setup_xstate_comp_offsets(void) ...@@ -314,7 +291,7 @@ static void __init setup_xstate_comp_offsets(void)
next_offset = FXSAVE_SIZE + XSAVE_HDR_SIZE; next_offset = FXSAVE_SIZE + XSAVE_HDR_SIZE;
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) { for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) {
if (xfeature_is_aligned(i)) if (xfeature_is_aligned64(i))
next_offset = ALIGN(next_offset, 64); next_offset = ALIGN(next_offset, 64);
xstate_comp_offsets[i] = next_offset; xstate_comp_offsets[i] = next_offset;
...@@ -619,7 +596,7 @@ static unsigned int xstate_calculate_size(u64 xfeatures, bool compacted) ...@@ -619,7 +596,7 @@ static unsigned int xstate_calculate_size(u64 xfeatures, bool compacted)
for_each_extended_xfeature(i, xfeatures) { for_each_extended_xfeature(i, xfeatures) {
/* Align from the end of the previous feature */ /* Align from the end of the previous feature */
if (xfeature_is_aligned(i)) if (xfeature_is_aligned64(i))
size = ALIGN(size, 64); size = ALIGN(size, 64);
/* /*
* In compacted format the enabled features are packed, * In compacted format the enabled features are packed,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment