Skip to content

Commit e4e517b

Browse files
committed
KVM: MMU: Do not unconditionally read PDPTE from guest memory
Architecturally, PDPTEs are cached in the PDPTRs when CR3 is reloaded. On SVM, it is not possible to implement this, but on VMX this is possible and was indeed implemented until nested SVM changed this to unconditionally read PDPTEs dynamically. This has noticable impact when running PAE guests. Fix by changing the MMU to read PDPTRs from the cache, falling back to reading from memory for the nested MMU. Signed-off-by: Avi Kivity <avi@redhat.com> Tested-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
1 parent cf3ace7 commit e4e517b

File tree

5 files changed

+21
-9
lines changed

5 files changed

+21
-9
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ struct kvm_mmu {
265265
void (*new_cr3)(struct kvm_vcpu *vcpu);
266266
void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root);
267267
unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);
268+
u64 (*get_pdptr)(struct kvm_vcpu *vcpu, int index);
268269
int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err,
269270
bool prefault);
270271
void (*inject_page_fault)(struct kvm_vcpu *vcpu,

arch/x86/kvm/kvm_cache_regs.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,6 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
4545
return vcpu->arch.walk_mmu->pdptrs[index];
4646
}
4747

48-
static inline u64 kvm_pdptr_read_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, int index)
49-
{
50-
load_pdptrs(vcpu, mmu, mmu->get_cr3(vcpu));
51-
52-
return mmu->pdptrs[index];
53-
}
54-
5548
static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask)
5649
{
5750
ulong tmask = mask & KVM_POSSIBLE_CR0_GUEST_BITS;

arch/x86/kvm/mmu.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2770,7 +2770,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
27702770

27712771
ASSERT(!VALID_PAGE(root));
27722772
if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) {
2773-
pdptr = kvm_pdptr_read_mmu(vcpu, &vcpu->arch.mmu, i);
2773+
pdptr = vcpu->arch.mmu.get_pdptr(vcpu, i);
27742774
if (!is_present_gpte(pdptr)) {
27752775
vcpu->arch.mmu.pae_root[i] = 0;
27762776
continue;
@@ -3318,6 +3318,7 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
33183318
context->direct_map = true;
33193319
context->set_cr3 = kvm_x86_ops->set_tdp_cr3;
33203320
context->get_cr3 = get_cr3;
3321+
context->get_pdptr = kvm_pdptr_read;
33213322
context->inject_page_fault = kvm_inject_page_fault;
33223323
context->nx = is_nx(vcpu);
33233324

@@ -3376,6 +3377,7 @@ static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
33763377

33773378
vcpu->arch.walk_mmu->set_cr3 = kvm_x86_ops->set_cr3;
33783379
vcpu->arch.walk_mmu->get_cr3 = get_cr3;
3380+
vcpu->arch.walk_mmu->get_pdptr = kvm_pdptr_read;
33793381
vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault;
33803382

33813383
return r;
@@ -3386,6 +3388,7 @@ static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
33863388
struct kvm_mmu *g_context = &vcpu->arch.nested_mmu;
33873389

33883390
g_context->get_cr3 = get_cr3;
3391+
g_context->get_pdptr = kvm_pdptr_read;
33893392
g_context->inject_page_fault = kvm_inject_page_fault;
33903393

33913394
/*

arch/x86/kvm/paging_tmpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
163163

164164
#if PTTYPE == 64
165165
if (walker->level == PT32E_ROOT_LEVEL) {
166-
pte = kvm_pdptr_read_mmu(vcpu, mmu, (addr >> 30) & 3);
166+
pte = mmu->get_pdptr(vcpu, (addr >> 30) & 3);
167167
trace_kvm_mmu_paging_element(pte, walker->level);
168168
if (!is_present_gpte(pte))
169169
goto error;

arch/x86/kvm/svm.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,6 +1844,20 @@ static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
18441844
return svm->nested.nested_cr3;
18451845
}
18461846

1847+
static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
1848+
{
1849+
struct vcpu_svm *svm = to_svm(vcpu);
1850+
u64 cr3 = svm->nested.nested_cr3;
1851+
u64 pdpte;
1852+
int ret;
1853+
1854+
ret = kvm_read_guest_page(vcpu->kvm, gpa_to_gfn(cr3), &pdpte,
1855+
offset_in_page(cr3) + index * 8, 8);
1856+
if (ret)
1857+
return 0;
1858+
return pdpte;
1859+
}
1860+
18471861
static void nested_svm_set_tdp_cr3(struct kvm_vcpu *vcpu,
18481862
unsigned long root)
18491863
{
@@ -1875,6 +1889,7 @@ static int nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
18751889

18761890
vcpu->arch.mmu.set_cr3 = nested_svm_set_tdp_cr3;
18771891
vcpu->arch.mmu.get_cr3 = nested_svm_get_tdp_cr3;
1892+
vcpu->arch.mmu.get_pdptr = nested_svm_get_tdp_pdptr;
18781893
vcpu->arch.mmu.inject_page_fault = nested_svm_inject_npf_exit;
18791894
vcpu->arch.mmu.shadow_root_level = get_npt_level();
18801895
vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu;

0 commit comments

Comments
 (0)