[PATCH v3 2/3] KVM: x86: Switch to vmcs01 to update EOI exiting bitmap on-demand if L2 is active

From: Sean Christopherson

Date: Tue Oct 27 2026 - 18:32:36 EST


If KVM needs to update the EOI bitmap while L2 is running, temporarily load
vmcs01 and immediately refresh the bitmap in vmcs01 instead of deferring
the update until the next nested VM-Exit. I.e. give the EOI bitmap the
same treatment as the many other updates that were previously deferred.

Reported-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@xxxxxxxx>
Closes: https://lore.kernel.org/all/20261017093016.32348-2-amirmohammad.eftekhar@xxxxxxxx
Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
arch/x86/include/asm/kvm_host.h | 3 +--
arch/x86/kvm/regs.h | 6 ------
arch/x86/kvm/vmx/vmx.c | 2 ++
arch/x86/kvm/x86.c | 13 -------------
4 files changed, 3 insertions(+), 21 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 0378577d9d8b..92aae551bfae 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -113,7 +113,7 @@
#define KVM_REQ_HV_RESET KVM_ARCH_REQ(20)
#define KVM_REQ_HV_EXIT KVM_ARCH_REQ(21)
#define KVM_REQ_HV_STIMER KVM_ARCH_REQ(22)
-#define KVM_REQ_LOAD_EOI_EXITMAP KVM_ARCH_REQ(23)
+/*#define FREE!!! USE ME!!! KVM_ARCH_REQ(23) */
#define KVM_REQ_GET_NESTED_STATE_PAGES KVM_ARCH_REQ(24)
#define KVM_REQ_APICV_UPDATE \
KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
@@ -746,7 +746,6 @@ struct kvm_vcpu_arch {
u64 host_debugctl;
u64 apic_base;
struct kvm_lapic *apic; /* kernel irqchip context */
- bool load_eoi_exitmap_pending;
DECLARE_BITMAP(ioapic_handled_vectors, 256);
unsigned long apic_attention;
int32_t apic_arb_prio;
diff --git a/arch/x86/kvm/regs.h b/arch/x86/kvm/regs.h
index 97c17b120a57..04d047f46753 100644
--- a/arch/x86/kvm/regs.h
+++ b/arch/x86/kvm/regs.h
@@ -463,12 +463,6 @@ static inline void enter_guest_mode(struct kvm_vcpu *vcpu)
static inline void leave_guest_mode(struct kvm_vcpu *vcpu)
{
vcpu->arch.hflags &= ~HF_GUEST_MASK;
-
- if (vcpu->arch.load_eoi_exitmap_pending) {
- vcpu->arch.load_eoi_exitmap_pending = false;
- kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
- }
-
vcpu->stat.guest_mode = 0;
}

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index d8e66d67138f..ba5575002538 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7082,6 +7082,8 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
if (!lapic_in_kernel(vcpu) || !enable_apicv)
return;

+ guard(vmx_vmcs01)(vcpu);
+
vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]);
vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 32563a91fba9..0028d57e964a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8062,17 +8062,6 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
#endif

- if (is_guest_mode(vcpu))
- vcpu->arch.load_eoi_exitmap_pending = true;
- else
- kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
-}
-
-static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
-{
- if (!kvm_apic_hw_enabled(vcpu->arch.apic))
- return;
-
#ifdef CONFIG_KVM_HYPERV
if (to_hv_vcpu(vcpu)) {
u64 eoi_exit_bitmap[4];
@@ -8240,8 +8229,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
}
if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
vcpu_scan_ioapic(vcpu);
- if (kvm_check_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu))
- vcpu_load_eoi_exitmap(vcpu);
if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
kvm_vcpu_reload_apic_access_page(vcpu);
#ifdef CONFIG_KVM_HYPERV
--
2.56.0.307.g5fe7bd680c-goog