diff options
Diffstat (limited to 'arch/x86/kernel/cpu/common.c')
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 51 | 
1 files changed, 43 insertions, 8 deletions
| diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index b3410f1ac217..0083464de5e3 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -42,7 +42,7 @@  #include <asm/setup.h>  #include <asm/apic.h>  #include <asm/desc.h> -#include <asm/fpu/internal.h> +#include <asm/fpu/api.h>  #include <asm/mtrr.h>  #include <asm/hwcap2.h>  #include <linux/numa.h> @@ -85,6 +85,9 @@ u16 get_llc_id(unsigned int cpu)  }  EXPORT_SYMBOL_GPL(get_llc_id); +/* L2 cache ID of each logical CPU */ +DEFINE_PER_CPU_READ_MOSTLY(u16, cpu_l2c_id) = BAD_APICID; +  /* correctly size the local cpu masks */  void __init setup_cpu_local_masks(void)  { @@ -1045,6 +1048,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {  	VULNWL(CENTAUR,	5, X86_MODEL_ANY,	NO_SPECULATION),  	VULNWL(INTEL,	5, X86_MODEL_ANY,	NO_SPECULATION),  	VULNWL(NSC,	5, X86_MODEL_ANY,	NO_SPECULATION), +	VULNWL(VORTEX,	5, X86_MODEL_ANY,	NO_SPECULATION), +	VULNWL(VORTEX,	6, X86_MODEL_ANY,	NO_SPECULATION),  	/* Intel Family 6 */  	VULNWL_INTEL(ATOM_SALTWELL,		NO_SPECULATION | NO_ITLB_MULTIHIT), @@ -1396,9 +1401,8 @@ void __init early_cpu_init(void)  	early_identify_cpu(&boot_cpu_data);  } -static void detect_null_seg_behavior(struct cpuinfo_x86 *c) +static bool detect_null_seg_behavior(void)  { -#ifdef CONFIG_X86_64  	/*  	 * Empirically, writing zero to a segment selector on AMD does  	 * not clear the base, whereas writing zero to a segment @@ -1419,10 +1423,43 @@ static void detect_null_seg_behavior(struct cpuinfo_x86 *c)  	wrmsrl(MSR_FS_BASE, 1);  	loadsegment(fs, 0);  	rdmsrl(MSR_FS_BASE, tmp); -	if (tmp != 0) -		set_cpu_bug(c, X86_BUG_NULL_SEG);  	wrmsrl(MSR_FS_BASE, old_base); -#endif +	return tmp == 0; +} + +void check_null_seg_clears_base(struct cpuinfo_x86 *c) +{ +	/* BUG_NULL_SEG is only relevant with 64bit userspace */ +	if (!IS_ENABLED(CONFIG_X86_64)) +		return; + +	/* Zen3 CPUs advertise Null Selector Clears Base in CPUID. */ +	if (c->extended_cpuid_level >= 0x80000021 && +	    cpuid_eax(0x80000021) & BIT(6)) +		return; + +	/* +	 * CPUID bit above wasn't set. If this kernel is still running +	 * as a HV guest, then the HV has decided not to advertize +	 * that CPUID bit for whatever reason.	For example, one +	 * member of the migration pool might be vulnerable.  Which +	 * means, the bug is present: set the BUG flag and return. +	 */ +	if (cpu_has(c, X86_FEATURE_HYPERVISOR)) { +		set_cpu_bug(c, X86_BUG_NULL_SEG); +		return; +	} + +	/* +	 * Zen2 CPUs also have this behaviour, but no CPUID bit. +	 * 0x18 is the respective family for Hygon. +	 */ +	if ((c->x86 == 0x17 || c->x86 == 0x18) && +	    detect_null_seg_behavior()) +		return; + +	/* All the remaining ones are affected */ +	set_cpu_bug(c, X86_BUG_NULL_SEG);  }  static void generic_identify(struct cpuinfo_x86 *c) @@ -1458,8 +1495,6 @@ static void generic_identify(struct cpuinfo_x86 *c)  	get_model_name(c); /* Default name */ -	detect_null_seg_behavior(c); -  	/*  	 * ESPFIX is a strange bug.  All real CPUs have it.  Paravirt  	 * systems that run Linux at CPL > 0 may or may not have the |