Commit 9cc13d60 authored by Maxim Levitsky's avatar Maxim Levitsky Committed by Paolo Bonzini

KVM: x86/mmu: allow APICv memslot to be enabled but invisible

on AMD, APIC virtualization needs to dynamicaly inhibit the AVIC in a
response to some events, and this is problematic and not efficient to do by
enabling/disabling the memslot that covers APIC's mmio range.

Plus due to SRCU locking, it makes it more complex to
request AVIC inhibition.

Instead, the APIC memslot will be always enabled, but be invisible
to the guest, such as the MMU code will not install a SPTE for it,
when it is inhibited and instead jump straight to emulating the access.

When inhibiting the AVIC, this SPTE will be zapped.

This code is based on a suggestion from Sean Christopherson:
https://lkml.org/lkml/2021/7/19/2970Suggested-by: default avatarSean Christopherson <seanjc@google.com>
Signed-off-by: default avatarMaxim Levitsky <mlevitsk@redhat.com>
Message-Id: <20210810205251.424103-8-mlevitsk@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 8f32d5e5
...@@ -3899,12 +3899,25 @@ static bool kvm_faultin_pfn(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, ...@@ -3899,12 +3899,25 @@ static bool kvm_faultin_pfn(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
if (slot && (slot->flags & KVM_MEMSLOT_INVALID)) if (slot && (slot->flags & KVM_MEMSLOT_INVALID))
goto out_retry; goto out_retry;
if (!kvm_is_visible_memslot(slot)) {
/* Don't expose private memslots to L2. */ /* Don't expose private memslots to L2. */
if (is_guest_mode(vcpu) && !kvm_is_visible_memslot(slot)) { if (is_guest_mode(vcpu)) {
*pfn = KVM_PFN_NOSLOT; *pfn = KVM_PFN_NOSLOT;
*writable = false; *writable = false;
return false; return false;
} }
/*
* If the APIC access page exists but is disabled, go directly
* to emulation without caching the MMIO access or creating a
* MMIO SPTE. That way the cache doesn't need to be purged
* when the AVIC is re-enabled.
*/
if (slot && slot->id == APIC_ACCESS_PAGE_PRIVATE_MEMSLOT &&
!kvm_apicv_activated(vcpu->kvm)) {
*r = RET_PF_EMULATE;
return true;
}
}
async = false; async = false;
*pfn = __gfn_to_pfn_memslot(slot, gfn, false, &async, *pfn = __gfn_to_pfn_memslot(slot, gfn, false, &async,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment