Skip to content

Commit e992bf6

Browse files
committed
KVM: SVM: Set/clear CR8 write interception when AVIC is (de)activated
Explicitly set/clear CR8 write interception when AVIC is (de)activated to fix a bug where KVM leaves the interception enabled after AVIC is activated. E.g. if KVM emulates INIT=>WFS while AVIC is deactivated, CR8 will remain intercepted in perpetuity. On its own, the dangling CR8 intercept is "just" a performance issue, but combined with the TPR sync bug fixed by commit d02e488 ("KVM: SVM: Sync TPR from LAPIC into VMCB::V_TPR even if AVIC is active"), the danging intercept is fatal to Windows guests as the TPR seen by hardware gets wildly out of sync with reality. Note, VMX isn't affected by the bug as TPR_THRESHOLD is explicitly ignored when Virtual Interrupt Delivery is enabled, i.e. when APICv is active in KVM's world. I.e. there's no need to trigger update_cr8_intercept(), this is firmly an SVM implementation flaw/detail. WARN if KVM gets a CR8 write #VMEXIT while AVIC is active, as KVM should never enter the guest with AVIC enabled and CR8 writes intercepted. Fixes: 3bbf356 ("svm: Do not intercept CR8 when enable AVIC") Cc: stable@vger.kernel.org Cc: Jim Mattson <jmattson@google.com> Cc: Naveen N Rao (AMD) <naveen@kernel.org> Cc: Maciej S. Szmigiero <maciej.szmigiero@oracle.com> Reviewed-by: Naveen N Rao (AMD) <naveen@kernel.org> Reviewed-by: Jim Mattson <jmattson@google.com> Link: https://patch.msgid.link/20260203190711.458413-3-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 9071d0e commit e992bf6

File tree

2 files changed

+8
-5
lines changed

2 files changed

+8
-5
lines changed

arch/x86/kvm/svm/avic.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,12 @@ static void avic_activate_vmcb(struct vcpu_svm *svm)
189189
struct kvm_vcpu *vcpu = &svm->vcpu;
190190

191191
vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK);
192-
193192
vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK;
194193
vmcb->control.avic_physical_id |= avic_get_max_physical_id(vcpu);
195-
196194
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
197195

196+
svm_clr_intercept(svm, INTERCEPT_CR8_WRITE);
197+
198198
/*
199199
* Note: KVM supports hybrid-AVIC mode, where KVM emulates x2APIC MSR
200200
* accesses, while interrupt injection to a running vCPU can be
@@ -226,6 +226,8 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm)
226226
vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK);
227227
vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK;
228228

229+
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
230+
229231
/*
230232
* If running nested and the guest uses its own MSR bitmap, there
231233
* is no need to update L0's msr bitmap

arch/x86/kvm/svm/svm.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,8 +1077,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event)
10771077
svm_set_intercept(svm, INTERCEPT_CR0_WRITE);
10781078
svm_set_intercept(svm, INTERCEPT_CR3_WRITE);
10791079
svm_set_intercept(svm, INTERCEPT_CR4_WRITE);
1080-
if (!kvm_vcpu_apicv_active(vcpu))
1081-
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
1080+
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
10821081

10831082
set_dr_intercepts(svm);
10841083

@@ -2674,9 +2673,11 @@ static int dr_interception(struct kvm_vcpu *vcpu)
26742673

26752674
static int cr8_write_interception(struct kvm_vcpu *vcpu)
26762675
{
2676+
u8 cr8_prev = kvm_get_cr8(vcpu);
26772677
int r;
26782678

2679-
u8 cr8_prev = kvm_get_cr8(vcpu);
2679+
WARN_ON_ONCE(kvm_vcpu_apicv_active(vcpu));
2680+
26802681
/* instruction emulation calls kvm_set_cr8() */
26812682
r = cr_interception(vcpu);
26822683
if (lapic_in_kernel(vcpu))

0 commit comments

Comments
 (0)