user_mem_abort always creates a brand new PTE, even when handling a permission fault. This is semantically wrong, as such a fault should be handled by reading the existing entry and modifying it. Convert user_mem_abort to stage2_get_pte()/stage2_set_pte_at(), gicing the opportunity to test the present bit, and only use the default PTE if nothing was present yet. Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx> --- arch/arm/kvm/mmu.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 8fde75b..d033344 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -519,7 +519,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, gfn_t gfn, struct kvm_memory_slot *memslot, unsigned long fault_status) { - pte_t new_pte; + pte_t new_pte, *ptep; pfn_t pfn; int ret; bool write_fault, writable; @@ -553,17 +553,24 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (is_error_pfn(pfn)) return -EFAULT; - new_pte = pfn_pte(pfn, PAGE_S2); coherent_icache_guest_page(vcpu->kvm, gfn); spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu->kvm, mmu_seq)) goto out_unlock; + + ptep = stage2_get_pte(vcpu->kvm, memcache, fault_ipa); + if (pte_present(*ptep)) + new_pte = *ptep; + else + new_pte = pfn_pte(pfn, PAGE_S2); + if (writable) { kvm_set_s2pte_writable(&new_pte); kvm_set_pfn_dirty(pfn); } - stage2_set_pte(vcpu->kvm, memcache, fault_ipa, &new_pte); + + stage2_set_pte_at(vcpu->kvm, fault_ipa, ptep, new_pte); out_unlock: spin_unlock(&vcpu->kvm->mmu_lock); -- 1.8.1.2 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm