* [PATCH v5 2/5] x86/cpuid: Add generic table for cpuid dependencies
2017-08-17 15:43 Support generic disabling of all XSAVE features v5 Andi Kleen
2017-08-17 15:43 ` [PATCH v5 1/5] x86/xsave: Move xsave initialization to after parsing early parameters Andi Kleen
@ 2017-08-17 15:44 ` Andi Kleen
2017-08-17 15:44 ` [PATCH v5 3/5] x86/cpuid: Make clearcpuid an early param Andi Kleen
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Andi Kleen @ 2017-08-17 15:44 UTC (permalink / raw)
To: hpa; +Cc: x86, linux-kernel, Andi Kleen, Jonathan McDowell
From: Andi Kleen <ak@linux.intel.com>
Some CPUID features depend on other features. Currently it's
possible to to clear dependent features, but not clear the base features,
which can cause various interesting problems.
This patch implements a generic table to describe dependencies
between CPUID features, to be used by all code that clears
CPUID.
Some subsystems (like XSAVE) had an own implementation of this,
but it's better to do it all in a single place for everyone.
Then clear_cpu_cap and setup_clear_cpu_cap always look up
this table and clear all dependencies too.
This is intended to be a practical table: only for features
that make sense to clear. If someone for example clears FPU,
or other features that are essentially part of the required
base feature set, not much is going to work. Handling
that is right now out of scope. We're only handling
features which can be usefully cleared.
v2: Add EXPORT_SYMBOL for clear_cpu_id for lguest
v3:
Fix handling of depending issues
Fix dups in the table (Jonathan McDowell)
Cc: Jonathan McDowell <noodles@earth.li>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/include/asm/cpufeature.h | 8 +++-
arch/x86/include/asm/cpufeatures.h | 5 ++
arch/x86/kernel/cpu/Makefile | 1 +
arch/x86/kernel/cpu/cpuid-deps.c | 94 ++++++++++++++++++++++++++++++++++++++
4 files changed, 106 insertions(+), 2 deletions(-)
create mode 100644 arch/x86/kernel/cpu/cpuid-deps.c
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index d59c15c3defd..e6145f383ff8 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -125,8 +125,12 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
#define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability))
-#define clear_cpu_cap(c, bit) clear_bit(bit, (unsigned long *)((c)->x86_capability))
-#define setup_clear_cpu_cap(bit) do { \
+#define __clear_cpu_cap(c, bit) clear_bit(bit, (unsigned long *)((c)->x86_capability))
+
+extern void setup_clear_cpu_cap(int bit);
+extern void clear_cpu_cap(struct cpuinfo_x86 *cpu, int bit);
+
+#define __setup_clear_cpu_cap(bit) do { \
clear_cpu_cap(&boot_cpu_data, bit); \
set_bit(bit, (unsigned long *)cpu_caps_cleared); \
} while (0)
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index ca3c48c0872f..3467e5dd5259 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -21,6 +21,11 @@
* this feature bit is not displayed in /proc/cpuinfo at all.
*/
+/*
+ * When adding new features here that depend on other features,
+ * please update the table in kernel/cpu/cpuid-deps.c
+ */
+
/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
#define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */
#define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index cdf82492b770..ffc3ec870f1e 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -22,6 +22,7 @@ obj-y += rdrand.o
obj-y += match.o
obj-y += bugs.o
obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
+obj-y += cpuid-deps.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
new file mode 100644
index 000000000000..f3087d46459d
--- /dev/null
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -0,0 +1,94 @@
+/* Declare dependencies between CPUIDs */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/cpufeature.h>
+
+struct cpuid_dep {
+ int feature;
+ int disable;
+};
+
+/*
+ * Table of CPUID features that depend on others.
+ *
+ * This only includes dependencies that can be usefully disabled, not
+ * features part of the base set (like FPU).
+ */
+const static struct cpuid_dep cpuid_deps[] = {
+ { X86_FEATURE_XSAVE, X86_FEATURE_XSAVEOPT },
+ { X86_FEATURE_XSAVE, X86_FEATURE_XSAVEC },
+ { X86_FEATURE_XSAVE, X86_FEATURE_XSAVES },
+ { X86_FEATURE_XSAVE, X86_FEATURE_AVX },
+ { X86_FEATURE_XSAVE, X86_FEATURE_AVX512F },
+ { X86_FEATURE_XSAVE, X86_FEATURE_PKU },
+ { X86_FEATURE_XSAVE, X86_FEATURE_MPX },
+ { X86_FEATURE_XSAVE, X86_FEATURE_XGETBV1 },
+ { X86_FEATURE_XMM, X86_FEATURE_XMM2 },
+ { X86_FEATURE_XMM2, X86_FEATURE_XMM3 },
+ { X86_FEATURE_XMM2, X86_FEATURE_XMM4_1 },
+ { X86_FEATURE_XMM2, X86_FEATURE_XMM4_2 },
+ { X86_FEATURE_XMM2, X86_FEATURE_XMM3 },
+ { X86_FEATURE_XMM2, X86_FEATURE_PCLMULQDQ },
+ { X86_FEATURE_XMM2, X86_FEATURE_SSSE3 },
+ { X86_FEATURE_XMM2, X86_FEATURE_F16C },
+ { X86_FEATURE_XMM2, X86_FEATURE_AES },
+ { X86_FEATURE_FMA, X86_FEATURE_AVX },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512IFMA },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512PF },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512ER },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512CD },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512DQ },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512BW },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512VL },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512VBMI },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512_4VNNIW },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512_4FMAPS },
+ { X86_FEATURE_AVX512F, X86_FEATURE_AVX512_VPOPCNTDQ },
+ { X86_FEATURE_AVX, X86_FEATURE_AVX2 },
+ {}
+};
+
+static inline void clearfeat(struct cpuinfo_x86 *cpu, int feat)
+{
+ if (!cpu)
+ __setup_clear_cpu_cap(feat);
+ else
+ __clear_cpu_cap(cpu, feat);
+}
+
+static void do_clear_cpu_cap(struct cpuinfo_x86 *cpu, int feat)
+{
+ bool changed;
+ __u32 disable[NCAPINTS + NBUGINTS];
+ unsigned long *disable_mask = (unsigned long *)disable;
+ const struct cpuid_dep *d;
+
+ clearfeat(cpu, feat);
+
+ /* Collect all features to disable, handling dependencies */
+ memset(disable, 0, sizeof(disable));
+ __set_bit(feat, disable_mask);
+ do {
+ changed = false;
+ for (d = cpuid_deps; d->feature; d++) {
+ if (test_bit(d->feature, disable_mask) &&
+ !__test_and_set_bit(d->disable, disable_mask)) {
+ changed = true;
+ clearfeat(cpu, d->disable);
+ }
+ }
+ } while (changed);
+}
+
+void clear_cpu_cap(struct cpuinfo_x86 *cpu, int feat)
+{
+ do_clear_cpu_cap(cpu, feat);
+}
+
+EXPORT_SYMBOL_GPL(clear_cpu_cap);
+
+void setup_clear_cpu_cap(int feat)
+{
+ do_clear_cpu_cap(NULL, feat);
+}
--
2.9.4
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 4/5] x86/xsave: Make XSAVE check the base CPUID features before enabling
2017-08-17 15:43 Support generic disabling of all XSAVE features v5 Andi Kleen
` (2 preceding siblings ...)
2017-08-17 15:44 ` [PATCH v5 3/5] x86/cpuid: Make clearcpuid an early param Andi Kleen
@ 2017-08-17 15:44 ` Andi Kleen
2017-08-17 15:44 ` [PATCH v5 5/5] x86/xsave: Using generic CPUID clearing when disabling XSAVE Andi Kleen
4 siblings, 0 replies; 6+ messages in thread
From: Andi Kleen @ 2017-08-17 15:44 UTC (permalink / raw)
To: hpa; +Cc: x86, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Before enabling XSAVE, not only check the XSAVE specific CPUID bits,
but also the base CPUID features of the respective XSAVE feature.
This allows to disable individual XSAVE states using the existing
clearcpuid= option, which can be useful for performance testing
and debugging, and also in general avoids inconsistencies.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/kernel/fpu/xstate.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index c24ac1efb12d..8f0b96320cc9 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -15,6 +15,7 @@
#include <asm/fpu/xstate.h>
#include <asm/tlbflush.h>
+#include <asm/cpufeature.h>
/*
* Although we spell it out in here, the Processor Trace
@@ -36,6 +37,19 @@ static const char *xfeature_names[] =
"unknown xstate feature" ,
};
+static short xsave_cpuid_features[] = {
+ X86_FEATURE_FPU,
+ X86_FEATURE_XMM,
+ X86_FEATURE_AVX,
+ X86_FEATURE_MPX,
+ X86_FEATURE_MPX,
+ X86_FEATURE_AVX512F,
+ X86_FEATURE_AVX512F,
+ X86_FEATURE_AVX512F,
+ X86_FEATURE_INTEL_PT,
+ X86_FEATURE_PKU,
+};
+
/*
* Mask of xstate features supported by the CPU and the kernel:
*/
@@ -702,6 +716,7 @@ void __init fpu__init_system_xstate(void)
unsigned int eax, ebx, ecx, edx;
static int on_boot_cpu __initdata = 1;
int err;
+ int i;
WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0;
@@ -735,6 +750,13 @@ void __init fpu__init_system_xstate(void)
goto out_disable;
}
+ /*
+ * Clear XSAVE features that are disabled in the normal CPUID.
+ */
+ for (i = 0; i < ARRAY_SIZE(xsave_cpuid_features); i++)
+ if (!boot_cpu_has(xsave_cpuid_features[i]))
+ xfeatures_mask &= ~BIT(i);
+
xfeatures_mask &= fpu__get_supported_xfeatures_mask();
/* Enable xstate instructions to be able to continue with initialization: */
--
2.9.4
^ permalink raw reply related [flat|nested] 6+ messages in thread