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 <chuck.anderson@oracle.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
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)
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);
}
}
-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;
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)
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)
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;
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 */
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);
}
}
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();
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];
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;