Some CPU feature bits are forced set and stored in cpuinfo_x86 before handling clearcpuid options. To clear those bits from cpuinfo_x86, apply_forced_cap() is called after handling the options. Please note, apply_forced_cap() is called twice on boot CPU. But this code is simple and there is no functionality issue. Signed-off-by: Fenghua Yu <fenghua.yu@xxxxxxxxx> --- arch/x86/include/asm/cpu.h | 2 ++ arch/x86/kernel/cpu/common.c | 5 +++-- arch/x86/kernel/fpu/init.c | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 4e03f53fc079..bfa5ac6b7502 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -26,6 +26,8 @@ struct x86_cpu { struct cpu cpu; }; +void apply_forced_caps(struct cpuinfo_x86 *c); + #ifdef CONFIG_HOTPLUG_CPU extern int arch_register_cpu(int num); extern void arch_unregister_cpu(int); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index bbdd69dd4f5f..e1d41405c27b 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -758,13 +758,14 @@ void cpu_detect(struct cpuinfo_x86 *c) } } -static void apply_forced_caps(struct cpuinfo_x86 *c) +void apply_forced_caps(struct cpuinfo_x86 *c) { int i; for (i = 0; i < NCAPINTS + NBUGINTS; i++) { - c->x86_capability[i] &= ~cpu_caps_cleared[i]; + /* Bits may be cleared after they are set. */ c->x86_capability[i] |= cpu_caps_set[i]; + c->x86_capability[i] &= ~cpu_caps_cleared[i]; } } diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 99b895eea166..9c2801b605e3 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -5,6 +5,7 @@ #include <asm/tlbflush.h> #include <asm/setup.h> #include <asm/cmdline.h> +#include <asm/cpu.h> #include <linux/sched.h> #include <linux/sched/task.h> @@ -261,6 +262,7 @@ static void __init clear_cpuid(void) bit >= 0 && bit < NCAPINTS * 32) setup_clear_cpu_cap(bit); } + apply_forced_caps(&boot_cpu_data); } /* -- 2.19.1