From: Sean Christopherson <seanjc@google.com>
To: sashiko-reviews@lists.linux.dev
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH v2 1/2] KVM: x86: Switch to vmcs01 to update EOI exiting bitmap on-demand if L2 is active
Date: Thu, 22 Oct 2026 06:08:45 -0700 [thread overview]
Message-ID: <atoK3Z1hrMxwwgTY@google.com> (raw)
In-Reply-To: <sashiko-outbox-180887@kernel.org>
On Thu, Oct 22, 2026, sashiko-bot@kernel.org wrote:
> > diff --git a/arch/x86/kvm/regs.h b/arch/x86/kvm/regs.h
> > index 447f0ec3e63e4..411eaf445d436 100644
> > --- a/arch/x86/kvm/regs.h
> > +++ b/arch/x86/kvm/regs.h
> > @@ -464,12 +464,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;
> > }
> >
>
> [Severity: Low]
> With the removal of the only reader of vcpu->arch.load_eoi_exitmap_pending in
> leave_guest_mode() (in arch/x86/kvm/regs.h) and its only writer in
> vcpu_scan_ioapic() (in arch/x86/kvm/x86.c), load_eoi_exitmap_pending in
> struct kvm_vcpu_arch has no remaining references in the tree (both at this
> commit and at the end of the series):
>
> arch/x86/include/asm/kvm_host.h:
> struct kvm_vcpu_arch {
> ...
> u64 apic_base;
> struct kvm_lapic *apic; /* kernel irqchip context */
> bool load_eoi_exitmap_pending;
> DECLARE_BITMAP(ioapic_handled_vectors, 256);
>
> Should load_eoi_exitmap_pending be removed from struct kvm_vcpu_arch as well?
/facepalm
Every. Single. Time. I forget to remove the boolean.
> > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> > index 612ab07d4100f..5e765409398d3 100644
> > --- a/arch/x86/kvm/vmx/vmx.c
> > +++ b/arch/x86/kvm/vmx/vmx.c
> > @@ -7139,6 +7139,8 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
> > if (!kvm_vcpu_apicv_active(vcpu))
> > 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 aad065d035fbb..082d027ade583 100644
> > --- a/arch/x86/kvm/x86.c
> > +++ b/arch/x86/kvm/x86.c
> > @@ -8003,17 +8003,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];
> > @@ -8167,8 +8156,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
>
> [Severity: High]
> Can calling load_eoi_exitmap() directly from vcpu_scan_ioapic() while L2 is
> active leave stale EOI_EXIT_BITMAP0..3 values in vmcs01 when APICv
> transitions from inhibited to uninhibited in L2?
Huh. This isn't an L2 vs. L1 issue, this is a pre-existing bug that doesn't have
anything to do with nested. Sashiko found a convoluted scenario where not
deferring the EOI update would create a bigger window for the bug, but there are
much simpler scenarios that will hit this bug. E.g. any GSI routing changes that
affect the EOI bitmap that are made while APICv is inhibited will run afoul of
this issue.
The bug has likely gone unnoticed because APICv doesn't have many inhibits, and
pretty much the only one that's likely to be toggled by a "real" guest is the
APICV_INHIBIT_REASON_HYPERV one that SynIC uses when AutoEOI is enabled.
> When APICv becomes inhibited on a vCPU (for example, when L1 or L2 modifies
> the xAPIC APIC_ID via kvm_lapic_reg_write() -> kvm_recalculate_apic_map(),
> disables the APIC via kvm_apic_set_base(), or enables Hyper-V SynIC AutoEOI),
> KVM queues both KVM_REQ_APICV_UPDATE and KVM_REQ_SCAN_IOAPIC.
>
> In vcpu_enter_guest() in arch/x86/kvm/x86.c, KVM_REQ_SCAN_IOAPIC is serviced
> before KVM_REQ_APICV_UPDATE:
>
> arch/x86/kvm/x86.c:vcpu_enter_guest() {
> ...
> if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
> vcpu_scan_ioapic(vcpu);
> ...
> if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
> kvm_vcpu_update_apicv(vcpu);
> }
>
> During the inhibit transition, apic->apicv_active is still true when
> vcpu_scan_ioapic() runs, so vmx_load_eoi_exitmap() writes the zeroed
> ioapic_handled_vectors bitmap into vmcs01's EOI_EXIT_BITMAP0..3 before
> KVM_REQ_APICV_UPDATE sets apic->apicv_active to false. Similarly, any IOAPIC
> routes configured while APICv is inhibited are not written to vmcs01 because
> apic->apicv_active is false.
>
> When the guest later transitions out of the inhibited state while L2 is
> active (is_guest_mode(vcpu) is true) -- for example, when L2 enables x2APIC
> via MSR_IA32_APICBASE or restores the xAPIC ID -- kvm_apic_set_base() or
> kvm_recalculate_apic_map() clears the APICv inhibit (queuing
> KVM_REQ_APICV_UPDATE) and calls kvm_make_scan_ioapic_request() (queuing
> KVM_REQ_SCAN_IOAPIC).
>
> Previously, because is_guest_mode(vcpu) was true, vcpu_scan_ioapic() set
> vcpu->arch.load_eoi_exitmap_pending = true and deferred
> KVM_REQ_LOAD_EOI_EXITMAP until leave_guest_mode() on nested VM-Exit, after
> KVM_REQ_APICV_UPDATE had already set apic->apicv_active = true.
...
> Should KVM_REQ_APICV_UPDATE be processed before KVM_REQ_SCAN_IOAPIC in
> vcpu_enter_guest(), or should kvm_vcpu_update_apicv() reload the EOI exit
> bitmap when re-activating APICv?
Neither. This bug was introduced by commit d62caabb41f3 ("kvm/x86: per-vcpu apicv
deactivation support"). As KVM does with device posted interrupts, where IRTEs
are kept up-to-date even if APICv is *currently* inhibited, the simple thing to
do is keep the EOI bitmap up-to-date if APICv is globally enabled, i.e.:
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index b341af4c6057..d8e66d67138f 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7079,7 +7079,7 @@ int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
{
- if (!kvm_vcpu_apicv_active(vcpu))
+ if (!lapic_in_kernel(vcpu) || !enable_apicv)
return;
vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
I'll insert a new patch in v2.
next prev parent reply other threads:[~2026-10-22 13:08 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 2:28 [PATCH v2 0/2] KVM: x86: Drop deferred updates of EOI bitmaps Sean Christopherson
2026-10-22 2:28 ` [PATCH v2 1/2] KVM: x86: Switch to vmcs01 to update EOI exiting bitmap on-demand if L2 is active Sean Christopherson
2026-10-22 2:52 ` sashiko-bot
2026-10-22 13:08 ` Sean Christopherson [this message]
2026-10-22 2:28 ` [PATCH v2 2/2] KVM: x86: Consolidate invocations of kvm_x86_ops.load_eoi_exitmap() Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=atoK3Z1hrMxwwgTY@google.com \
--to=seanjc@google.com \
--cc=kvm@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.