[PATCH v7 114/120] x86: Route all feature queries to the CPUID tables
"Ahmed S. Darwish" <[email protected]> Thu, 28 May 2026 17:39:16 +0200
| Newsgroups | dev.linux.lists.x86-cpuid,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Use the CPUID API's cpuid_feature_*() and cpuid_word_*() helpers to route all feature querying to the CPUID tables instead of to x86_capability[]. This allows the CPUID tables to act as a single source of truth for x86 feature state; both hardware-backed and synthetic. Do this routing in one shot, not to fragment x86 state tracking between CPUID tables and x86_capability[]. The latter will be fully removed. Signed-off-by: Ahmed S. Darwish <[email protected]> --- arch/x86/include/asm/cpufeature.h | 12 ++++++--- arch/x86/include/asm/elf.h | 2 +- arch/x86/kernel/cpu/common.c | 41 +++++++++++++++++-------------- arch/x86/kernel/cpu/cpuid-deps.c | 2 +- arch/x86/kernel/mpparse.c | 2 +- arch/x86/kvm/cpuid.c | 3 +-- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 48643b4b1e24..58d5e4f3891c 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <asm/alternative.h> #include <asm/cpufeaturemasks.h> +#include <asm/cpuid/api.h> enum cpuid_leafs { @@ -48,7 +49,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define x86_bug_flag(flag) x86_bug_flags[flag] #define test_cpu_cap(c, bit) \ - arch_test_bit(bit, (unsigned long *)((c)->x86_capability)) + arch_test_bit(cpuid_feature_bit_offset(bit), cpuid_feature_bitmap(c, bit)) #define cpu_has(c, bit) \ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ @@ -56,7 +57,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define this_cpu_has(bit) \ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ - x86_this_cpu_test_bit(bit, cpu_info.x86_capability, 0)) + x86_this_cpu_test_bit(cpuid_feature_bit_offset(bit), cpu_info.cpuid.leaves, cpuid_feature_byte_offset(bit))) /* * This is the default CPU features testing macro to use in code. @@ -72,7 +73,8 @@ 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 set_cpu_cap(c, bit) \ + set_bit(cpuid_feature_bit_offset(bit), cpuid_feature_bitmap(c, bit)) extern void setup_clear_cpu_cap(unsigned int bit); extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit); @@ -116,7 +118,9 @@ void check_cpufeature_deps(struct cpuinfo_x86 *c); static __always_inline bool _static_cpu_has(u16 bit) { - __static_cpu_has(bit, &boot_cpu_data.x86_capability, bit); + __static_cpu_has(bit, + cpuid_feature_bitmap(&boot_cpu_data, bit), + cpuid_feature_bit_offset(bit)); } #define static_cpu_has(bit) \ diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index c7f98977663c..abf3142bb255 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -238,7 +238,7 @@ extern int force_personality32; instruction set this CPU supports. This could be done in user space, but it's not easy, and we've already done it here. */ -#define ELF_HWCAP (boot_cpu_data.x86_capability[CPUID_1_EDX]) +#define ELF_HWCAP cpuid_word(&boot_cpu_data, CPUID_1_EDX) extern u32 elf_hwcap2; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f5e3aaed67ef..d6b3550b9f11 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -970,11 +970,9 @@ void cpu_detect(struct cpuinfo_x86 *c) static 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]; - c->x86_capability[i] |= cpu_caps_set[i]; + for (int i = 0; i < NCAPINTS + NBUGINTS; i++) { + cpuid_word_clear_bits(c, i, cpu_caps_cleared[i]); + cpuid_word_set_bits(c, i, cpu_caps_set[i]); } } @@ -2004,8 +2002,6 @@ static void generic_identify(struct cpuinfo_x86 *c) */ static void identify_cpu(struct cpuinfo_x86 *c) { - int i; - c->loops_per_jiffy = loops_per_jiffy; c->x86_cache_size = 0; c->x86_vendor = X86_VENDOR_UNKNOWN; @@ -2107,13 +2103,13 @@ static void identify_cpu(struct cpuinfo_x86 *c) * executed, c == &boot_cpu_data. */ if (c != &boot_cpu_data) { - /* AND the already accumulated flags with these */ - for (i = 0; i < NCAPINTS; i++) - boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; + /* Clear boot_cpu_data features that are not on this CPU */ + for (int i = 0; i < NCAPINTS; i++) + cpuid_word_clear_bits(&boot_cpu_data, i, ~cpuid_word(c, i)); - /* OR, i.e. replicate the bug flags */ - for (i = NCAPINTS; i < NCAPINTS + NBUGINTS; i++) - c->x86_capability[i] |= boot_cpu_data.x86_capability[i]; + /* Replicate boot_cpu_data's bug flags to this CPU */ + for (int i = NCAPINTS; i < NCAPINTS + NBUGINTS; i++) + cpuid_word_set_bits(c, i, cpuid_word(&boot_cpu_data, i)); } ppin_init(c); @@ -2529,12 +2525,17 @@ void cpu_init(void) */ void store_cpu_caps(struct cpuinfo_x86 *curr_info) { + const struct leaf_0x0_0 *l0; + /* Reload CPUID max function as it might've changed. */ - curr_info->cpuid_level = cpuid_eax(0); + cpuid_refresh_leaf(curr_info, 0x0); + l0 = cpuid_leaf(curr_info, 0x0); + if (l0) + curr_info->cpuid_level = l0->max_std_leaf; /* Copy all capability leafs and pick up the synthetic ones. */ - memcpy(&curr_info->x86_capability, &boot_cpu_data.x86_capability, - sizeof(curr_info->x86_capability)); + for (int i = 0; i < NCAPINTS + NBUGINTS; i++) + cpuid_word_set(curr_info, i, cpuid_word(&boot_cpu_data, i)); /* Get the hardware CPUID leafs */ get_cpu_cap(curr_info); @@ -2564,10 +2565,12 @@ void microcode_check(struct cpuinfo_x86 *prev_info) store_cpu_caps(curr_info); - if (!memcmp(&prev_info->x86_capability, &curr_info->x86_capability, - sizeof(prev_info->x86_capability))) - return; + for (int i = 0; i < NCAPINTS + NBUGINTS; i++) + if (cpuid_word(prev_info, i) != cpuid_word(curr_info, i)) + goto err; + return; +err: pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n"); pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); } diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c index 99801e844b30..da4fc649f857 100644 --- a/arch/x86/kernel/cpu/cpuid-deps.c +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -107,7 +107,7 @@ static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature) clear_cpu_cap(&boot_cpu_data, feature); set_bit(feature, (unsigned long *)cpu_caps_cleared); } else { - clear_bit(feature, (unsigned long *)c->x86_capability); + clear_bit(cpuid_feature_bit_offset(feature), cpuid_feature_bitmap(c, feature)); } } diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 4a1b1b28abf9..a66f22db640f 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -384,7 +384,7 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) processor.cpuflag = CPU_ENABLED; processor.cpufeature = (boot_cpu_data.x86 << 8) | (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping; - processor.featureflag = boot_cpu_data.x86_capability[CPUID_1_EDX]; + processor.featureflag = cpuid_word(&boot_cpu_data, CPUID_1_EDX); processor.reserved[0] = 0; processor.reserved[1] = 0; for (i = 0; i < 2; i++) { diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index ad0a5410899d..018cd3078306 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -704,7 +704,6 @@ static __always_inline u32 raw_cpuid_get(struct cpuid_reg cpuid) do { \ const struct cpuid_reg cpuid = x86_feature_cpuid(leaf * 32); \ const u32 __maybe_unused kvm_cpu_cap_init_in_progress = leaf; \ - const u32 *kernel_cpu_caps = boot_cpu_data.x86_capability; \ u32 kvm_cpu_cap_passthrough = 0; \ u32 kvm_cpu_cap_synthesized = 0; \ u32 kvm_cpu_cap_emulated = 0; \ @@ -715,7 +714,7 @@ do { \ kvm_cpu_caps[leaf] = kvm_cpu_cap_features; \ \ if (leaf < NCAPINTS) \ - kvm_cpu_caps[leaf] &= kernel_cpu_caps[leaf]; \ + kvm_cpu_caps[leaf] &= cpuid_word(&boot_cpu_data, leaf);\ \ kvm_cpu_caps[leaf] |= kvm_cpu_cap_passthrough; \ kvm_cpu_caps[leaf] &= (raw_cpuid_get(cpuid) | \ -- 2.54.0