KVM: nVMX: Free only guest_mode (L2) roots on INVVPID w/o EPT
When emulating INVVPID for L1, free only L2+ roots, using the guest_mode tag in the MMU role to identify L2+ roots. From L1's perspective, its own TLB entries use VPID=0, and INVVPID is not requied to invalidate such entries. Per Intel's SDM, INVVPID _may_ invalidate entries with VPID=0, but it is not required to do so. Cc: Lai Jiangshan <laijs@linux.alibaba.com> Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20210609234235.1244004-10-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
50a417962a
commit
25b62c6274
@ -1684,6 +1684,7 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn);
|
||||
void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
|
||||
void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
|
||||
ulong roots_to_free);
|
||||
void kvm_mmu_free_guest_mode_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu);
|
||||
gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access,
|
||||
struct x86_exception *exception);
|
||||
gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva,
|
||||
|
@ -3212,6 +3212,33 @@ void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_mmu_free_roots);
|
||||
|
||||
void kvm_mmu_free_guest_mode_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu)
|
||||
{
|
||||
unsigned long roots_to_free = 0;
|
||||
hpa_t root_hpa;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* This should not be called while L2 is active, L2 can't invalidate
|
||||
* _only_ its own roots, e.g. INVVPID unconditionally exits.
|
||||
*/
|
||||
WARN_ON_ONCE(mmu->mmu_role.base.guest_mode);
|
||||
|
||||
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) {
|
||||
root_hpa = mmu->prev_roots[i].hpa;
|
||||
if (!VALID_PAGE(root_hpa))
|
||||
continue;
|
||||
|
||||
if (!to_shadow_page(root_hpa) ||
|
||||
to_shadow_page(root_hpa)->role.guest_mode)
|
||||
roots_to_free |= KVM_MMU_ROOT_PREVIOUS(i);
|
||||
}
|
||||
|
||||
kvm_mmu_free_roots(vcpu, mmu, roots_to_free);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_mmu_free_guest_mode_roots);
|
||||
|
||||
|
||||
static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -5481,8 +5481,8 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
|
||||
|
||||
/*
|
||||
* Sync the shadow page tables if EPT is disabled, L1 is invalidating
|
||||
* linear mappings for L2 (tagged with L2's VPID). Free all roots as
|
||||
* VPIDs are not tracked in the MMU role.
|
||||
* linear mappings for L2 (tagged with L2's VPID). Free all guest
|
||||
* roots as VPIDs are not tracked in the MMU role.
|
||||
*
|
||||
* Note, this operates on root_mmu, not guest_mmu, as L1 and L2 share
|
||||
* an MMU when EPT is disabled.
|
||||
@ -5490,8 +5490,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
|
||||
* TODO: sync only the affected SPTEs for INVDIVIDUAL_ADDR.
|
||||
*/
|
||||
if (!enable_ept)
|
||||
kvm_mmu_free_roots(vcpu, &vcpu->arch.root_mmu,
|
||||
KVM_MMU_ROOTS_ALL);
|
||||
kvm_mmu_free_guest_mode_roots(vcpu, &vcpu->arch.root_mmu);
|
||||
|
||||
return nested_vmx_succeed(vcpu);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user