return 0;
}
-static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
- struct kvm_s2_trans *nested,
- struct kvm_memory_slot *memslot, unsigned long hva,
- bool fault_is_perm)
+static int kvm_s2_fault_map(struct kvm_s2_fault *fault, void *memcache)
{
- int ret = 0;
- struct kvm_s2_fault fault_data = {
- .vcpu = vcpu,
- .fault_ipa = fault_ipa,
- .nested = nested,
- .memslot = memslot,
- .hva = hva,
- .fault_is_perm = fault_is_perm,
- .ipa = fault_ipa,
- .logging_active = memslot_is_logging(memslot),
- .force_pte = memslot_is_logging(memslot),
- .s2_force_noncacheable = false,
- .vfio_allow_any_uc = false,
- .prot = KVM_PGTABLE_PROT_R,
- };
- struct kvm_s2_fault *fault = &fault_data;
- struct kvm *kvm = vcpu->kvm;
- void *memcache;
+ struct kvm *kvm = fault->vcpu->kvm;
struct kvm_pgtable *pgt;
+ int ret;
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_SHARED;
- if (fault->fault_is_perm)
- fault->fault_granule = kvm_vcpu_trap_get_perm_fault_granule(fault->vcpu);
- fault->write_fault = kvm_is_write_fault(fault->vcpu);
- fault->exec_fault = kvm_vcpu_trap_is_exec_fault(fault->vcpu);
- VM_WARN_ON_ONCE(fault->write_fault && fault->exec_fault);
-
- /*
- * Permission faults just need to update the existing leaf entry,
- * and so normally don't require allocations from the memcache. The
- * only exception to this is when dirty logging is enabled at runtime
- * and a write fault needs to collapse a block entry into a table.
- */
- fault->topup_memcache = !fault->fault_is_perm ||
- (fault->logging_active && fault->write_fault);
- ret = prepare_mmu_memcache(fault->vcpu, fault->topup_memcache, &memcache);
- if (ret)
- return ret;
-
- /*
- * Let's check if we will get back a huge page backed by hugetlbfs, or
- * get block mapping for device MMIO region.
- */
- ret = kvm_s2_fault_pin_pfn(fault);
- if (ret != 1)
- return ret;
-
- ret = 0;
-
- ret = kvm_s2_fault_compute_prot(fault);
- if (ret == 1) {
- ret = 1; /* fault injected */
- goto out_put_page;
- }
- if (ret)
- goto out_put_page;
-
kvm_fault_lock(kvm);
pgt = fault->vcpu->arch.hw_mmu->pgt;
if (mmu_invalidate_retry(kvm, fault->mmu_seq)) {
* PTE, which will be preserved.
*/
fault->prot &= ~KVM_NV_GUEST_MAP_SZ;
- ret = KVM_PGT_FN(kvm_pgtable_stage2_relax_perms)(pgt, fault->fault_ipa, fault->prot,
- flags);
+ ret = KVM_PGT_FN(kvm_pgtable_stage2_relax_perms)(pgt, fault->fault_ipa,
+ fault->prot, flags);
} else {
ret = KVM_PGT_FN(kvm_pgtable_stage2_map)(pgt, fault->fault_ipa, fault->vma_pagesize,
__pfn_to_phys(fault->pfn), fault->prot,
mark_page_dirty_in_slot(kvm, fault->memslot, fault->gfn);
return ret != -EAGAIN ? ret : 0;
+}
+
+static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ struct kvm_s2_trans *nested,
+ struct kvm_memory_slot *memslot, unsigned long hva,
+ bool fault_is_perm)
+{
+ int ret = 0;
+ struct kvm_s2_fault fault_data = {
+ .vcpu = vcpu,
+ .fault_ipa = fault_ipa,
+ .nested = nested,
+ .memslot = memslot,
+ .hva = hva,
+ .fault_is_perm = fault_is_perm,
+ .ipa = fault_ipa,
+ .logging_active = memslot_is_logging(memslot),
+ .force_pte = memslot_is_logging(memslot),
+ .s2_force_noncacheable = false,
+ .vfio_allow_any_uc = false,
+ .prot = KVM_PGTABLE_PROT_R,
+ };
+ struct kvm_s2_fault *fault = &fault_data;
+ void *memcache;
+
+ if (fault->fault_is_perm)
+ fault->fault_granule = kvm_vcpu_trap_get_perm_fault_granule(fault->vcpu);
+ fault->write_fault = kvm_is_write_fault(fault->vcpu);
+ fault->exec_fault = kvm_vcpu_trap_is_exec_fault(fault->vcpu);
+ VM_WARN_ON_ONCE(fault->write_fault && fault->exec_fault);
+
+ /*
+ * Permission faults just need to update the existing leaf entry,
+ * and so normally don't require allocations from the memcache. The
+ * only exception to this is when dirty logging is enabled at runtime
+ * and a write fault needs to collapse a block entry into a table.
+ */
+ fault->topup_memcache = !fault->fault_is_perm ||
+ (fault->logging_active && fault->write_fault);
+ ret = prepare_mmu_memcache(fault->vcpu, fault->topup_memcache, &memcache);
+ if (ret)
+ return ret;
+
+ /*
+ * Let's check if we will get back a huge page backed by hugetlbfs, or
+ * get block mapping for device MMIO region.
+ */
+ ret = kvm_s2_fault_pin_pfn(fault);
+ if (ret != 1)
+ return ret;
+
+ ret = 0;
+
+ ret = kvm_s2_fault_compute_prot(fault);
+ if (ret == 1) {
+ ret = 1; /* fault injected */
+ goto out_put_page;
+ }
+ if (ret)
+ goto out_put_page;
+
+ ret = kvm_s2_fault_map(fault, memcache);
+ return ret;
out_put_page:
kvm_release_page_unused(fault->page);