Skip to content

Commit cd272fc

Browse files
sean-jcbonzini
authored andcommitted
KVM: x86/mmu: Move slot checks from __kvm_faultin_pfn() to kvm_faultin_pfn()
Move the checks related to the validity of an access to a memslot from the inner __kvm_faultin_pfn() to its sole caller, kvm_faultin_pfn(). This allows emulating accesses to the APIC access page, which don't need to resolve a pfn, even if there is a relevant in-progress mmu_notifier invalidation. Ditto for accesses to KVM internal memslots from L2, which KVM also treats as emulated MMIO. More importantly, this will allow for future cleanup by having the "no memslot" case bail from kvm_faultin_pfn() very early on. Go to rather extreme and gross lengths to make the change a glorified nop, e.g. call into __kvm_faultin_pfn() even when there is no slot, as the related code is very subtle. E.g. fault->slot can be nullified if it points at the APIC access page, some flows in KVM x86 expect fault->pfn to be KVM_PFN_NOSLOT, while others check only fault->slot, etc. No functional change intended. Signed-off-by: Sean Christopherson <[email protected]> Reviewed-by: Kai Huang <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent bde9f9d commit cd272fc

File tree

1 file changed

+44
-43
lines changed

1 file changed

+44
-43
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4291,52 +4291,15 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu,
42914291

42924292
static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
42934293
{
4294-
struct kvm_memory_slot *slot = fault->slot;
42954294
bool async;
42964295

4297-
/*
4298-
* Retry the page fault if the gfn hit a memslot that is being deleted
4299-
* or moved. This ensures any existing SPTEs for the old memslot will
4300-
* be zapped before KVM inserts a new MMIO SPTE for the gfn.
4301-
*/
4302-
if (slot && (slot->flags & KVM_MEMSLOT_INVALID))
4303-
return RET_PF_RETRY;
4304-
4305-
if (slot && slot->id == APIC_ACCESS_PAGE_PRIVATE_MEMSLOT) {
4306-
/*
4307-
* Don't map L1's APIC access page into L2, KVM doesn't support
4308-
* using APICv/AVIC to accelerate L2 accesses to L1's APIC,
4309-
* i.e. the access needs to be emulated. Emulating access to
4310-
* L1's APIC is also correct if L1 is accelerating L2's own
4311-
* virtual APIC, but for some reason L1 also maps _L1's_ APIC
4312-
* into L2. Note, vcpu_is_mmio_gpa() always treats access to
4313-
* the APIC as MMIO. Allow an MMIO SPTE to be created, as KVM
4314-
* uses different roots for L1 vs. L2, i.e. there is no danger
4315-
* of breaking APICv/AVIC for L1.
4316-
*/
4317-
if (is_guest_mode(vcpu)) {
4318-
fault->slot = NULL;
4319-
fault->pfn = KVM_PFN_NOSLOT;
4320-
fault->map_writable = false;
4321-
return RET_PF_CONTINUE;
4322-
}
4323-
/*
4324-
* If the APIC access page exists but is disabled, go directly
4325-
* to emulation without caching the MMIO access or creating a
4326-
* MMIO SPTE. That way the cache doesn't need to be purged
4327-
* when the AVIC is re-enabled.
4328-
*/
4329-
if (!kvm_apicv_activated(vcpu->kvm))
4330-
return RET_PF_EMULATE;
4331-
}
4332-
43334296
if (fault->is_private)
43344297
return kvm_faultin_pfn_private(vcpu, fault);
43354298

43364299
async = false;
4337-
fault->pfn = __gfn_to_pfn_memslot(slot, fault->gfn, false, false, &async,
4338-
fault->write, &fault->map_writable,
4339-
&fault->hva);
4300+
fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, false, false,
4301+
&async, fault->write,
4302+
&fault->map_writable, &fault->hva);
43404303
if (!async)
43414304
return RET_PF_CONTINUE; /* *pfn has correct page already */
43424305

@@ -4356,15 +4319,16 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
43564319
* to wait for IO. Note, gup always bails if it is unable to quickly
43574320
* get a page and a fatal signal, i.e. SIGKILL, is pending.
43584321
*/
4359-
fault->pfn = __gfn_to_pfn_memslot(slot, fault->gfn, false, true, NULL,
4360-
fault->write, &fault->map_writable,
4361-
&fault->hva);
4322+
fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, false, true,
4323+
NULL, fault->write,
4324+
&fault->map_writable, &fault->hva);
43624325
return RET_PF_CONTINUE;
43634326
}
43644327

43654328
static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
43664329
unsigned int access)
43674330
{
4331+
struct kvm_memory_slot *slot = fault->slot;
43684332
int ret;
43694333

43704334
/*
@@ -4385,6 +4349,42 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
43854349
return -EFAULT;
43864350
}
43874351

4352+
/*
4353+
* Retry the page fault if the gfn hit a memslot that is being deleted
4354+
* or moved. This ensures any existing SPTEs for the old memslot will
4355+
* be zapped before KVM inserts a new MMIO SPTE for the gfn.
4356+
*/
4357+
if (slot && (slot->flags & KVM_MEMSLOT_INVALID))
4358+
return RET_PF_RETRY;
4359+
4360+
if (slot && slot->id == APIC_ACCESS_PAGE_PRIVATE_MEMSLOT) {
4361+
/*
4362+
* Don't map L1's APIC access page into L2, KVM doesn't support
4363+
* using APICv/AVIC to accelerate L2 accesses to L1's APIC,
4364+
* i.e. the access needs to be emulated. Emulating access to
4365+
* L1's APIC is also correct if L1 is accelerating L2's own
4366+
* virtual APIC, but for some reason L1 also maps _L1's_ APIC
4367+
* into L2. Note, vcpu_is_mmio_gpa() always treats access to
4368+
* the APIC as MMIO. Allow an MMIO SPTE to be created, as KVM
4369+
* uses different roots for L1 vs. L2, i.e. there is no danger
4370+
* of breaking APICv/AVIC for L1.
4371+
*/
4372+
if (is_guest_mode(vcpu)) {
4373+
fault->slot = NULL;
4374+
fault->pfn = KVM_PFN_NOSLOT;
4375+
fault->map_writable = false;
4376+
goto faultin_done;
4377+
}
4378+
/*
4379+
* If the APIC access page exists but is disabled, go directly
4380+
* to emulation without caching the MMIO access or creating a
4381+
* MMIO SPTE. That way the cache doesn't need to be purged
4382+
* when the AVIC is re-enabled.
4383+
*/
4384+
if (!kvm_apicv_activated(vcpu->kvm))
4385+
return RET_PF_EMULATE;
4386+
}
4387+
43884388
/*
43894389
* Check for a relevant mmu_notifier invalidation event before getting
43904390
* the pfn from the primary MMU, and before acquiring mmu_lock.
@@ -4414,6 +4414,7 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
44144414
if (ret != RET_PF_CONTINUE)
44154415
return ret;
44164416

4417+
faultin_done:
44174418
if (unlikely(is_error_pfn(fault->pfn)))
44184419
return kvm_handle_error_pfn(vcpu, fault);
44194420

0 commit comments

Comments
 (0)