[PATCH v5 11/18] kvm/vmx: Emulate MSR TEST_CTL

From: Fenghua Yu
Date: Tue Mar 12 2019 - 19:11:02 EST


From: Xiaoyao Li <xiaoyao.li@xxxxxxxxxxxxxxx>

A control bit (bit 29) in TEST_CTL MSR 0x33 will be introduced in
future x86 processors. When bit 29 is set, the processor causes #AC
exception for split locked accesses at all CPL.

Please check the latest Intel 64 and IA-32 Architectures Software
Developer's Manual for more detailed information on the MSR and
the split lock bit.

This patch emulate MSR TEST_CTL with vmx->msr_test_ctl and does the
following:
1. As we emulate MSR TEST_CTL of guest, we should enable the related bits
in CORE_CAPABILITY to corretly report this feature to guest.

2. Differentiate MSR TEST_CTL between host and guest.

Signed-off-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxxxxxxxx>
Signed-off-by: Fenghua Yu <fenghua.yu@xxxxxxxxx>
---
arch/x86/kvm/vmx/vmx.c | 35 +++++++++++++++++++++++++++++++++++
arch/x86/kvm/vmx/vmx.h | 1 +
arch/x86/kvm/x86.c | 17 ++++++++++++++++-
3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 30a6bcd735ec..270c6566fd5a 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1659,6 +1659,12 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
u32 index;

switch (msr_info->index) {
+ case MSR_TEST_CTL:
+ if (!msr_info->host_initiated &&
+ !(vcpu->arch.core_capability & CORE_CAP_SPLIT_LOCK_DETECT))
+ return 1;
+ msr_info->data = vmx->msr_test_ctl;
+ break;
#ifdef CONFIG_X86_64
case MSR_FS_BASE:
msr_info->data = vmcs_readl(GUEST_FS_BASE);
@@ -1799,6 +1805,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
u32 index;

switch (msr_index) {
+ case MSR_TEST_CTL:
+ if (!(vcpu->arch.core_capability & CORE_CAP_SPLIT_LOCK_DETECT))
+ return 1;
+
+ if (data & ~TEST_CTL_ENABLE_SPLIT_LOCK_DETECT)
+ return 1;
+ vmx->msr_test_ctl = data;
+ break;
case MSR_EFER:
ret = kvm_set_msr_common(vcpu, msr_info);
break;
@@ -4085,6 +4099,9 @@ static void vmx_vcpu_setup(struct vcpu_vmx *vmx)

vmx->arch_capabilities = kvm_get_arch_capabilities();

+ /* disable AC split lock by default */
+ vmx->msr_test_ctl = 0;
+
vm_exit_controls_init(vmx, vmx_vmexit_ctrl());

/* 22.2.1, 20.8.1 */
@@ -4122,6 +4139,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)

vmx->rmode.vm86_active = 0;
vmx->spec_ctrl = 0;
+ vmx->msr_test_ctl = 0;

vcpu->arch.microcode_version = 0x100000000ULL;
vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val();
@@ -6321,6 +6339,21 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
msrs[i].host, false);
}

+static void atomic_switch_msr_test_ctl(struct vcpu_vmx *vmx)
+{
+ u64 host_msr_test_ctl;
+
+ /* if TEST_CTL MSR doesn't exist on the hardware, we do nothing */
+ if (rdmsrl_safe(MSR_TEST_CTL, &host_msr_test_ctl))
+ return;
+
+ if (host_msr_test_ctl == vmx->msr_test_ctl)
+ clear_atomic_switch_msr(vmx, MSR_TEST_CTL);
+ else
+ add_atomic_switch_msr(vmx, MSR_TEST_CTL, vmx->msr_test_ctl,
+ host_msr_test_ctl, false);
+}
+
static void vmx_arm_hv_timer(struct vcpu_vmx *vmx, u32 val)
{
vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, val);
@@ -6562,6 +6595,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)

atomic_switch_perf_msrs(vmx);

+ atomic_switch_msr_test_ctl(vmx);
+
vmx_update_hv_timer(vcpu);

/*
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index 0ac0a64c7790..8549cba0fb75 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -191,6 +191,7 @@ struct vcpu_vmx {
u64 msr_guest_kernel_gs_base;
#endif

+ u64 msr_test_ctl;
u64 arch_capabilities;
u64 spec_ctrl;

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e20cbb8c2b74..ad1df965574e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1228,7 +1228,22 @@ EXPORT_SYMBOL_GPL(kvm_get_arch_capabilities);

u64 kvm_get_core_capability(void)
{
- return 0;
+ u64 data;
+
+ rdmsrl_safe(MSR_IA32_CORE_CAPABILITY, &data);
+
+ /* mask non-virtualizable functions */
+ data &= CORE_CAP_SPLIT_LOCK_DETECT;
+
+ /*
+ * There will be a list of FMS values that have split lock detection
+ * but lack the CORE CAPABILITY MSR. In this case, we can set
+ * CORE_CAP_SPLIT_LOCK_DETECT since we emulate MSR CORE_CAPABILITY.
+ */
+ if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
+ data |= CORE_CAP_SPLIT_LOCK_DETECT;
+
+ return data;
}
EXPORT_SYMBOL_GPL(kvm_get_core_capability);

--
2.19.1