diff options
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
| -rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 62 | 
1 files changed, 55 insertions, 7 deletions
| diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 40bdaea97fe7..c37e66e493bf 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -35,12 +35,10 @@ static void __init spectre_v2_select_mitigation(void);  static void __init ssb_select_mitigation(void);  static void __init l1tf_select_mitigation(void); -/* - * Our boot-time value of the SPEC_CTRL MSR. We read it once so that any - * writes to SPEC_CTRL contain whatever reserved bits have been set. - */ -u64 __ro_after_init x86_spec_ctrl_base; +/* The base value of the SPEC_CTRL MSR that always has to be preserved. */ +u64 x86_spec_ctrl_base;  EXPORT_SYMBOL_GPL(x86_spec_ctrl_base); +static DEFINE_MUTEX(spec_ctrl_mutex);  /*   * The vendor and possibly platform specific bits which can be modified in @@ -312,6 +310,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)  	}  	if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD && +	    boot_cpu_data.x86_vendor != X86_VENDOR_HYGON &&  	    boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {  		pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");  		return SPECTRE_V2_CMD_AUTO; @@ -325,6 +324,46 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)  	return cmd;  } +static bool stibp_needed(void) +{ +	if (spectre_v2_enabled == SPECTRE_V2_NONE) +		return false; + +	if (!boot_cpu_has(X86_FEATURE_STIBP)) +		return false; + +	return true; +} + +static void update_stibp_msr(void *info) +{ +	wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); +} + +void arch_smt_update(void) +{ +	u64 mask; + +	if (!stibp_needed()) +		return; + +	mutex_lock(&spec_ctrl_mutex); +	mask = x86_spec_ctrl_base; +	if (cpu_smt_control == CPU_SMT_ENABLED) +		mask |= SPEC_CTRL_STIBP; +	else +		mask &= ~SPEC_CTRL_STIBP; + +	if (mask != x86_spec_ctrl_base) { +		pr_info("Spectre v2 cross-process SMT mitigation: %s STIBP\n", +				cpu_smt_control == CPU_SMT_ENABLED ? +				"Enabling" : "Disabling"); +		x86_spec_ctrl_base = mask; +		on_each_cpu(update_stibp_msr, NULL, 1); +	} +	mutex_unlock(&spec_ctrl_mutex); +} +  static void __init spectre_v2_select_mitigation(void)  {  	enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); @@ -371,7 +410,8 @@ static void __init spectre_v2_select_mitigation(void)  	return;  retpoline_auto: -	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { +	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD || +	    boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {  	retpoline_amd:  		if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {  			pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n"); @@ -424,6 +464,9 @@ specv2_set_mode:  		setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);  		pr_info("Enabling Restricted Speculation for firmware calls\n");  	} + +	/* Enable STIBP if appropriate */ +	arch_smt_update();  }  #undef pr_fmt @@ -814,6 +857,8 @@ static ssize_t l1tf_show_state(char *buf)  static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,  			       char *buf, unsigned int bug)  { +	int ret; +  	if (!boot_cpu_has_bug(bug))  		return sprintf(buf, "Not affected\n"); @@ -831,10 +876,13 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr  		return sprintf(buf, "Mitigation: __user pointer sanitization\n");  	case X86_BUG_SPECTRE_V2: -		return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], +		ret = sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],  			       boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "",  			       boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", +			       (x86_spec_ctrl_base & SPEC_CTRL_STIBP) ? ", STIBP" : "", +			       boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",  			       spectre_v2_module_string()); +		return ret;  	case X86_BUG_SPEC_STORE_BYPASS:  		return sprintf(buf, "%s\n", ssb_strings[ssb_mode]); |