KVM: MMU: Convert direct maps to use the generic shadow walker
authorAvi Kivity <avi@qumranet.com>
Fri, 22 Aug 2008 16:28:04 +0000 (19:28 +0300)
committerAvi Kivity <avi@qumranet.com>
Wed, 15 Oct 2008 08:15:23 +0000 (10:15 +0200)
Signed-off-by: Avi Kivity <avi@qumranet.com>
arch/x86/kvm/mmu.c

index 8b95cf748b53022f5bbd8e69e429209e9038978d..a1ca4ff9c11630263618cc395bf41570d3dc777f 100644 (file)
@@ -1260,49 +1260,66 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
 {
 }
 
-static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
-                       int largepage, gfn_t gfn, pfn_t pfn)
-{
-       hpa_t table_addr = vcpu->arch.mmu.root_hpa;
-       int pt_write = 0;
-       int level = vcpu->arch.mmu.shadow_root_level;
-
-       for (; ; level--) {
-               u32 index = PT64_INDEX(v, level);
-               u64 *table;
+struct direct_shadow_walk {
+       struct kvm_shadow_walk walker;
+       pfn_t pfn;
+       int write;
+       int largepage;
+       int pt_write;
+};
 
-               ASSERT(VALID_PAGE(table_addr));
-               table = __va(table_addr);
+static int direct_map_entry(struct kvm_shadow_walk *_walk,
+                           struct kvm_vcpu *vcpu,
+                           gva_t addr, u64 *sptep, int level)
+{
+       struct direct_shadow_walk *walk =
+               container_of(_walk, struct direct_shadow_walk, walker);
+       struct kvm_mmu_page *sp;
+       gfn_t pseudo_gfn;
+       gfn_t gfn = addr >> PAGE_SHIFT;
+
+       if (level == PT_PAGE_TABLE_LEVEL
+           || (walk->largepage && level == PT_DIRECTORY_LEVEL)) {
+               mmu_set_spte(vcpu, sptep, ACC_ALL, ACC_ALL,
+                            0, walk->write, 1, &walk->pt_write,
+                            walk->largepage, gfn, walk->pfn, false);
+               return 1;
+       }
 
-               if (level == 1 || (largepage && level == 2)) {
-                       mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL,
-                                    0, write, 1, &pt_write, largepage,
-                                    gfn, pfn, false);
-                       return pt_write;
+       if (*sptep == shadow_trap_nonpresent_pte) {
+               pseudo_gfn = (addr & PT64_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT;
+               sp = kvm_mmu_get_page(vcpu, pseudo_gfn, addr, level - 1,
+                                     1, ACC_ALL, sptep);
+               if (!sp) {
+                       pgprintk("nonpaging_map: ENOMEM\n");
+                       kvm_release_pfn_clean(walk->pfn);
+                       return -ENOMEM;
                }
 
-               if (table[index] == shadow_trap_nonpresent_pte) {
-                       struct kvm_mmu_page *new_table;
-                       gfn_t pseudo_gfn;
-
-                       pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK)
-                               >> PAGE_SHIFT;
-                       new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
-                                                    v, level - 1,
-                                                    1, ACC_ALL, &table[index]);
-                       if (!new_table) {
-                               pgprintk("nonpaging_map: ENOMEM\n");
-                               kvm_release_pfn_clean(pfn);
-                               return -ENOMEM;
-                       }
-
-                       set_shadow_pte(&table[index],
-                                      __pa(new_table->spt)
-                                      | PT_PRESENT_MASK | PT_WRITABLE_MASK
-                                      | shadow_user_mask | shadow_x_mask);
-               }
-               table_addr = table[index] & PT64_BASE_ADDR_MASK;
+               set_shadow_pte(sptep,
+                              __pa(sp->spt)
+                              | PT_PRESENT_MASK | PT_WRITABLE_MASK
+                              | shadow_user_mask | shadow_x_mask);
        }
+       return 0;
+}
+
+static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
+                       int largepage, gfn_t gfn, pfn_t pfn)
+{
+       int r;
+       struct direct_shadow_walk walker = {
+               .walker = { .entry = direct_map_entry, },
+               .pfn = pfn,
+               .largepage = largepage,
+               .write = write,
+               .pt_write = 0,
+       };
+
+       r = walk_shadow(&walker.walker, vcpu, (gva_t)gfn << PAGE_SHIFT);
+       if (r < 0)
+               return r;
+       return walker.pt_write;
 }
 
 static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)