2019-12-21 04:44:58 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/tboot.h>
|
|
|
|
|
|
|
|
#include <asm/cpufeature.h>
|
|
|
|
#include <asm/msr-index.h>
|
|
|
|
#include <asm/processor.h>
|
2019-12-21 04:45:04 +00:00
|
|
|
#include <asm/vmx.h>
|
2020-03-23 10:59:34 +00:00
|
|
|
#include "cpu.h"
|
2019-12-21 04:44:58 +00:00
|
|
|
|
2019-12-21 04:45:02 +00:00
|
|
|
#undef pr_fmt
|
|
|
|
#define pr_fmt(fmt) "x86/cpu: " fmt
|
|
|
|
|
2019-12-21 04:45:04 +00:00
|
|
|
#ifdef CONFIG_X86_VMX_FEATURE_NAMES
|
|
|
|
enum vmx_feature_leafs {
|
|
|
|
MISC_FEATURES = 0,
|
|
|
|
PRIMARY_CTLS,
|
|
|
|
SECONDARY_CTLS,
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
2019-12-21 04:45:06 +00:00
|
|
|
|
|
|
|
/* 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);
|
2019-12-21 04:45:04 +00:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_X86_VMX_FEATURE_NAMES */
|
|
|
|
|
2019-12-21 04:44:58 +00:00
|
|
|
void init_ia32_feat_ctl(struct cpuinfo_x86 *c)
|
|
|
|
{
|
2019-12-21 04:45:02 +00:00
|
|
|
bool tboot = tboot_enabled();
|
2019-12-21 04:44:58 +00:00
|
|
|
u64 msr;
|
|
|
|
|
2019-12-21 04:45:02 +00:00
|
|
|
if (rdmsrl_safe(MSR_IA32_FEAT_CTL, &msr)) {
|
|
|
|
clear_cpu_cap(c, X86_FEATURE_VMX);
|
2019-12-21 04:44:58 +00:00
|
|
|
return;
|
2019-12-21 04:45:02 +00:00
|
|
|
}
|
2019-12-21 04:44:58 +00:00
|
|
|
|
|
|
|
if (msr & FEAT_CTL_LOCKED)
|
2019-12-21 04:45:02 +00:00
|
|
|
goto update_caps;
|
2019-12-21 04:44:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 (cpu_has(c, X86_FEATURE_VMX) && IS_ENABLED(CONFIG_KVM_INTEL)) {
|
|
|
|
msr |= FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX;
|
|
|
|
|
2019-12-21 04:45:02 +00:00
|
|
|
if (tboot)
|
2019-12-21 04:44:58 +00:00
|
|
|
msr |= FEAT_CTL_VMX_ENABLED_INSIDE_SMX;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrmsrl(MSR_IA32_FEAT_CTL, msr);
|
2019-12-21 04:45:02 +00:00
|
|
|
|
|
|
|
update_caps:
|
x86/cpufeatures: Add flag to track whether MSR IA32_FEAT_CTL is configured
Add a new feature flag, X86_FEATURE_MSR_IA32_FEAT_CTL, to track whether
IA32_FEAT_CTL has been initialized. This will allow KVM, and any future
subsystems that depend on IA32_FEAT_CTL, to rely purely on cpufeatures
to query platform support, e.g. allows a future patch to remove KVM's
manual IA32_FEAT_CTL MSR checks.
Various features (on platforms that support IA32_FEAT_CTL) are dependent
on IA32_FEAT_CTL being configured and locked, e.g. VMX and LMCE. The
MSR is always configured during boot, but only if the CPU vendor is
recognized by the kernel. Because CPUID doesn't incorporate the current
IA32_FEAT_CTL value in its reporting of relevant features, it's possible
for a feature to be reported as supported in cpufeatures but not truly
enabled, e.g. if the CPU supports VMX but the kernel doesn't recognize
the CPU.
As a result, without the flag, KVM would see VMX as supported even if
IA32_FEAT_CTL hasn't been initialized, and so would need to manually
read the MSR and check the various enabling bits to avoid taking an
unexpected #GP on VMXON.
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20191221044513.21680-14-sean.j.christopherson@intel.com
2019-12-21 04:45:07 +00:00
|
|
|
set_cpu_cap(c, X86_FEATURE_MSR_IA32_FEAT_CTL);
|
|
|
|
|
2019-12-21 04:45:02 +00:00
|
|
|
if (!cpu_has(c, X86_FEATURE_VMX))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( (tboot && !(msr & FEAT_CTL_VMX_ENABLED_INSIDE_SMX)) ||
|
|
|
|
(!tboot && !(msr & FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX))) {
|
2020-01-14 20:25:45 +00:00
|
|
|
if (IS_ENABLED(CONFIG_KVM_INTEL))
|
|
|
|
pr_err_once("VMX (%s TXT) disabled by BIOS\n",
|
|
|
|
tboot ? "inside" : "outside");
|
2019-12-21 04:45:02 +00:00
|
|
|
clear_cpu_cap(c, X86_FEATURE_VMX);
|
2019-12-21 04:45:04 +00:00
|
|
|
} else {
|
|
|
|
#ifdef CONFIG_X86_VMX_FEATURE_NAMES
|
|
|
|
init_vmx_capabilities(c);
|
|
|
|
#endif
|
2019-12-21 04:45:02 +00:00
|
|
|
}
|
2019-12-21 04:44:58 +00:00
|
|
|
}
|