Skip to content

Commit b53e84e

Browse files
Lai Jiangshanbonzini
authored andcommitted
KVM: x86: Unload MMU on guest TLB flush if TDP disabled to force MMU sync
When using shadow paging, unload the guest MMU when emulating a guest TLB flush to ensure all roots are synchronized. From the guest's perspective, flushing the TLB ensures any and all modifications to its PTEs will be recognized by the CPU. Note, unloading the MMU is overkill, but is done to mirror KVM's existing handling of INVPCID(all) and ensure the bug is squashed. Future cleanup can be done to more precisely synchronize roots when servicing a guest TLB flush. If TDP is enabled, synchronizing the MMU is unnecessary even if nested TDP is in play, as a "legacy" TLB flush from L1 does not invalidate L1's TDP mappings. For EPT, an explicit INVEPT is required to invalidate guest-physical mappings; for NPT, guest mappings are always tagged with an ASID and thus can only be invalidated via the VMCB's ASID control. This bug has existed since the introduction of KVM_VCPU_FLUSH_TLB. It was only recently exposed after Linux guests stopped flushing the local CPU's TLB prior to flushing remote TLBs (see commit 4ce94ea, "x86/mm/tlb: Flush remote and local TLBs concurrently"), but is also visible in Windows 10 guests. Tested-by: Maxim Levitsky <[email protected]> Reviewed-by: Maxim Levitsky <[email protected]> Fixes: f38a7b7 ("KVM: X86: support paravirtualized help for TLB shootdowns") Signed-off-by: Lai Jiangshan <[email protected]> [sean: massaged comment and changelog] Message-Id: <[email protected]> Signed-off-by: Sean Christopherson <[email protected]> Cc: [email protected] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent f31500b commit b53e84e

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

arch/x86/kvm/x86.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3072,6 +3072,19 @@ static void kvm_vcpu_flush_tlb_all(struct kvm_vcpu *vcpu)
30723072
static void kvm_vcpu_flush_tlb_guest(struct kvm_vcpu *vcpu)
30733073
{
30743074
++vcpu->stat.tlb_flush;
3075+
3076+
if (!tdp_enabled) {
3077+
/*
3078+
* A TLB flush on behalf of the guest is equivalent to
3079+
* INVPCID(all), toggling CR4.PGE, etc., which requires
3080+
* a forced sync of the shadow page tables. Unload the
3081+
* entire MMU here and the subsequent load will sync the
3082+
* shadow page tables, and also flush the TLB.
3083+
*/
3084+
kvm_mmu_unload(vcpu);
3085+
return;
3086+
}
3087+
30753088
static_call(kvm_x86_tlb_flush_guest)(vcpu);
30763089
}
30773090

0 commit comments

Comments
 (0)