Paritition the function into three sections: - fetching indirect shadow pages (host_level > guest_level) - fetching direct shadow pages (page_level < host_level <= guest_level) - the final spte (page_level == host_level) Instead of the current spaghetti. Signed-off-by: Avi Kivity <avi@xxxxxxxxxx> --- arch/x86/kvm/paging_tmpl.h | 77 ++++++++++++++++++++++--------------------- 1 files changed, 39 insertions(+), 38 deletions(-) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 72f54fe..a7f8295 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -327,9 +327,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, unsigned access = gw->pt_access; struct kvm_mmu_page *sp; u64 *sptep = NULL; - int direct; - gfn_t table_gfn; - int level; + int uninitialized_var(level); bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]); unsigned direct_access; struct kvm_shadow_walk_iterator iterator; @@ -341,55 +339,58 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, if (!dirty) direct_access &= ~ACC_WRITE_MASK; - for_each_shadow_entry(vcpu, addr, iterator) { + for (shadow_walk_init(&iterator, vcpu, addr); + shadow_walk_okay(&iterator) && iterator.level > gw->level; + shadow_walk_next(&iterator)) { + gfn_t table_gfn; + level = iterator.level; sptep = iterator.sptep; - if (iterator.level == hlevel) { - mmu_set_spte(vcpu, sptep, access, - gw->pte_access & access, - user_fault, write_fault, - dirty, ptwrite, level, - gw->gfn, pfn, false, true); - break; + + drop_spte_if_large(vcpu, sptep); + + if (is_shadow_present_pte(*sptep)) + continue; + + table_gfn = gw->table_gfn[level - 2]; + sp = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, + false, access, sptep); + + if (!FNAME(validate_indirect_spte)(vcpu, sptep, sp, + gw, level)) { + kvm_release_pfn_clean(pfn); + return NULL; } - if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) - && level == gw->level) - validate_direct_spte(vcpu, sptep, direct_access); + link_shadow_page(sptep, sp); + } + + for (; + shadow_walk_okay(&iterator) && iterator.level > hlevel; + shadow_walk_next(&iterator)) { + gfn_t direct_gfn; + + level = iterator.level; + sptep = iterator.sptep; drop_spte_if_large(vcpu, sptep); if (is_shadow_present_pte(*sptep)) continue; - if (level <= gw->level) { - direct = 1; - access = direct_access; - - /* - * It is a large guest pages backed by small host pages, - * So we set @direct(@sp->role.direct)=1, and set - * @table_gfn(@sp->gfn)=the base page frame for linear - * translations. - */ - table_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(level) - 1); - } else { - direct = 0; - table_gfn = gw->table_gfn[level - 2]; - } - sp = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, - direct, access, sptep); - if (!direct) - if (!FNAME(validate_indirect_spte)(vcpu, sptep, sp, - gw, level)) { - kvm_release_pfn_clean(pfn); - sptep = NULL; - break; - } + validate_direct_spte(vcpu, sptep, direct_access); + + direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(level) - 1); + sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, level-1, + true, direct_access, sptep); link_shadow_page(sptep, sp); } + mmu_set_spte(vcpu, sptep, access, gw->pte_access & access, + user_fault, write_fault, dirty, ptwrite, level, + gw->gfn, pfn, false, true); + return sptep; } -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html