[PATCH v12 4/4] x86/cpu: Clear feature bits whose dependencies were cleared
From: Maciej Wieczor-Retman
Date: Fri Mar 27 2026 - 11:15:32 EST
From: Maciej Wieczor-Retman <maciej.wieczor-retman@xxxxxxxxx>
After cpu_caps_cleared[] is initialized with DISABLED_MASK_INIT,
features present in disabled bitmasks are cleared from x86_capability[].
However features that depend on them and are not part of any disabled
mask are not cleared by anything. They can trigger the warning in
check_cpufeature_deps(), as before both features would show up as
enabled even though they weren't. The uncleared features can also still
falsely show up in /proc/cpuinfo.
Take such cases into account before applying the cpu_caps_cleared[]
array.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@xxxxxxxxx>
---
Changelog v12:
- Move the check from check_cpufeature_deps() to apply_forced_caps().
Redo last paragraph of the patch message.
Changelog v11:
- Add this patch to the series.
arch/x86/include/asm/cpufeature.h | 1 +
arch/x86/kernel/cpu/common.c | 2 ++
arch/x86/kernel/cpu/cpuid-deps.c | 14 ++++++++++++++
3 files changed, 17 insertions(+)
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 3ddc1d33399b..e7a62990a9c2 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -77,6 +77,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
extern void setup_clear_cpu_cap(unsigned int bit);
extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
+void clear_feature_disabled_deps(struct cpuinfo_x86 *c);
void check_cpufeature_deps(struct cpuinfo_x86 *c);
#define setup_force_cpu_cap(bit) do { \
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 8ad0da7012dd..2e24bdb3acaa 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -955,6 +955,8 @@ static void apply_forced_caps(struct cpuinfo_x86 *c)
{
int i;
+ clear_feature_disabled_deps(c);
+
for (i = 0; i < NCAPINTS + NBUGINTS; i++) {
c->x86_capability[i] &= ~cpu_caps_cleared[i];
c->x86_capability[i] |= cpu_caps_set[i];
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index 4354c0dd6d66..83060c0013c1 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -158,6 +158,20 @@ void setup_clear_cpu_cap(unsigned int feature)
do_clear_cpu_cap(NULL, feature);
}
+/*
+ * If the dependency was cleared through the disabled bitmasks while the
+ * feature wasn't it also needs to be cleared.
+ */
+void clear_feature_disabled_deps(struct cpuinfo_x86 *c)
+{
+ const struct cpuid_dep *d;
+
+ for (d = cpuid_deps; d->feature; d++) {
+ if (!DISABLED_MASK_BIT_SET(d->feature) && DISABLED_MASK_BIT_SET(d->depends))
+ set_bit(d->feature, (unsigned long *)cpu_caps_cleared);
+ }
+}
+
void check_cpufeature_deps(struct cpuinfo_x86 *c)
{
char feature_buf[X86_NAMELESS_FEAT_BUFLEN], depends_buf[X86_NAMELESS_FEAT_BUFLEN];
--
2.53.0