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