KVM: MMU: fix permission_fault()
authorXiao Guangrong <guangrong.xiao@linux.intel.com>
Fri, 25 Mar 2016 13:19:35 +0000 (21:19 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Sun, 10 Apr 2016 19:53:49 +0000 (21:53 +0200)
kvm-unit-tests complained about the PFEC is not set properly, e.g,:
test pte.rw pte.d pte.nx pde.p pde.rw pde.pse user fetch: FAIL: error code 15
expected 5
Dump mapping: address: 0x123400000000
------L4: 3e95007
------L3: 3e96007
------L2: 2000083

It's caused by the reason that PFEC returned to guest is copied from the
PFEC triggered by shadow page table

This patch fixes it and makes the logic of updating errcode more clean

Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
[Do not assume pfec.p=1. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/mmu.h
arch/x86/kvm/paging_tmpl.h

index b70df72e2b33d417307d01f57bca57388650d34f..66b33b96a31b47138c9fef94c20e034d07678cb7 100644 (file)
@@ -173,10 +173,9 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
        int index = (pfec >> 1) +
                    (smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
        bool fault = (mmu->permissions[index] >> pte_access) & 1;
+       u32 errcode = PFERR_PRESENT_MASK;
 
        WARN_ON(pfec & (PFERR_PK_MASK | PFERR_RSVD_MASK));
-       pfec |= PFERR_PRESENT_MASK;
-
        if (unlikely(mmu->pkru_mask)) {
                u32 pkru_bits, offset;
 
@@ -189,15 +188,15 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
                pkru_bits = (kvm_read_pkru(vcpu) >> (pte_pkey * 2)) & 3;
 
                /* clear present bit, replace PFEC.RSVD with ACC_USER_MASK. */
-               offset = pfec - 1 +
+               offset = (pfec & ~1) +
                        ((pte_access & PT_USER_MASK) << (PFERR_RSVD_BIT - PT_USER_SHIFT));
 
                pkru_bits &= mmu->pkru_mask >> offset;
-               pfec |= -pkru_bits & PFERR_PK_MASK;
+               errcode |= -pkru_bits & PFERR_PK_MASK;
                fault |= (pkru_bits != 0);
        }
 
-       return -(uint32_t)fault & pfec;
+       return -(u32)fault & errcode;
 }
 
 void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
index 1d971c7553c3847f0d1335487ce551a19875b709..bc019f70e0b6bb374d851bdb3be32ea09e49768b 100644 (file)
@@ -360,7 +360,7 @@ retry_walk:
                        goto error;
 
                if (unlikely(is_rsvd_bits_set(mmu, pte, walker->level))) {
-                       errcode |= PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
+                       errcode = PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
                        goto error;
                }