Skip to content

Commit ad7dc69

Browse files
vittyvkbonzini
authored andcommitted
x86/kvm/mmu: fix switch between root and guest MMUs
Commit 14c07ad ("x86/kvm/mmu: introduce guest_mmu") brought one subtle change: previously, when switching back from L2 to L1, we were resetting MMU hooks (like mmu->get_cr3()) in kvm_init_mmu() called from nested_vmx_load_cr3() and now we do that in nested_ept_uninit_mmu_context() when we re-target vcpu->arch.mmu pointer. The change itself looks logical: if nested_ept_init_mmu_context() changes something than nested_ept_uninit_mmu_context() restores it back. There is, however, one thing: the following call chain: nested_vmx_load_cr3() kvm_mmu_new_cr3() __kvm_mmu_new_cr3() fast_cr3_switch() cached_root_available() now happens with MMU hooks pointing to the new MMU (root MMU in our case) while previously it was happening with the old one. cached_root_available() tries to stash current root but it is incorrect to read current CR3 with mmu->get_cr3(), we need to use old_mmu->get_cr3() which in case we're switching from L2 to L1 is guest_mmu. (BTW, in shadow page tables case this is a non-issue because we don't switch MMU). While we could've tried to guess that we're switching between MMUs and call the right ->get_cr3() from cached_root_available() this seems to be overly complicated. Instead, just stash the corresponding CR3 when setting root_hpa and make cached_root_available() use the stashed value. Fixes: 14c07ad ("x86/kvm/mmu: introduce guest_mmu") Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 73de65f commit ad7dc69

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ struct kvm_mmu {
397397
void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
398398
u64 *spte, const void *pte);
399399
hpa_t root_hpa;
400+
gpa_t root_cr3;
400401
union kvm_mmu_role mmu_role;
401402
u8 root_level;
402403
u8 shadow_root_level;

arch/x86/kvm/mmu.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,6 +3555,7 @@ void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
35553555
&invalid_list);
35563556
mmu->root_hpa = INVALID_PAGE;
35573557
}
3558+
mmu->root_cr3 = 0;
35583559
}
35593560

35603561
kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
@@ -3610,6 +3611,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
36103611
vcpu->arch.mmu->root_hpa = __pa(vcpu->arch.mmu->pae_root);
36113612
} else
36123613
BUG();
3614+
vcpu->arch.mmu->root_cr3 = vcpu->arch.mmu->get_cr3(vcpu);
36133615

36143616
return 0;
36153617
}
@@ -3618,10 +3620,11 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
36183620
{
36193621
struct kvm_mmu_page *sp;
36203622
u64 pdptr, pm_mask;
3621-
gfn_t root_gfn;
3623+
gfn_t root_gfn, root_cr3;
36223624
int i;
36233625

3624-
root_gfn = vcpu->arch.mmu->get_cr3(vcpu) >> PAGE_SHIFT;
3626+
root_cr3 = vcpu->arch.mmu->get_cr3(vcpu);
3627+
root_gfn = root_cr3 >> PAGE_SHIFT;
36253628

36263629
if (mmu_check_root(vcpu, root_gfn))
36273630
return 1;
@@ -3646,7 +3649,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
36463649
++sp->root_count;
36473650
spin_unlock(&vcpu->kvm->mmu_lock);
36483651
vcpu->arch.mmu->root_hpa = root;
3649-
return 0;
3652+
goto set_root_cr3;
36503653
}
36513654

36523655
/*
@@ -3712,6 +3715,9 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
37123715
vcpu->arch.mmu->root_hpa = __pa(vcpu->arch.mmu->lm_root);
37133716
}
37143717

3718+
set_root_cr3:
3719+
vcpu->arch.mmu->root_cr3 = root_cr3;
3720+
37153721
return 0;
37163722
}
37173723

@@ -4163,7 +4169,7 @@ static bool cached_root_available(struct kvm_vcpu *vcpu, gpa_t new_cr3,
41634169
struct kvm_mmu_root_info root;
41644170
struct kvm_mmu *mmu = vcpu->arch.mmu;
41654171

4166-
root.cr3 = mmu->get_cr3(vcpu);
4172+
root.cr3 = mmu->root_cr3;
41674173
root.hpa = mmu->root_hpa;
41684174

41694175
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) {
@@ -4176,6 +4182,7 @@ static bool cached_root_available(struct kvm_vcpu *vcpu, gpa_t new_cr3,
41764182
}
41774183

41784184
mmu->root_hpa = root.hpa;
4185+
mmu->root_cr3 = root.cr3;
41794186

41804187
return i < KVM_MMU_NUM_PREV_ROOTS;
41814188
}
@@ -5516,11 +5523,13 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu)
55165523
vcpu->arch.walk_mmu = &vcpu->arch.root_mmu;
55175524

55185525
vcpu->arch.root_mmu.root_hpa = INVALID_PAGE;
5526+
vcpu->arch.root_mmu.root_cr3 = 0;
55195527
vcpu->arch.root_mmu.translate_gpa = translate_gpa;
55205528
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
55215529
vcpu->arch.root_mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID;
55225530

55235531
vcpu->arch.guest_mmu.root_hpa = INVALID_PAGE;
5532+
vcpu->arch.guest_mmu.root_cr3 = 0;
55245533
vcpu->arch.guest_mmu.translate_gpa = translate_gpa;
55255534
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
55265535
vcpu->arch.guest_mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID;

0 commit comments

Comments
 (0)