From: Chuck Anderson Date: Thu, 22 Feb 2018 22:01:24 +0000 (-0800) Subject: retpoline: microcode incorrectly reported as broken during early boot X-Git-Tag: v4.1.12-124.31.3~1110 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=7f500a3ceedcd8e86a68d4eb8019c050d5435168;p=users%2Fjedix%2Flinux-maple.git retpoline: microcode incorrectly reported as broken during early boot init_scattered_cpuid_features() is called on each CPU to set its capabilities based on features enumerated by the cpuid instruction. If the CPU supports IBRS or STIBP, a call is made through bad_spectre_microcode() to detect a microcode level that makes it unsafe to use IBRS as a mitigation for Spectre. A warning is issued if the microcode is unsafe: Intel Spectre v2 broken microcode detected; disabling SPEC_CTRL/IBR init_scattered_cpuid_features() may be called early during boot on the boot CPU. The microcode level from BIOS may be broken, triggering the message above. A subsequent microcode update made during early boot could install a level that is IBRS/STIBP/IPBP safe making the warning message misleading. This patch skips the microcode check during early boot. The check is made during a subsequent call to init_scattered_cpuid_features() after a potential microcode update. Orabug: 27625404 Signed-off-by: Chuck Anderson Reviewed-by: Konrad Rzeszutek Wilk Reviewed-by: Darren Kenny --- diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 1d70864c19b01..7007b2f6a2318 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -153,6 +153,11 @@ extern struct tss_struct doublefault_tss; extern __u32 cpu_caps_cleared[NCAPINTS]; extern __u32 cpu_caps_set[NCAPINTS]; +enum get_cpu_cap_behavior { + GET_CPU_CAP_MINIMUM, + GET_CPU_CAP_FULL, +}; + #ifdef CONFIG_SMP DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info); #define cpu_data(cpu) per_cpu(cpu_info, cpu) @@ -173,7 +178,8 @@ extern void identify_boot_cpu(void); extern void identify_secondary_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); void print_cpu_msr(struct cpuinfo_x86 *); -extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c); +extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c, + enum get_cpu_cap_behavior behavior); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); extern void init_amd_cacheinfo(struct cpuinfo_x86 *c); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 4dbac25c0aec1..73ada6d460046 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -682,7 +682,7 @@ void cpu_detect(struct cpuinfo_x86 *c) } } -void get_cpu_cap(struct cpuinfo_x86 *c) +void get_cpu_cap(struct cpuinfo_x86 *c, enum get_cpu_cap_behavior behavior) { u32 tfms, xlvl; u32 ebx; @@ -772,7 +772,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c) if (c->extended_cpuid_level >= 0x80000007) c->x86_power = cpuid_edx(0x80000007); - init_scattered_cpuid_features(c); + init_scattered_cpuid_features(c, behavior); } static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) @@ -870,7 +870,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) cpu_detect(c); get_cpu_vendor(c); - get_cpu_cap(c); + get_cpu_cap(c, GET_CPU_CAP_MINIMUM); fpu_detect(c); if (this_cpu->c_early_init) @@ -959,7 +959,7 @@ static void generic_identify(struct cpuinfo_x86 *c) get_cpu_vendor(c); - get_cpu_cap(c); + get_cpu_cap(c, GET_CPU_CAP_FULL); if (c->cpuid_level >= 0x00000001) { c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF; diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index c37dc37e8317f..ac7c209e289bb 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -43,6 +43,7 @@ struct _tlb_table { extern const struct cpu_dev *const __x86_cpu_dev_start[], *const __x86_cpu_dev_end[]; -extern void get_cpu_cap(struct cpuinfo_x86 *c); +extern void get_cpu_cap(struct cpuinfo_x86 *c, + enum get_cpu_cap_behavior behavior); extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c); #endif /* ARCH_X86_CPU_H */ diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 50163fa9034f0..23f86bde85d17 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -34,7 +34,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) if (msr_clear_bit(MSR_IA32_MISC_ENABLE, MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) > 0) { c->cpuid_level = cpuid_eax(0); - get_cpu_cap(c); + get_cpu_cap(c, GET_CPU_CAP_FULL); } } diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 2f83c508c1ccd..808f33974cd36 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -233,7 +233,7 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, perf_check_microcode(); /* check spec_ctrl capabilities */ - init_scattered_cpuid_features(&boot_cpu_data); + init_scattered_cpuid_features(&boot_cpu_data, GET_CPU_CAP_FULL); mutex_unlock(µcode_mutex); put_online_cpus(); diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 39e16bb62490a..67a1ea0173d03 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -86,7 +86,8 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) return false; } -void init_scattered_cpuid_features(struct cpuinfo_x86 *c) +void init_scattered_cpuid_features(struct cpuinfo_x86 *c, + enum get_cpu_cap_behavior behavior) { u32 max_level; u32 regs[4]; @@ -150,6 +151,9 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_IBRS)) set_cpu_cap(c, X86_FEATURE_IBPB); + if (behavior == GET_CPU_CAP_MINIMUM) + return; + if (!c->cpu_index) { bool ignore = false;