KVM: MMU: fix for calculating gpa in invlpg code
[safe/jmp/linux-2.6] / arch / x86 / kvm / paging_tmpl.h
index d9dea28..3464fdb 100644 (file)
@@ -190,10 +190,10 @@ walk:
 
                if ((walker->level == PT_PAGE_TABLE_LEVEL) ||
                    ((walker->level == PT_DIRECTORY_LEVEL) &&
-                               (pte & PT_PAGE_SIZE_MASK)  &&
+                               is_large_pte(pte) &&
                                (PTTYPE == 64 || is_pse(vcpu))) ||
                    ((walker->level == PT_PDPE_LEVEL) &&
-                               (pte & PT_PAGE_SIZE_MASK)  &&
+                               is_large_pte(pte) &&
                                is_long_mode(vcpu))) {
                        int lvl = walker->level;
 
@@ -478,8 +478,13 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
                    ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) ||
                    ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) {
                        struct kvm_mmu_page *sp = page_header(__pa(sptep));
+                       int offset, shift;
 
-                       pte_gpa = (sp->gfn << PAGE_SHIFT);
+                       shift = PAGE_SHIFT -
+                                 (PT_LEVEL_BITS - PT64_LEVEL_BITS) * level;
+                       offset = sp->role.quadrant << shift;
+
+                       pte_gpa = (sp->gfn << PAGE_SHIFT) + offset;
                        pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t);
 
                        if (is_shadow_present_pte(*sptep)) {
@@ -572,12 +577,15 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
        int i, offset, nr_present;
        bool reset_host_protection;
+       gpa_t first_pte_gpa;
 
        offset = nr_present = 0;
 
        if (PTTYPE == 32)
                offset = sp->role.quadrant << PT64_LEVEL_BITS;
 
+       first_pte_gpa = gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t);
+
        for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
                unsigned pte_access;
                pt_element_t gpte;
@@ -587,8 +595,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
                if (!is_shadow_present_pte(sp->spt[i]))
                        continue;
 
-               pte_gpa = gfn_to_gpa(sp->gfn);
-               pte_gpa += (i+offset) * sizeof(pt_element_t);
+               pte_gpa = first_pte_gpa + i * sizeof(pt_element_t);
 
                if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte,
                                          sizeof(pt_element_t)))