mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	x86/cpu: Support AMD Automatic IBRS
The AMD Zen4 core supports a new feature called Automatic IBRS. It is a "set-and-forget" feature that means that, like Intel's Enhanced IBRS, h/w manages its IBRS mitigation resources automatically across CPL transitions. The feature is advertised by CPUID_Fn80000021_EAX bit 8 and is enabled by setting MSR C000_0080 (EFER) bit 21. Enable Automatic IBRS by default if the CPU feature is present. It typically provides greater performance over the incumbent generic retpolines mitigation. Reuse the SPECTRE_V2_EIBRS spectre_v2_mitigation enum. AMD Automatic IBRS and Intel Enhanced IBRS have similar enablement. Add NO_EIBRS_PBRSB to cpu_vuln_whitelist, since AMD Automatic IBRS isn't affected by PBRSB-eIBRS. The kernel command line option spectre_v2=eibrs is used to select AMD Automatic IBRS, if available. Signed-off-by: Kim Phillips <kim.phillips@amd.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Acked-by: Sean Christopherson <seanjc@google.com> Acked-by: Dave Hansen <dave.hansen@linux.intel.com> Link: https://lore.kernel.org/r/20230124163319.2277355-8-kim.phillips@amd.com
This commit is contained in:
		
							parent
							
								
									faabfcb194
								
							
						
					
					
						commit
						e7862eda30
					
				
					 6 changed files with 32 additions and 22 deletions
				
			
		| 
						 | 
					@ -610,9 +610,9 @@ kernel command line.
 | 
				
			||||||
                retpoline,generic       Retpolines
 | 
					                retpoline,generic       Retpolines
 | 
				
			||||||
                retpoline,lfence        LFENCE; indirect branch
 | 
					                retpoline,lfence        LFENCE; indirect branch
 | 
				
			||||||
                retpoline,amd           alias for retpoline,lfence
 | 
					                retpoline,amd           alias for retpoline,lfence
 | 
				
			||||||
                eibrs                   enhanced IBRS
 | 
					                eibrs                   Enhanced/Auto IBRS
 | 
				
			||||||
                eibrs,retpoline         enhanced IBRS + Retpolines
 | 
					                eibrs,retpoline         Enhanced/Auto IBRS + Retpolines
 | 
				
			||||||
                eibrs,lfence            enhanced IBRS + LFENCE
 | 
					                eibrs,lfence            Enhanced/Auto IBRS + LFENCE
 | 
				
			||||||
                ibrs                    use IBRS to protect kernel
 | 
					                ibrs                    use IBRS to protect kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Not specifying this option is equivalent to
 | 
							Not specifying this option is equivalent to
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5729,9 +5729,9 @@
 | 
				
			||||||
			retpoline,generic - Retpolines
 | 
								retpoline,generic - Retpolines
 | 
				
			||||||
			retpoline,lfence  - LFENCE; indirect branch
 | 
								retpoline,lfence  - LFENCE; indirect branch
 | 
				
			||||||
			retpoline,amd     - alias for retpoline,lfence
 | 
								retpoline,amd     - alias for retpoline,lfence
 | 
				
			||||||
			eibrs		  - enhanced IBRS
 | 
								eibrs		  - Enhanced/Auto IBRS
 | 
				
			||||||
			eibrs,retpoline   - enhanced IBRS + Retpolines
 | 
								eibrs,retpoline   - Enhanced/Auto IBRS + Retpolines
 | 
				
			||||||
			eibrs,lfence      - enhanced IBRS + LFENCE
 | 
								eibrs,lfence      - Enhanced/Auto IBRS + LFENCE
 | 
				
			||||||
			ibrs		  - use IBRS to protect kernel
 | 
								ibrs		  - use IBRS to protect kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Not specifying this option is equivalent to
 | 
								Not specifying this option is equivalent to
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -431,6 +431,7 @@
 | 
				
			||||||
#define X86_FEATURE_NO_NESTED_DATA_BP	(20*32+ 0) /* "" No Nested Data Breakpoints */
 | 
					#define X86_FEATURE_NO_NESTED_DATA_BP	(20*32+ 0) /* "" No Nested Data Breakpoints */
 | 
				
			||||||
#define X86_FEATURE_LFENCE_RDTSC	(20*32+ 2) /* "" LFENCE always serializing / synchronizes RDTSC */
 | 
					#define X86_FEATURE_LFENCE_RDTSC	(20*32+ 2) /* "" LFENCE always serializing / synchronizes RDTSC */
 | 
				
			||||||
#define X86_FEATURE_NULL_SEL_CLR_BASE	(20*32+ 6) /* "" Null Selector Clears Base */
 | 
					#define X86_FEATURE_NULL_SEL_CLR_BASE	(20*32+ 6) /* "" Null Selector Clears Base */
 | 
				
			||||||
 | 
					#define X86_FEATURE_AUTOIBRS		(20*32+ 8) /* "" Automatic IBRS */
 | 
				
			||||||
#define X86_FEATURE_NO_SMM_CTL_MSR	(20*32+ 9) /* "" SMM_CTL MSR is not present */
 | 
					#define X86_FEATURE_NO_SMM_CTL_MSR	(20*32+ 9) /* "" SMM_CTL MSR is not present */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@
 | 
				
			||||||
#define _EFER_SVME		12 /* Enable virtualization */
 | 
					#define _EFER_SVME		12 /* Enable virtualization */
 | 
				
			||||||
#define _EFER_LMSLE		13 /* Long Mode Segment Limit Enable */
 | 
					#define _EFER_LMSLE		13 /* Long Mode Segment Limit Enable */
 | 
				
			||||||
#define _EFER_FFXSR		14 /* Enable Fast FXSAVE/FXRSTOR */
 | 
					#define _EFER_FFXSR		14 /* Enable Fast FXSAVE/FXRSTOR */
 | 
				
			||||||
 | 
					#define _EFER_AUTOIBRS		21 /* Enable Automatic IBRS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define EFER_SCE		(1<<_EFER_SCE)
 | 
					#define EFER_SCE		(1<<_EFER_SCE)
 | 
				
			||||||
#define EFER_LME		(1<<_EFER_LME)
 | 
					#define EFER_LME		(1<<_EFER_LME)
 | 
				
			||||||
| 
						 | 
					@ -33,6 +34,7 @@
 | 
				
			||||||
#define EFER_SVME		(1<<_EFER_SVME)
 | 
					#define EFER_SVME		(1<<_EFER_SVME)
 | 
				
			||||||
#define EFER_LMSLE		(1<<_EFER_LMSLE)
 | 
					#define EFER_LMSLE		(1<<_EFER_LMSLE)
 | 
				
			||||||
#define EFER_FFXSR		(1<<_EFER_FFXSR)
 | 
					#define EFER_FFXSR		(1<<_EFER_FFXSR)
 | 
				
			||||||
 | 
					#define EFER_AUTOIBRS		(1<<_EFER_AUTOIBRS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Intel MSRs. Some also available on other CPUs */
 | 
					/* Intel MSRs. Some also available on other CPUs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1238,9 +1238,9 @@ static const char * const spectre_v2_strings[] = {
 | 
				
			||||||
	[SPECTRE_V2_NONE]			= "Vulnerable",
 | 
						[SPECTRE_V2_NONE]			= "Vulnerable",
 | 
				
			||||||
	[SPECTRE_V2_RETPOLINE]			= "Mitigation: Retpolines",
 | 
						[SPECTRE_V2_RETPOLINE]			= "Mitigation: Retpolines",
 | 
				
			||||||
	[SPECTRE_V2_LFENCE]			= "Mitigation: LFENCE",
 | 
						[SPECTRE_V2_LFENCE]			= "Mitigation: LFENCE",
 | 
				
			||||||
	[SPECTRE_V2_EIBRS]			= "Mitigation: Enhanced IBRS",
 | 
						[SPECTRE_V2_EIBRS]			= "Mitigation: Enhanced / Automatic IBRS",
 | 
				
			||||||
	[SPECTRE_V2_EIBRS_LFENCE]		= "Mitigation: Enhanced IBRS + LFENCE",
 | 
						[SPECTRE_V2_EIBRS_LFENCE]		= "Mitigation: Enhanced / Automatic IBRS + LFENCE",
 | 
				
			||||||
	[SPECTRE_V2_EIBRS_RETPOLINE]		= "Mitigation: Enhanced IBRS + Retpolines",
 | 
						[SPECTRE_V2_EIBRS_RETPOLINE]		= "Mitigation: Enhanced / Automatic IBRS + Retpolines",
 | 
				
			||||||
	[SPECTRE_V2_IBRS]			= "Mitigation: IBRS",
 | 
						[SPECTRE_V2_IBRS]			= "Mitigation: IBRS",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1309,7 +1309,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
 | 
				
			||||||
	     cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
 | 
						     cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
 | 
				
			||||||
	     cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
 | 
						     cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
 | 
				
			||||||
	    !boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
 | 
						    !boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
 | 
				
			||||||
		pr_err("%s selected but CPU doesn't have eIBRS. Switching to AUTO select\n",
 | 
							pr_err("%s selected but CPU doesn't have Enhanced or Automatic IBRS. Switching to AUTO select\n",
 | 
				
			||||||
		       mitigation_options[i].option);
 | 
							       mitigation_options[i].option);
 | 
				
			||||||
		return SPECTRE_V2_CMD_AUTO;
 | 
							return SPECTRE_V2_CMD_AUTO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1495,8 +1495,12 @@ static void __init spectre_v2_select_mitigation(void)
 | 
				
			||||||
		pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
 | 
							pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spectre_v2_in_ibrs_mode(mode)) {
 | 
						if (spectre_v2_in_ibrs_mode(mode)) {
 | 
				
			||||||
		x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
 | 
							if (boot_cpu_has(X86_FEATURE_AUTOIBRS)) {
 | 
				
			||||||
		update_spec_ctrl(x86_spec_ctrl_base);
 | 
								msr_set_bit(MSR_EFER, _EFER_AUTOIBRS);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
 | 
				
			||||||
 | 
								update_spec_ctrl(x86_spec_ctrl_base);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (mode) {
 | 
						switch (mode) {
 | 
				
			||||||
| 
						 | 
					@ -1580,8 +1584,8 @@ static void __init spectre_v2_select_mitigation(void)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
 | 
						 * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
 | 
				
			||||||
	 * and Enhanced IBRS protect firmware too, so enable IBRS around
 | 
						 * and Enhanced IBRS protect firmware too, so enable IBRS around
 | 
				
			||||||
	 * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
 | 
						 * firmware calls only when IBRS / Enhanced / Automatic IBRS aren't
 | 
				
			||||||
	 * enabled.
 | 
						 * otherwise enabled.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
 | 
						 * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
 | 
				
			||||||
	 * the user might select retpoline on the kernel command line and if
 | 
						 * the user might select retpoline on the kernel command line and if
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1229,8 +1229,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
 | 
				
			||||||
	VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
 | 
						VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
 | 
						/* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
 | 
				
			||||||
	VULNWL_AMD(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
 | 
						VULNWL_AMD(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB),
 | 
				
			||||||
	VULNWL_HYGON(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
 | 
						VULNWL_HYGON(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Zhaoxin Family 7 */
 | 
						/* Zhaoxin Family 7 */
 | 
				
			||||||
	VULNWL(CENTAUR,	7, X86_MODEL_ANY,	NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO),
 | 
						VULNWL(CENTAUR,	7, X86_MODEL_ANY,	NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO),
 | 
				
			||||||
| 
						 | 
					@ -1341,8 +1341,16 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
 | 
				
			||||||
	   !cpu_has(c, X86_FEATURE_AMD_SSB_NO))
 | 
						   !cpu_has(c, X86_FEATURE_AMD_SSB_NO))
 | 
				
			||||||
		setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS);
 | 
							setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ia32_cap & ARCH_CAP_IBRS_ALL)
 | 
						/*
 | 
				
			||||||
 | 
						 * AMD's AutoIBRS is equivalent to Intel's eIBRS - use the Intel feature
 | 
				
			||||||
 | 
						 * flag and protect from vendor-specific bugs via the whitelist.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if ((ia32_cap & ARCH_CAP_IBRS_ALL) || cpu_has(c, X86_FEATURE_AUTOIBRS)) {
 | 
				
			||||||
		setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED);
 | 
							setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED);
 | 
				
			||||||
 | 
							if (!cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) &&
 | 
				
			||||||
 | 
							    !(ia32_cap & ARCH_CAP_PBRSB_NO))
 | 
				
			||||||
 | 
								setup_force_cpu_bug(X86_BUG_EIBRS_PBRSB);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!cpu_matches(cpu_vuln_whitelist, NO_MDS) &&
 | 
						if (!cpu_matches(cpu_vuln_whitelist, NO_MDS) &&
 | 
				
			||||||
	    !(ia32_cap & ARCH_CAP_MDS_NO)) {
 | 
						    !(ia32_cap & ARCH_CAP_MDS_NO)) {
 | 
				
			||||||
| 
						 | 
					@ -1404,11 +1412,6 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
 | 
				
			||||||
			setup_force_cpu_bug(X86_BUG_RETBLEED);
 | 
								setup_force_cpu_bug(X86_BUG_RETBLEED);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cpu_has(c, X86_FEATURE_IBRS_ENHANCED) &&
 | 
					 | 
				
			||||||
	    !cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) &&
 | 
					 | 
				
			||||||
	    !(ia32_cap & ARCH_CAP_PBRSB_NO))
 | 
					 | 
				
			||||||
		setup_force_cpu_bug(X86_BUG_EIBRS_PBRSB);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
 | 
						if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue