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 <darwi@linutronix.de>
---
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 2ba5f166e58f..33deebdde48a 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -239,7 +239,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 ece5a59124f5..98e53f5aa41d 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -968,11 +968,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]);
}
}
@@ -2002,8 +2000,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;
@@ -2112,13 +2108,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);
@@ -2521,12 +2517,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);
@@ -2556,10 +2557,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 146f6f8b0650..78374450374a 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -106,7 +106,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 efc155e1da10..161fa2b23bdb 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.53.0