Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a98205d authored by Xiao Guangrong's avatar Xiao Guangrong Committed by Paolo Bonzini
Browse files

KVM: MMU: fix permission_fault()



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: default avatarXiao Guangrong <guangrong.xiao@linux.intel.com>
[Do not assume pfec.p=1. - Paolo]
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 4a6cd3ba
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -360,7 +360,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
			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;
		}