6a9158e
From: Roman Kagan <rkagan@virtuozzo.com>
6a9158e
Subject: [PATCH v3] kvm:vmx: more complete state update on APICv on/off
6a9158e
Date: 2016-05-18 14:48:20 GMT (1 day, 21 hours and 23 minutes ago)
6a9158e
6a9158e
The function to update APICv on/off state (in particular, to deactivate
6a9158e
it when enabling Hyper-V SynIC), used to be incomplete: it didn't adjust
6a9158e
APICv-related fields among secondary processor-based VM-execution
6a9158e
controls.
6a9158e
6a9158e
As a result, Windows 2012 guests would get stuck when SynIC-based
6a9158e
auto-EOI interrupt intersected with e.g. an IPI in the guest.
6a9158e
6a9158e
In addition, the MSR intercept bitmap wasn't updated to correspond to
6a9158e
whether "virtualize x2APIC mode" was enabled.  This path used not to be
6a9158e
triggered, since Windows didn't use x2APIC but rather their own
6a9158e
synthetic APIC access MSRs; however it represented a security risk
6a9158e
because the guest running in a SynIC-enabled VM could switch to x2APIC
6a9158e
and thus obtain direct access to host APIC MSRs (thanks to Yang Zhang
6a9158e
<yang.zhang.wz@gmail.com> for spotting this).
6a9158e
6a9158e
The patch fixes those omissions.
6a9158e
6a9158e
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
6a9158e
Cc: Steve Rutherford <srutherford@google.com>
6a9158e
Cc: Yang Zhang <yang.zhang.wz@gmail.com>
6a9158e
---
6a9158e
v2 -> v3:
6a9158e
 - only switch to x2apic msr bitmap if virtualize x2apic mode is on in vmcs
6a9158e
6a9158e
v1 -> v2:
6a9158e
 - only update relevant bits in the secondary exec control
6a9158e
 - update msr intercept bitmap (also make x2apic msr bitmap always
6a9158e
   correspond to APICv)
6a9158e
6a9158e
 arch/x86/kvm/vmx.c | 48 ++++++++++++++++++++++++++++++------------------
6a9158e
 1 file changed, 30 insertions(+), 18 deletions(-)
6a9158e
6a9158e
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
6a9158e
index ee1c8a9..cef741a 100644
6a9158e
--- a/arch/x86/kvm/vmx.c
6a9158e
+++ b/arch/x86/kvm/vmx.c
6a9158e
@@ -2418,7 +2418,9 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
6a9158e
6a9158e
 	if (is_guest_mode(vcpu))
6a9158e
 		msr_bitmap = vmx_msr_bitmap_nested;
6a9158e
-	else if (vcpu->arch.apic_base & X2APIC_ENABLE) {
6a9158e
+	else if (cpu_has_secondary_exec_ctrls() &&
6a9158e
+		 (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
6a9158e
+		  SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
6a9158e
 		if (is_long_mode(vcpu))
6a9158e
 			msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
6a9158e
 		else
6a9158e
@@ -4783,6 +4785,19 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
6a9158e
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
6a9158e
6a9158e
 	vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
6a9158e
+	if (cpu_has_secondary_exec_ctrls()) {
6a9158e
+		if (kvm_vcpu_apicv_active(vcpu))
6a9158e
+			vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
6a9158e
+				      SECONDARY_EXEC_APIC_REGISTER_VIRT |
6a9158e
+				      SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
6a9158e
+		else
6a9158e
+			vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
6a9158e
+					SECONDARY_EXEC_APIC_REGISTER_VIRT |
6a9158e
+					SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
6a9158e
+	}
6a9158e
+
6a9158e
+	if (cpu_has_vmx_msr_bitmap())
6a9158e
+		vmx_set_msr_bitmap(vcpu);
6a9158e
 }
6a9158e
6a9158e
 static u32 vmx_exec_control(struct vcpu_vmx *vmx)
6a9158e
@@ -6329,23 +6344,20 @@ static __init int hardware_setup(void)
6a9158e
6a9158e
 	set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
6a9158e
6a9158e
-	if (enable_apicv) {
6a9158e
-		for (msr = 0x800; msr <= 0x8ff; msr++)
6a9158e
-			vmx_disable_intercept_msr_read_x2apic(msr);
6a9158e
-
6a9158e
-		/* According SDM, in x2apic mode, the whole id reg is used.
6a9158e
-		 * But in KVM, it only use the highest eight bits. Need to
6a9158e
-		 * intercept it */
6a9158e
-		vmx_enable_intercept_msr_read_x2apic(0x802);
6a9158e
-		/* TMCCT */
6a9158e
-		vmx_enable_intercept_msr_read_x2apic(0x839);
6a9158e
-		/* TPR */
6a9158e
-		vmx_disable_intercept_msr_write_x2apic(0x808);
6a9158e
-		/* EOI */
6a9158e
-		vmx_disable_intercept_msr_write_x2apic(0x80b);
6a9158e
-		/* SELF-IPI */
6a9158e
-		vmx_disable_intercept_msr_write_x2apic(0x83f);
6a9158e
-	}
6a9158e
+	for (msr = 0x800; msr <= 0x8ff; msr++)
6a9158e
+		vmx_disable_intercept_msr_read_x2apic(msr);
6a9158e
+
6a9158e
+	/* According SDM, in x2apic mode, the whole id reg is used.  But in
6a9158e
+	 * KVM, it only use the highest eight bits. Need to intercept it */
6a9158e
+	vmx_enable_intercept_msr_read_x2apic(0x802);
6a9158e
+	/* TMCCT */
6a9158e
+	vmx_enable_intercept_msr_read_x2apic(0x839);
6a9158e
+	/* TPR */
6a9158e
+	vmx_disable_intercept_msr_write_x2apic(0x808);
6a9158e
+	/* EOI */
6a9158e
+	vmx_disable_intercept_msr_write_x2apic(0x80b);
6a9158e
+	/* SELF-IPI */
6a9158e
+	vmx_disable_intercept_msr_write_x2apic(0x83f);
6a9158e
6a9158e
 	if (enable_ept) {
6a9158e
 		kvm_mmu_set_mask_ptes(0ull,
6a9158e
-- 
6a9158e
2.5.5