Re: [PATCH v3 22/27] KVM: nSVM: Flush the TLB if L1 changes L2's ASID in vmcb12
From: Jim Mattson
Date: Thu Oct 15 2026 - 19:50:46 EST
On Thu, Oct 15, 2026 at 4:20 PM Yosry Ahmed <yosry@xxxxxxxxxx> wrote:
>
> On Thu, Oct 15, 2026 at 4:09 PM Jim Mattson <jmattson@xxxxxxxxxx> wrote:
> >
> > On Mon, Oct 12, 2026 at 4:36 PM Yosry Ahmed <yosry@xxxxxxxxxx> wrote:
> > >
> > > KVM uses a single ASID for L2 guests per-vCPU. Hence, when L1 changes
> > > L2's ASID in vmcb12 (e.g. due to switching to a different L2
> > > vCPU or simply to avoid flushing an existing ASID), KVM needs to flush
> > > the L2 ASID to correctly emulate different ASIDs as different TLB
> > > domains.
> > >
> > > Additionally, the nested NPT needs to be resync'd, as the MMU context
> > > is not tagged by ASID, and KVM cannot reuse nested NPT entries across
> > > different L2 ASIDs.
> > >
> > > Essentially, L1 switching L2's ASID is treated exactly the same as L1
> > > flushing L2's ASID, which is consistent with the APM:
> > >
> > > Software may effectively flush the guest's TLB entries by allocating a
> > > new ASID for the guest and not reusing the old ASID until the entire
> > > TLB has been flushed at least once.
> > >
> > > This is similar to nVMX's handling of last_vpid, except that when L1
> > > changes VPID12, KVM does *not* need to resync the nested EPT, because
> > > VMX VPIDs, unlike SVM ASIDs, do not tag guest-physical translations
> > > (i.e. nGPA to GPA translations).
> > >
> > > Reset last_asid when nested VMRUN fails to force a flush and sync on the
> > > next nested VMRUN. The TLB flush request survives the failure, but the
> > > request to sync the nested NPT does not, as it ends up being serviced in
> > > L1's MMU context after the synthesized VM-Exit.
> > >
> > > Drop the commentary about vmcb12's ASID being copied around only for the
> > > consistency checks, as they no longer apply, and opportunistically fix
> > > whitespace alignment.
> > >
> > > This is currently functionally a noop, as a full flush and sync is
> > > triggered on every nested transition, but is a step toward eliminating
> > > that.
> > >
> > > Signed-off-by: Yosry Ahmed <yosry@xxxxxxxxxx>
> > > ---
> > > arch/x86/kvm/svm/nested.c | 29 +++++++++++++++++++++++------
> > > arch/x86/kvm/svm/svm.h | 2 ++
> > > 2 files changed, 25 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> > > index e04cc4f7669ea..8e4686b0d603a 100644
> > > --- a/arch/x86/kvm/svm/nested.c
> > > +++ b/arch/x86/kvm/svm/nested.c
> > > @@ -556,10 +556,8 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
> > > to->nested_cr3 = from->nested_cr3;
> > > to->pause_filter_count = from->pause_filter_count;
> > > to->pause_filter_thresh = from->pause_filter_thresh;
> > > -
> > > - /* Copy asid here because nested_vmcb_check_controls() will check it */
> > > - to->asid = from->asid;
> > > - to->clean = from->clean;
> > > + to->asid = from->asid;
> > > + to->clean = from->clean;
> > >
> > > #ifdef CONFIG_KVM_HYPERV
> > > /* Hyper-V extensions (Enlightened VMCB) */
> > > @@ -691,23 +689,35 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
> > > static void nested_svm_entry_tlb_flush(struct kvm_vcpu *vcpu)
> > > {
> > > struct vcpu_svm *svm = to_svm(vcpu);
> > > + bool new_asid = false;
> > >
> > > /* Handle pending Hyper-V TLB flush requests */
> > > kvm_hv_nested_transtion_tlb_flush(vcpu, npt_enabled);
> > >
> > > + if (svm->nested.ctl.asid != svm->nested.last_asid) {
> > > + svm->nested.last_asid = svm->nested.ctl.asid;
> > > + new_asid = true;
> > > + }
> >
> > To make sure we don't miss a flush after restore, do we need to clear
> > last_asid in svm_set_nested_state()?
>
> In [1], we set svm->nested.vmcb02.cpu = -1 in svm_allocate_nested(),
> which should be called when EFER.SVME is set on restore, and should
> force a TLB flush on the first vCPU run. That being said, if EFER.SVME
> was already set (not a fresh vCPU), we won't necessarily flush the
> TLB. KVM_SET_SREGS will _probably_ flush the TLB, but I don't think
> it's guaranteed.
I'm pretty sure that restoring nested state on an existing vCPU with
the same asid12 and no TLB_CONTROL skips the flush.
> But wouldn't this also affect non-nested? Are we guaranteed to flush
> L1's ASID after restore?
That may be a bug too.