Merge tag 'kvm-arm-for-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm...
[linux-2.6-block.git] / arch / x86 / kvm / paging_tmpl.h
index 2ce4f05e81d3804cef4ded542a105a5a917b8bed..e159a8185ad9af081de317ff6b686d1ee3eb1d4b 100644 (file)
@@ -189,8 +189,11 @@ static inline unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, u64 gpte)
                ((gpte & VMX_EPT_EXECUTABLE_MASK) ? ACC_EXEC_MASK : 0) |
                ACC_USER_MASK;
 #else
-       access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
-       access &= ~(gpte >> PT64_NX_SHIFT);
+       BUILD_BUG_ON(ACC_EXEC_MASK != PT_PRESENT_MASK);
+       BUILD_BUG_ON(ACC_EXEC_MASK != 1);
+       access = gpte & (PT_WRITABLE_MASK | PT_USER_MASK | PT_PRESENT_MASK);
+       /* Combine NX with P (which is set here) to get ACC_EXEC_MASK.  */
+       access ^= (gpte >> PT64_NX_SHIFT);
 #endif
 
        return access;
@@ -702,23 +705,16 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
 
        pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
 
-       if (unlikely(error_code & PFERR_RSVD_MASK)) {
-               r = handle_mmio_page_fault(vcpu, addr, mmu_is_nested(vcpu));
-               if (likely(r != RET_MMIO_PF_INVALID))
-                       return r;
-
-               /*
-                * page fault with PFEC.RSVD  = 1 is caused by shadow
-                * page fault, should not be used to walk guest page
-                * table.
-                */
-               error_code &= ~PFERR_RSVD_MASK;
-       };
-
        r = mmu_topup_memory_caches(vcpu);
        if (r)
                return r;
 
+       /*
+        * If PFEC.RSVD is set, this is a shadow page fault.
+        * The bit needs to be cleared before walking guest page tables.
+        */
+       error_code &= ~PFERR_RSVD_MASK;
+
        /*
         * Look up the guest pte for the faulting address.
         */
@@ -735,6 +731,11 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
                return 0;
        }
 
+       if (page_fault_handle_page_track(vcpu, error_code, walker.gfn)) {
+               shadow_page_table_clear_flood(vcpu, addr);
+               return 1;
+       }
+
        vcpu->arch.write_fault_to_shadow_pgtable = false;
 
        is_self_change_mapping = FNAME(is_self_change_mapping)(vcpu,
@@ -945,7 +946,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 
                if (kvm_vcpu_read_guest_atomic(vcpu, pte_gpa, &gpte,
                                               sizeof(pt_element_t)))
-                       return -EINVAL;
+                       return 0;
 
                if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) {
                        vcpu->kvm->tlbs_dirty++;
@@ -977,7 +978,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
                         host_writable);
        }
 
-       return !nr_present;
+       return nr_present;
 }
 
 #undef pt_element_t