Commit 0be44352 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: x86/mmu: Reuse the current root if possible for fast switch

Reuse the current root when possible instead of grabbing a different
root from the array of cached roots.  Doing so avoids unnecessary MMU
switches and also fixes a quirk where KVM can't reuse roots without
creating multiple roots since the cache is a victim cache, i.e. roots
are added to the cache when they're "evicted", not when they are
created.  The quirk could be fixed by adding roots to the cache on
creation, but that would reduce the effective size of the cache as one
of its entries would be burned to track the current root.

Reusing the current root is especially helpful for nested virt as the
current root is almost always usable for the "new" MMU on nested
VM-entry/VM-exit.

Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 3651c7fc
...@@ -4253,6 +4253,14 @@ static void nonpaging_init_context(struct kvm_vcpu *vcpu, ...@@ -4253,6 +4253,14 @@ static void nonpaging_init_context(struct kvm_vcpu *vcpu,
context->nx = false; context->nx = false;
} }
static inline bool is_root_usable(struct kvm_mmu_root_info *root, gpa_t cr3,
union kvm_mmu_page_role role)
{
return (role.direct || cr3 == root->cr3) &&
VALID_PAGE(root->hpa) && page_header(root->hpa) &&
role.word == page_header(root->hpa)->role.word;
}
/* /*
* Find out if a previously cached root matching the new CR3/role is available. * Find out if a previously cached root matching the new CR3/role is available.
* The current root is also inserted into the cache. * The current root is also inserted into the cache.
...@@ -4271,12 +4279,13 @@ static bool cached_root_available(struct kvm_vcpu *vcpu, gpa_t new_cr3, ...@@ -4271,12 +4279,13 @@ static bool cached_root_available(struct kvm_vcpu *vcpu, gpa_t new_cr3,
root.cr3 = mmu->root_cr3; root.cr3 = mmu->root_cr3;
root.hpa = mmu->root_hpa; root.hpa = mmu->root_hpa;
if (is_root_usable(&root, new_cr3, new_role))
return true;
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) { for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) {
swap(root, mmu->prev_roots[i]); swap(root, mmu->prev_roots[i]);
if ((new_role.direct || new_cr3 == root.cr3) && if (is_root_usable(&root, new_cr3, new_role))
VALID_PAGE(root.hpa) && page_header(root.hpa) &&
new_role.word == page_header(root.hpa)->role.word)
break; break;
} }
......
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