KVM: MMU: return page fault error code from permission_fault
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 8 Mar 2016 09:08:16 +0000 (10:08 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 22 Mar 2016 15:20:54 +0000 (16:20 +0100)
This will help in the implementation of PKRU, where the PK bit of the page
fault error code cannot be computed in advance (unlike I/D, R/W and U/S).

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/mmu.h
arch/x86/kvm/paging_tmpl.h

index 58fe98a0a526c00f1126ee3af212428ff5123b06..8b2b3dfca1ae292742251dc434924c9ffe69517b 100644 (file)
@@ -141,11 +141,15 @@ static inline bool is_write_protection(struct kvm_vcpu *vcpu)
 }
 
 /*
- * Will a fault with a given page-fault error code (pfec) cause a permission
- * fault with the given access (in ACC_* format)?
+ * Check if a given access (described through the I/D, W/R and U/S bits of a
+ * page fault error code pfec) causes a permission fault with the given PTE
+ * access rights (in ACC_* format).
+ *
+ * Return zero if the access does not fault; return the page fault error code
+ * if the access faults.
  */
-static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
-                                   unsigned pte_access, unsigned pfec)
+static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+                                 unsigned pte_access, unsigned pfec)
 {
        int cpl = kvm_x86_ops->get_cpl(vcpu);
        unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
@@ -169,7 +173,8 @@ static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
 
        WARN_ON(pfec & PFERR_RSVD_MASK);
 
-       return (mmu->permissions[index] >> pte_access) & 1;
+       pfec |= PFERR_PRESENT_MASK;
+       return -((mmu->permissions[index] >> pte_access) & 1) & pfec;
 }
 
 void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
index e159a8185ad9af081de317ff6b686d1ee3eb1d4b..45ed3c38d20e6ce0a9f2924664ae86a46755ae38 100644 (file)
@@ -359,10 +359,9 @@ retry_walk:
                walker->ptes[walker->level - 1] = pte;
        } while (!is_last_gpte(mmu, walker->level, pte));
 
-       if (unlikely(permission_fault(vcpu, mmu, pte_access, access))) {
-               errcode |= PFERR_PRESENT_MASK;
+       errcode = permission_fault(vcpu, mmu, pte_access, access);
+       if (unlikely(errcode))
                goto error;
-       }
 
        gfn = gpte_to_gfn_lvl(pte, walker->level);
        gfn += (addr & PT_LVL_OFFSET_MASK(walker->level)) >> PAGE_SHIFT;