Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | // SPDX-License-Identifier: GPL-2.0 #include <linux/tboot.h> #include <asm/cpu.h> #include <asm/cpufeature.h> #include <asm/msr-index.h> #include <asm/processor.h> #include <asm/vmx.h> #undef pr_fmt #define pr_fmt(fmt) "x86/cpu: " fmt #ifdef CONFIG_X86_VMX_FEATURE_NAMES enum vmx_feature_leafs { MISC_FEATURES = 0, PRIMARY_CTLS, SECONDARY_CTLS, TERTIARY_CTLS_LOW, TERTIARY_CTLS_HIGH, NR_VMX_FEATURE_WORDS, }; #define VMX_F(x) BIT(VMX_FEATURE_##x & 0x1f) static void init_vmx_capabilities(struct cpuinfo_x86 *c) { u32 supported, funcs, ept, vpid, ign, low, high; BUILD_BUG_ON(NVMXINTS != NR_VMX_FEATURE_WORDS); /* * The high bits contain the allowed-1 settings, i.e. features that can * be turned on. The low bits contain the allowed-0 settings, i.e. * features that can be turned off. Ignore the allowed-0 settings, * if a feature can be turned on then it's supported. * * Use raw rdmsr() for primary processor controls and pin controls MSRs * as they exist on any CPU that supports VMX, i.e. we want the WARN if * the RDMSR faults. */ rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, ign, supported); c->vmx_capability[PRIMARY_CTLS] = supported; rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &ign, &supported); c->vmx_capability[SECONDARY_CTLS] = supported; /* All 64 bits of tertiary controls MSR are allowed-1 settings. */ rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &low, &high); c->vmx_capability[TERTIARY_CTLS_LOW] = low; c->vmx_capability[TERTIARY_CTLS_HIGH] = high; rdmsr(MSR_IA32_VMX_PINBASED_CTLS, ign, supported); rdmsr_safe(MSR_IA32_VMX_VMFUNC, &ign, &funcs); /* * Except for EPT+VPID, which enumerates support for both in a single * MSR, low for EPT, high for VPID. */ rdmsr_safe(MSR_IA32_VMX_EPT_VPID_CAP, &ept, &vpid); /* Pin, EPT, VPID and VM-Func are merged into a single word. */ WARN_ON_ONCE(supported >> 16); WARN_ON_ONCE(funcs >> 4); c->vmx_capability[MISC_FEATURES] = (supported & 0xffff) | ((vpid & 0x1) << 16) | ((funcs & 0xf) << 28); /* EPT bits are full on scattered and must be manually handled. */ if (ept & VMX_EPT_EXECUTE_ONLY_BIT) c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_EXECUTE_ONLY); if (ept & VMX_EPT_AD_BIT) c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_AD); if (ept & VMX_EPT_1GB_PAGE_BIT) c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_1GB); /* Synthetic APIC features that are aggregates of multiple features. */ if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) && (c->vmx_capability[SECONDARY_CTLS] & VMX_F(VIRT_APIC_ACCESSES))) c->vmx_capability[MISC_FEATURES] |= VMX_F(FLEXPRIORITY); if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) && (c->vmx_capability[SECONDARY_CTLS] & VMX_F(APIC_REGISTER_VIRT)) && (c->vmx_capability[SECONDARY_CTLS] & VMX_F(VIRT_INTR_DELIVERY)) && (c->vmx_capability[MISC_FEATURES] & VMX_F(POSTED_INTR))) c->vmx_capability[MISC_FEATURES] |= VMX_F(APICV); /* Set the synthetic cpufeatures to preserve /proc/cpuinfo's ABI. */ if (c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) set_cpu_cap(c, X86_FEATURE_TPR_SHADOW); if (c->vmx_capability[MISC_FEATURES] & VMX_F(FLEXPRIORITY)) set_cpu_cap(c, X86_FEATURE_FLEXPRIORITY); if (c->vmx_capability[MISC_FEATURES] & VMX_F(VIRTUAL_NMIS)) set_cpu_cap(c, X86_FEATURE_VNMI); if (c->vmx_capability[SECONDARY_CTLS] & VMX_F(EPT)) set_cpu_cap(c, X86_FEATURE_EPT); if (c->vmx_capability[MISC_FEATURES] & VMX_F(EPT_AD)) set_cpu_cap(c, X86_FEATURE_EPT_AD); if (c->vmx_capability[MISC_FEATURES] & VMX_F(VPID)) set_cpu_cap(c, X86_FEATURE_VPID); } #endif /* CONFIG_X86_VMX_FEATURE_NAMES */ static int __init nosgx(char *str) { setup_clear_cpu_cap(X86_FEATURE_SGX); return 0; } early_param("nosgx", nosgx); void init_ia32_feat_ctl(struct cpuinfo_x86 *c) { bool enable_sgx_kvm = false, enable_sgx_driver = false; bool tboot = tboot_enabled(); bool enable_vmx; u64 msr; if (rdmsrl_safe(MSR_IA32_FEAT_CTL, &msr)) { clear_cpu_cap(c, X86_FEATURE_VMX); clear_cpu_cap(c, X86_FEATURE_SGX); return; } enable_vmx = cpu_has(c, X86_FEATURE_VMX) && IS_ENABLED(CONFIG_KVM_INTEL); if (cpu_has(c, X86_FEATURE_SGX) && IS_ENABLED(CONFIG_X86_SGX)) { /* * Separate out SGX driver enabling from KVM. This allows KVM * guests to use SGX even if the kernel SGX driver refuses to * use it. This happens if flexible Launch Control is not * available. */ enable_sgx_driver = cpu_has(c, X86_FEATURE_SGX_LC); enable_sgx_kvm = enable_vmx && IS_ENABLED(CONFIG_X86_SGX_KVM); } if (msr & FEAT_CTL_LOCKED) goto update_caps; /* * Ignore whatever value BIOS left in the MSR to avoid enabling random * features or faulting on the WRMSR. */ msr = FEAT_CTL_LOCKED; /* * Enable VMX if and only if the kernel may do VMXON at some point, * i.e. KVM is enabled, to avoid unnecessarily adding an attack vector * for the kernel, e.g. using VMX to hide malicious code. */ if (enable_vmx) { msr |= FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX; if (tboot) msr |= FEAT_CTL_VMX_ENABLED_INSIDE_SMX; } if (enable_sgx_kvm || enable_sgx_driver) { msr |= FEAT_CTL_SGX_ENABLED; if (enable_sgx_driver) msr |= FEAT_CTL_SGX_LC_ENABLED; } wrmsrl(MSR_IA32_FEAT_CTL, msr); update_caps: set_cpu_cap(c, X86_FEATURE_MSR_IA32_FEAT_CTL); if (!cpu_has(c, X86_FEATURE_VMX)) goto update_sgx; if ( (tboot && !(msr & FEAT_CTL_VMX_ENABLED_INSIDE_SMX)) || (!tboot && !(msr & FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX))) { if (IS_ENABLED(CONFIG_KVM_INTEL)) pr_err_once("VMX (%s TXT) disabled by BIOS\n", tboot ? "inside" : "outside"); clear_cpu_cap(c, X86_FEATURE_VMX); } else { #ifdef CONFIG_X86_VMX_FEATURE_NAMES init_vmx_capabilities(c); #endif } update_sgx: if (!(msr & FEAT_CTL_SGX_ENABLED)) { if (enable_sgx_kvm || enable_sgx_driver) pr_err_once("SGX disabled by BIOS.\n"); clear_cpu_cap(c, X86_FEATURE_SGX); return; } /* * VMX feature bit may be cleared due to being disabled in BIOS, * in which case SGX virtualization cannot be supported either. */ if (!cpu_has(c, X86_FEATURE_VMX) && enable_sgx_kvm) { pr_err_once("SGX virtualization disabled due to lack of VMX.\n"); enable_sgx_kvm = 0; } if (!(msr & FEAT_CTL_SGX_LC_ENABLED) && enable_sgx_driver) { if (!enable_sgx_kvm) { pr_err_once("SGX Launch Control is locked. Disable SGX.\n"); clear_cpu_cap(c, X86_FEATURE_SGX); } else { pr_err_once("SGX Launch Control is locked. Support SGX virtualization only.\n"); clear_cpu_cap(c, X86_FEATURE_SGX_LC); } } } |