xref: /openbmc/linux/arch/x86/kernel/cpu/feat_ctl.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11db2a6e1SSean Christopherson // SPDX-License-Identifier: GPL-2.0
21db2a6e1SSean Christopherson #include <linux/tboot.h>
31db2a6e1SSean Christopherson 
4*30ea703aSLuciano Leão #include <asm/cpu.h>
51db2a6e1SSean Christopherson #include <asm/cpufeature.h>
61db2a6e1SSean Christopherson #include <asm/msr-index.h>
71db2a6e1SSean Christopherson #include <asm/processor.h>
8b47ce1feSSean Christopherson #include <asm/vmx.h>
91db2a6e1SSean Christopherson 
10ef4d3bf1SSean Christopherson #undef pr_fmt
11ef4d3bf1SSean Christopherson #define pr_fmt(fmt)	"x86/cpu: " fmt
12ef4d3bf1SSean Christopherson 
13b47ce1feSSean Christopherson #ifdef CONFIG_X86_VMX_FEATURE_NAMES
14b47ce1feSSean Christopherson enum vmx_feature_leafs {
15b47ce1feSSean Christopherson 	MISC_FEATURES = 0,
16b47ce1feSSean Christopherson 	PRIMARY_CTLS,
17b47ce1feSSean Christopherson 	SECONDARY_CTLS,
18465932dbSRobert Hoo 	TERTIARY_CTLS_LOW,
19465932dbSRobert Hoo 	TERTIARY_CTLS_HIGH,
20b47ce1feSSean Christopherson 	NR_VMX_FEATURE_WORDS,
21b47ce1feSSean Christopherson };
22b47ce1feSSean Christopherson 
23b47ce1feSSean Christopherson #define VMX_F(x) BIT(VMX_FEATURE_##x & 0x1f)
24b47ce1feSSean Christopherson 
init_vmx_capabilities(struct cpuinfo_x86 * c)25b47ce1feSSean Christopherson static void init_vmx_capabilities(struct cpuinfo_x86 *c)
26b47ce1feSSean Christopherson {
27465932dbSRobert Hoo 	u32 supported, funcs, ept, vpid, ign, low, high;
28b47ce1feSSean Christopherson 
29b47ce1feSSean Christopherson 	BUILD_BUG_ON(NVMXINTS != NR_VMX_FEATURE_WORDS);
30b47ce1feSSean Christopherson 
31b47ce1feSSean Christopherson 	/*
32b47ce1feSSean Christopherson 	 * The high bits contain the allowed-1 settings, i.e. features that can
33b47ce1feSSean Christopherson 	 * be turned on.  The low bits contain the allowed-0 settings, i.e.
34b47ce1feSSean Christopherson 	 * features that can be turned off.  Ignore the allowed-0 settings,
35b47ce1feSSean Christopherson 	 * if a feature can be turned on then it's supported.
36b47ce1feSSean Christopherson 	 *
37b47ce1feSSean Christopherson 	 * Use raw rdmsr() for primary processor controls and pin controls MSRs
38b47ce1feSSean Christopherson 	 * as they exist on any CPU that supports VMX, i.e. we want the WARN if
39b47ce1feSSean Christopherson 	 * the RDMSR faults.
40b47ce1feSSean Christopherson 	 */
41b47ce1feSSean Christopherson 	rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, ign, supported);
42b47ce1feSSean Christopherson 	c->vmx_capability[PRIMARY_CTLS] = supported;
43b47ce1feSSean Christopherson 
44b47ce1feSSean Christopherson 	rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &ign, &supported);
45b47ce1feSSean Christopherson 	c->vmx_capability[SECONDARY_CTLS] = supported;
46b47ce1feSSean Christopherson 
47465932dbSRobert Hoo 	/* All 64 bits of tertiary controls MSR are allowed-1 settings. */
48465932dbSRobert Hoo 	rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &low, &high);
49465932dbSRobert Hoo 	c->vmx_capability[TERTIARY_CTLS_LOW] = low;
50465932dbSRobert Hoo 	c->vmx_capability[TERTIARY_CTLS_HIGH] = high;
51465932dbSRobert Hoo 
52b47ce1feSSean Christopherson 	rdmsr(MSR_IA32_VMX_PINBASED_CTLS, ign, supported);
53b47ce1feSSean Christopherson 	rdmsr_safe(MSR_IA32_VMX_VMFUNC, &ign, &funcs);
54b47ce1feSSean Christopherson 
55b47ce1feSSean Christopherson 	/*
56b47ce1feSSean Christopherson 	 * Except for EPT+VPID, which enumerates support for both in a single
57b47ce1feSSean Christopherson 	 * MSR, low for EPT, high for VPID.
58b47ce1feSSean Christopherson 	 */
59b47ce1feSSean Christopherson 	rdmsr_safe(MSR_IA32_VMX_EPT_VPID_CAP, &ept, &vpid);
60b47ce1feSSean Christopherson 
61b47ce1feSSean Christopherson 	/* Pin, EPT, VPID and VM-Func are merged into a single word. */
62b47ce1feSSean Christopherson 	WARN_ON_ONCE(supported >> 16);
63b47ce1feSSean Christopherson 	WARN_ON_ONCE(funcs >> 4);
64b47ce1feSSean Christopherson 	c->vmx_capability[MISC_FEATURES] = (supported & 0xffff) |
65b47ce1feSSean Christopherson 					   ((vpid & 0x1) << 16) |
66b47ce1feSSean Christopherson 					   ((funcs & 0xf) << 28);
67b47ce1feSSean Christopherson 
68b47ce1feSSean Christopherson 	/* EPT bits are full on scattered and must be manually handled. */
69b47ce1feSSean Christopherson 	if (ept & VMX_EPT_EXECUTE_ONLY_BIT)
70b47ce1feSSean Christopherson 		c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_EXECUTE_ONLY);
71b47ce1feSSean Christopherson 	if (ept & VMX_EPT_AD_BIT)
72b47ce1feSSean Christopherson 		c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_AD);
73b47ce1feSSean Christopherson 	if (ept & VMX_EPT_1GB_PAGE_BIT)
74b47ce1feSSean Christopherson 		c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_1GB);
75b47ce1feSSean Christopherson 
76b47ce1feSSean Christopherson 	/* Synthetic APIC features that are aggregates of multiple features. */
77b47ce1feSSean Christopherson 	if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) &&
78b47ce1feSSean Christopherson 	    (c->vmx_capability[SECONDARY_CTLS] & VMX_F(VIRT_APIC_ACCESSES)))
79b47ce1feSSean Christopherson 		c->vmx_capability[MISC_FEATURES] |= VMX_F(FLEXPRIORITY);
80b47ce1feSSean Christopherson 
81b47ce1feSSean Christopherson 	if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) &&
82b47ce1feSSean Christopherson 	    (c->vmx_capability[SECONDARY_CTLS] & VMX_F(APIC_REGISTER_VIRT)) &&
83b47ce1feSSean Christopherson 	    (c->vmx_capability[SECONDARY_CTLS] & VMX_F(VIRT_INTR_DELIVERY)) &&
84b47ce1feSSean Christopherson 	    (c->vmx_capability[MISC_FEATURES] & VMX_F(POSTED_INTR)))
85b47ce1feSSean Christopherson 		c->vmx_capability[MISC_FEATURES] |= VMX_F(APICV);
86167a4894SSean Christopherson 
87167a4894SSean Christopherson 	/* Set the synthetic cpufeatures to preserve /proc/cpuinfo's ABI. */
88167a4894SSean Christopherson 	if (c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR))
89167a4894SSean Christopherson 		set_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
90167a4894SSean Christopherson 	if (c->vmx_capability[MISC_FEATURES] & VMX_F(FLEXPRIORITY))
91167a4894SSean Christopherson 		set_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
92167a4894SSean Christopherson 	if (c->vmx_capability[MISC_FEATURES] & VMX_F(VIRTUAL_NMIS))
93167a4894SSean Christopherson 		set_cpu_cap(c, X86_FEATURE_VNMI);
94167a4894SSean Christopherson 	if (c->vmx_capability[SECONDARY_CTLS] & VMX_F(EPT))
95167a4894SSean Christopherson 		set_cpu_cap(c, X86_FEATURE_EPT);
96167a4894SSean Christopherson 	if (c->vmx_capability[MISC_FEATURES] & VMX_F(EPT_AD))
97167a4894SSean Christopherson 		set_cpu_cap(c, X86_FEATURE_EPT_AD);
98167a4894SSean Christopherson 	if (c->vmx_capability[MISC_FEATURES] & VMX_F(VPID))
99167a4894SSean Christopherson 		set_cpu_cap(c, X86_FEATURE_VPID);
100b47ce1feSSean Christopherson }
101b47ce1feSSean Christopherson #endif /* CONFIG_X86_VMX_FEATURE_NAMES */
102b47ce1feSSean Christopherson 
nosgx(char * str)10338853a30SJarkko Sakkinen static int __init nosgx(char *str)
10438853a30SJarkko Sakkinen {
105e9a15a40SKai Huang 	setup_clear_cpu_cap(X86_FEATURE_SGX);
10638853a30SJarkko Sakkinen 
10738853a30SJarkko Sakkinen 	return 0;
10838853a30SJarkko Sakkinen }
10938853a30SJarkko Sakkinen 
11038853a30SJarkko Sakkinen early_param("nosgx", nosgx);
11138853a30SJarkko Sakkinen 
init_ia32_feat_ctl(struct cpuinfo_x86 * c)1121db2a6e1SSean Christopherson void init_ia32_feat_ctl(struct cpuinfo_x86 *c)
1131db2a6e1SSean Christopherson {
114332bfc7bSSean Christopherson 	bool enable_sgx_kvm = false, enable_sgx_driver = false;
115ef4d3bf1SSean Christopherson 	bool tboot = tboot_enabled();
116332bfc7bSSean Christopherson 	bool enable_vmx;
1171db2a6e1SSean Christopherson 	u64 msr;
1181db2a6e1SSean Christopherson 
119ef4d3bf1SSean Christopherson 	if (rdmsrl_safe(MSR_IA32_FEAT_CTL, &msr)) {
120ef4d3bf1SSean Christopherson 		clear_cpu_cap(c, X86_FEATURE_VMX);
121e9a15a40SKai Huang 		clear_cpu_cap(c, X86_FEATURE_SGX);
1221db2a6e1SSean Christopherson 		return;
123ef4d3bf1SSean Christopherson 	}
1241db2a6e1SSean Christopherson 
125332bfc7bSSean Christopherson 	enable_vmx = cpu_has(c, X86_FEATURE_VMX) &&
126332bfc7bSSean Christopherson 		     IS_ENABLED(CONFIG_KVM_INTEL);
127332bfc7bSSean Christopherson 
128332bfc7bSSean Christopherson 	if (cpu_has(c, X86_FEATURE_SGX) && IS_ENABLED(CONFIG_X86_SGX)) {
129224ab352SSean Christopherson 		/*
130332bfc7bSSean Christopherson 		 * Separate out SGX driver enabling from KVM.  This allows KVM
131332bfc7bSSean Christopherson 		 * guests to use SGX even if the kernel SGX driver refuses to
132332bfc7bSSean Christopherson 		 * use it.  This happens if flexible Launch Control is not
133332bfc7bSSean Christopherson 		 * available.
134224ab352SSean Christopherson 		 */
135332bfc7bSSean Christopherson 		enable_sgx_driver = cpu_has(c, X86_FEATURE_SGX_LC);
136332bfc7bSSean Christopherson 		enable_sgx_kvm = enable_vmx && IS_ENABLED(CONFIG_X86_SGX_KVM);
137332bfc7bSSean Christopherson 	}
138224ab352SSean Christopherson 
1391db2a6e1SSean Christopherson 	if (msr & FEAT_CTL_LOCKED)
140ef4d3bf1SSean Christopherson 		goto update_caps;
1411db2a6e1SSean Christopherson 
1421db2a6e1SSean Christopherson 	/*
1431db2a6e1SSean Christopherson 	 * Ignore whatever value BIOS left in the MSR to avoid enabling random
1441db2a6e1SSean Christopherson 	 * features or faulting on the WRMSR.
1451db2a6e1SSean Christopherson 	 */
1461db2a6e1SSean Christopherson 	msr = FEAT_CTL_LOCKED;
1471db2a6e1SSean Christopherson 
1481db2a6e1SSean Christopherson 	/*
1491db2a6e1SSean Christopherson 	 * Enable VMX if and only if the kernel may do VMXON at some point,
1501db2a6e1SSean Christopherson 	 * i.e. KVM is enabled, to avoid unnecessarily adding an attack vector
1511db2a6e1SSean Christopherson 	 * for the kernel, e.g. using VMX to hide malicious code.
1521db2a6e1SSean Christopherson 	 */
153332bfc7bSSean Christopherson 	if (enable_vmx) {
1541db2a6e1SSean Christopherson 		msr |= FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX;
1551db2a6e1SSean Christopherson 
156ef4d3bf1SSean Christopherson 		if (tboot)
1571db2a6e1SSean Christopherson 			msr |= FEAT_CTL_VMX_ENABLED_INSIDE_SMX;
1581db2a6e1SSean Christopherson 	}
1591db2a6e1SSean Christopherson 
160332bfc7bSSean Christopherson 	if (enable_sgx_kvm || enable_sgx_driver) {
161332bfc7bSSean Christopherson 		msr |= FEAT_CTL_SGX_ENABLED;
162332bfc7bSSean Christopherson 		if (enable_sgx_driver)
163332bfc7bSSean Christopherson 			msr |= FEAT_CTL_SGX_LC_ENABLED;
164332bfc7bSSean Christopherson 	}
165224ab352SSean Christopherson 
1661db2a6e1SSean Christopherson 	wrmsrl(MSR_IA32_FEAT_CTL, msr);
167ef4d3bf1SSean Christopherson 
168ef4d3bf1SSean Christopherson update_caps:
16985c17291SSean Christopherson 	set_cpu_cap(c, X86_FEATURE_MSR_IA32_FEAT_CTL);
17085c17291SSean Christopherson 
171ef4d3bf1SSean Christopherson 	if (!cpu_has(c, X86_FEATURE_VMX))
172224ab352SSean Christopherson 		goto update_sgx;
173ef4d3bf1SSean Christopherson 
174ef4d3bf1SSean Christopherson 	if ( (tboot && !(msr & FEAT_CTL_VMX_ENABLED_INSIDE_SMX)) ||
175ef4d3bf1SSean Christopherson 	    (!tboot && !(msr & FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX))) {
176bb02e2cbSSean Christopherson 		if (IS_ENABLED(CONFIG_KVM_INTEL))
177ef4d3bf1SSean Christopherson 			pr_err_once("VMX (%s TXT) disabled by BIOS\n",
178ef4d3bf1SSean Christopherson 				    tboot ? "inside" : "outside");
179ef4d3bf1SSean Christopherson 		clear_cpu_cap(c, X86_FEATURE_VMX);
180b47ce1feSSean Christopherson 	} else {
181b47ce1feSSean Christopherson #ifdef CONFIG_X86_VMX_FEATURE_NAMES
182b47ce1feSSean Christopherson 		init_vmx_capabilities(c);
183b47ce1feSSean Christopherson #endif
184ef4d3bf1SSean Christopherson 	}
185224ab352SSean Christopherson 
186224ab352SSean Christopherson update_sgx:
187332bfc7bSSean Christopherson 	if (!(msr & FEAT_CTL_SGX_ENABLED)) {
188332bfc7bSSean Christopherson 		if (enable_sgx_kvm || enable_sgx_driver)
189332bfc7bSSean Christopherson 			pr_err_once("SGX disabled by BIOS.\n");
190e9a15a40SKai Huang 		clear_cpu_cap(c, X86_FEATURE_SGX);
191332bfc7bSSean Christopherson 		return;
192332bfc7bSSean Christopherson 	}
193332bfc7bSSean Christopherson 
194332bfc7bSSean Christopherson 	/*
195332bfc7bSSean Christopherson 	 * VMX feature bit may be cleared due to being disabled in BIOS,
196332bfc7bSSean Christopherson 	 * in which case SGX virtualization cannot be supported either.
197332bfc7bSSean Christopherson 	 */
198332bfc7bSSean Christopherson 	if (!cpu_has(c, X86_FEATURE_VMX) && enable_sgx_kvm) {
199332bfc7bSSean Christopherson 		pr_err_once("SGX virtualization disabled due to lack of VMX.\n");
200332bfc7bSSean Christopherson 		enable_sgx_kvm = 0;
201332bfc7bSSean Christopherson 	}
202332bfc7bSSean Christopherson 
203332bfc7bSSean Christopherson 	if (!(msr & FEAT_CTL_SGX_LC_ENABLED) && enable_sgx_driver) {
204332bfc7bSSean Christopherson 		if (!enable_sgx_kvm) {
205332bfc7bSSean Christopherson 			pr_err_once("SGX Launch Control is locked. Disable SGX.\n");
206332bfc7bSSean Christopherson 			clear_cpu_cap(c, X86_FEATURE_SGX);
207332bfc7bSSean Christopherson 		} else {
208332bfc7bSSean Christopherson 			pr_err_once("SGX Launch Control is locked. Support SGX virtualization only.\n");
209332bfc7bSSean Christopherson 			clear_cpu_cap(c, X86_FEATURE_SGX_LC);
210332bfc7bSSean Christopherson 		}
211224ab352SSean Christopherson 	}
2121db2a6e1SSean Christopherson }
213