From: Nikolay Borisov <bp@alien8.de>
Date: Tue, 22 Aug 2023 13:53:41 +0200
Subject: kabi: Allow extra bugsints
Patch-mainline: Never, kabi fix
References: bsc#1213927
Allow adding more bugints by stashing them in an extra array added at the
end of cpuid_x86 thus ont breaking kABI. All extra bugints begin at
cpuid_x86::x86_ext_capability and also at the end ot cpu_caps_set array.
Signed-off-by: Nikolay Borisov <nik.borisov@suse.com>
---
arch/x86/include/asm/cpufeature.h | 89 +++++++++++++++++++++++++++++++------
arch/x86/include/asm/cpufeatures.h | 3 -
arch/x86/include/asm/processor.h | 3 -
arch/x86/kernel/alternative.c | 5 +-
arch/x86/kernel/cpu/common.c | 7 ++
arch/x86/kernel/cpu/mkcapflags.sh | 4 -
arch/x86/kernel/cpu/proc.c | 4 -
7 files changed, 92 insertions(+), 23 deletions(-)
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -33,10 +33,19 @@ enum cpuid_leafs
CPUID_7_EDX,
CPUID_8000_001F_EAX,
CPUID_8000_0021_EAX,
+ CPUID_MAX = CPUID_8000_0021_EAX,
+ /*
+ * Everything below should go into the extended caps array to preserve
+ * kABI
+ */
CPUID_LNX_5,
CPUID_LNX_6,
};
+#define CPUID_IDX(x) \
+ __builtin_choose_expr((x) > CPUID_MAX, (x) - CPUID_MAX - 1, (x))
+#define IS_EXT_CPUID_BIT(bit) ((bit>>5) >= NCAPINTS)
+
#ifdef CONFIG_X86_FEATURE_NAMES
extern const char * const x86_cap_flags[NCAPINTS*32];
extern const char * const x86_power_flags[32];
@@ -51,10 +60,20 @@ extern const char * const x86_power_flag
* In order to save room, we index into this array by doing
* X86_BUG_<name> - NCAPINTS*32.
*/
-extern const char * const x86_bug_flags[NBUGINTS*32];
+extern const char * const x86_bug_flags[(NBUGINTS+NEXTBUGINTS)*32];
+
+/*
+ * This macro must be called with bit belonging to one of the extended bug bits,
+ * this required because the first bug word (19) aliases with the first extended
+ * cap word (19) as such the check would be ambiguous if this macro is called
+ * with a bit which represents an extended cpuid.
+ */
+#define IS_EXT_BUG_BIT(bit) ((bit>>5) >= (NCAPINTS+NBUGINTS))
#define test_cpu_cap(c, bit) \
- test_bit(bit, (unsigned long *)((c)->x86_capability))
+ (IS_EXT_CPUID_BIT(bit) ? test_bit((bit) - (NCAPINTS*32), \
+ (unsigned long *)((c)->x86_ext_capability)) : \
+ test_bit(bit, (unsigned long *)((c)->x86_capability)))
/*
* There are 32 bits/features in each mask word. The high bits
@@ -145,17 +164,47 @@ extern const char * const x86_bug_flags[
#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) do { \
+ if (IS_EXT_CPUID_BIT(bit)) { \
+ set_bit(bit - (NCAPINTS*32), \
+ (unsigned long *)(c)->x86_ext_capability); \
+ } else { \
+ set_bit(bit, (unsigned long *)((c)->x86_capability)); \
+ } \
+} while (0)
+
extern void setup_clear_cpu_cap(unsigned int bit);
extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
#define setup_force_cpu_cap(bit) do { \
- set_cpu_cap(&boot_cpu_data, bit); \
- set_bit(bit, (unsigned long *)cpu_caps_set); \
+ if (IS_EXT_CPUID_BIT(bit)) { \
+ set_bit(bit - (NCAPINTS*32), \
+ (unsigned long *)&cpu_caps_set[NCAPINTS + NBUGINTS]); \
+ set_bit(bit - (NCAPINTS*32), \
+ (unsigned long *)(&boot_cpu_data)->x86_ext_capability); \
+ } else { \
+ set_cpu_cap(&boot_cpu_data, bit); \
+ set_bit(bit, (unsigned long *)cpu_caps_set); \
+ } \
} while (0)
-#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
+
+/*
+ * This has to be re-implemented because of the aliasing issues between
+ * extended capability bits and bug bits, see comment above IS_EXT_BUG_BIT.
+ */
+#define setup_force_cpu_bug(bit) do { \
+ if (IS_EXT_BUG_BIT(bit)) { \
+ set_bit(bit - ((NCAPINTS+NBUGINTS)*32), \
+ (unsigned long *)&cpu_caps_set[NCAPINTS + NBUGINTS + NEXTCAPINTS]); \
+ set_bit(bit - ((NCAPINTS+NBUGINTS)*32), \
+ (unsigned long *)&(&boot_cpu_data)->x86_ext_capability[NEXTCAPINTS]); \
+ } else { \
+ set_cpu_cap(&boot_cpu_data, bit); \
+ set_bit(bit, (unsigned long *)cpu_caps_set); \
+ } \
+} while (0)
#if defined(__clang__) && !defined(CONFIG_CC_HAS_ASM_GOTO)
@@ -200,22 +249,34 @@ t_no:
}
#define static_cpu_has(bit) \
-( \
- __builtin_constant_p(boot_cpu_has(bit)) ? \
+({ \
+ BUILD_BUG_ON_MSG((bit >> 5) >= NCAPINTS+NBUGINTS, "extended bits/bugs not supported"); \
+ (__builtin_constant_p(boot_cpu_has(bit)) ? \
boot_cpu_has(bit) : \
- _static_cpu_has(bit) \
-)
+ _static_cpu_has(bit)); \
+})
#endif
-#define cpu_has_bug(c, bit) cpu_has(c, (bit))
-#define set_cpu_bug(c, bit) set_cpu_cap(c, (bit))
+#define cpu_has_bug(c, bit) (IS_EXT_BUG_BIT((bit)) ? test_bit((bit) - ((NCAPINTS+NBUGINTS)*32), \
+ (unsigned long *)(&((c)->x86_ext_capability[NEXTCAPINTS]))) : \
+ test_bit(bit, (unsigned long *)((c)->x86_capability)))
+
+#define set_cpu_bug(c, bit) do { \
+ if (IS_EXT_BUG_BIT(bit)) { \
+ set_bit(bit - ((NCAPINTS+NBUGINTS)*32), \
+ (unsigned long *)(&((c)->x86_ext_capability[NEXTCAPINTS]))); \
+ } else { \
+ set_bit(bit, (unsigned long *)((c)->x86_capability)); \
+ } \
+} while (0)
+
#define clear_cpu_bug(c, bit) clear_cpu_cap(c, (bit))
#define static_cpu_has_bug(bit) static_cpu_has((bit))
#define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit))
-#define boot_cpu_set_bug(bit) set_cpu_cap(&boot_cpu_data, (bit))
+#define boot_cpu_set_bug(bit) set_cpu_bug(&boot_cpu_data, (bit))
-#define MAX_CPU_FEATURES (NCAPINTS * 32)
+#define MAX_CPU_FEATURES ((NCAPINTS + NEXTCAPINTS)* 32)
#define cpu_have_feature boot_cpu_has
#define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X"
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -15,7 +15,8 @@
*/
#define NCAPINTS 22 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */
-
+#define NEXTCAPINTS 1 /* N 32-bit words which come after NCAPINTS */
+#define NEXTBUGINTS 1 /* N 32-bit extended bug flags */
/*
* Note: If the comment begins with a quoted string, that string is used
* in /proc/cpuinfo instead of the macro name. If the string is "",
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -143,6 +143,7 @@ struct cpuinfo_x86 {
#ifndef __GENKSYMS__
/* protected processor identification number */
u64 ppin;
+ __u32 x86_ext_capability[NEXTCAPINTS+NEXTBUGINTS];
#endif
} __randomize_layout;
@@ -177,7 +178,7 @@ extern struct cpuinfo_x86 boot_cpu_data;
extern struct cpuinfo_x86 new_cpu_data;
extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS];
-extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS];
+extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS + NEXTCAPINTS + NEXTBUGINTS];
#ifdef CONFIG_SMP
DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -388,7 +388,7 @@ void __init_or_module noinline apply_alt
instr = (u8 *)&a->instr_offset + a->instr_offset;
replacement = (u8 *)&a->repl_offset + a->repl_offset;
BUG_ON(a->instrlen > sizeof(insn_buff));
- BUG_ON(feature >= (NCAPINTS + NBUGINTS) * 32);
+ BUG_ON(feature >= (NCAPINTS + NBUGINTS + NEXTCAPINTS + NEXTBUGINTS) * 32);
/*
* Patch if either:
@@ -396,7 +396,8 @@ void __init_or_module noinline apply_alt
* - feature not present but ALTINSTR_FLAG_INV is set to mean,
* patch if feature is *NOT* present.
*/
- if (!boot_cpu_has(feature) == !(a->cpuid & ALTINSTR_FLAG_INV)) {
+ if ((a->cpuid < NCAPINTS && (!boot_cpu_has(feature) == !(a->cpuid & ALTINSTR_FLAG_INV)))
+ || (a->cpuid > NCAPINTS && (!boot_cpu_has_bug(feature) == !(a->cpuid & ALTINSTR_FLAG_INV)))) {
optimize_nops_inplace(instr, a->instrlen);
continue;
}
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -678,7 +678,7 @@ static const char *table_lookup_model(st
/* Aligned to unsigned long to avoid split lock in atomic bitmap ops */
__u32 cpu_caps_cleared[NCAPINTS + NBUGINTS] __aligned(sizeof(unsigned long));
-__u32 cpu_caps_set[NCAPINTS + NBUGINTS] __aligned(sizeof(unsigned long));
+__u32 cpu_caps_set[NCAPINTS + NBUGINTS + NEXTCAPINTS + NEXTBUGINTS] __aligned(sizeof(unsigned long));
void load_percpu_segment(int cpu)
{
@@ -940,6 +940,11 @@ static void apply_forced_caps(struct cpu
c->x86_capability[i] &= ~cpu_caps_cleared[i];
c->x86_capability[i] |= cpu_caps_set[i];
}
+
+ for (i = 0; i < NEXTCAPINTS + NEXTBUGINTS; i++) {
+ c->x86_ext_capability[i] |= cpu_caps_set[NCAPINTS+NBUGINTS + i];
+ }
+
}
static void init_speculation_control(struct cpuinfo_x86 *c)
--- a/arch/x86/kernel/cpu/mkcapflags.sh
+++ b/arch/x86/kernel/cpu/mkcapflags.sh
@@ -57,10 +57,10 @@ trap 'rm "$OUT"' EXIT
echo "#endif"
echo ""
- dump_array "x86_cap_flags" "NCAPINTS*32" "X86_FEATURE_" "" $2
+ dump_array "x86_cap_flags" "(NCAPINTS+NEXTCAPINTS)*32" "X86_FEATURE_" "" $2
echo ""
- dump_array "x86_bug_flags" "NBUGINTS*32" "X86_BUG_" "NCAPINTS*32" $2
+ dump_array "x86_bug_flags" "(NBUGINTS+NEXTBUGINTS)*32" "X86_BUG_" "NCAPINTS*32" $2
echo ""
echo "#ifdef CONFIG_X86_VMX_FEATURE_NAMES"
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -102,7 +102,7 @@ static int show_cpuinfo(struct seq_file
show_cpuinfo_misc(m, c);
seq_puts(m, "flags\t\t:");
- for (i = 0; i < 32*NCAPINTS; i++)
+ for (i = 0; i < 32*(NCAPINTS+NEXTCAPINTS); i++)
if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
seq_printf(m, " %s", x86_cap_flags[i]);
@@ -118,7 +118,7 @@ static int show_cpuinfo(struct seq_file
#endif
seq_puts(m, "\nbugs\t\t:");
- for (i = 0; i < 32*NBUGINTS; i++) {
+ for (i = 0; i < 32*(NBUGINTS+NEXTBUGINTS); i++) {
unsigned int bug_bit = 32*NCAPINTS + i;
if (cpu_has_bug(c, bug_bit) && x86_bug_flags[i])