Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: LAPIC: Write 0 to TMICT should also cancel vmx-preemption timer

According to the SDM 10.5.4.1:

A write of 0 to the initial-count register effectively stops the local
APIC timer, in both one-shot and periodic mode.

However, the lapic timer oneshot/periodic mode which is emulated by vmx-preemption
timer doesn't stop by writing 0 to TMICT since vmx->hv_deadline_tsc is still
programmed and the guest will receive the spurious timer interrupt later. This
patch fixes it by also cancelling the vmx-preemption timer when writing 0 to
the initial-count register.

Reviewed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Wanpeng Li <wanpengli@tencent.com>
Message-Id: <1623050385-100988-1-git-send-email-wanpengli@tencent.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Wanpeng Li and committed by
Paolo Bonzini
e898da78 4f13d471

+11 -6
+11 -6
arch/x86/kvm/lapic.c
··· 1494 1494 1495 1495 static void cancel_hv_timer(struct kvm_lapic *apic); 1496 1496 1497 + static void cancel_apic_timer(struct kvm_lapic *apic) 1498 + { 1499 + hrtimer_cancel(&apic->lapic_timer.timer); 1500 + preempt_disable(); 1501 + if (apic->lapic_timer.hv_timer_in_use) 1502 + cancel_hv_timer(apic); 1503 + preempt_enable(); 1504 + } 1505 + 1497 1506 static void apic_update_lvtt(struct kvm_lapic *apic) 1498 1507 { 1499 1508 u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) & ··· 1511 1502 if (apic->lapic_timer.timer_mode != timer_mode) { 1512 1503 if (apic_lvtt_tscdeadline(apic) != (timer_mode == 1513 1504 APIC_LVT_TIMER_TSCDEADLINE)) { 1514 - hrtimer_cancel(&apic->lapic_timer.timer); 1515 - preempt_disable(); 1516 - if (apic->lapic_timer.hv_timer_in_use) 1517 - cancel_hv_timer(apic); 1518 - preempt_enable(); 1505 + cancel_apic_timer(apic); 1519 1506 kvm_lapic_set_reg(apic, APIC_TMICT, 0); 1520 1507 apic->lapic_timer.period = 0; 1521 1508 apic->lapic_timer.tscdeadline = 0; ··· 2097 2092 if (apic_lvtt_tscdeadline(apic)) 2098 2093 break; 2099 2094 2100 - hrtimer_cancel(&apic->lapic_timer.timer); 2095 + cancel_apic_timer(apic); 2101 2096 kvm_lapic_set_reg(apic, APIC_TMICT, val); 2102 2097 start_apic_timer(apic); 2103 2098 break;