xref: /linux/arch/s390/kvm/gmap/faultin.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1*1b09c13cSSteffen Eiden // SPDX-License-Identifier: GPL-2.0
2*1b09c13cSSteffen Eiden /*
3*1b09c13cSSteffen Eiden  *  KVM guest fault handling.
4*1b09c13cSSteffen Eiden  *
5*1b09c13cSSteffen Eiden  *    Copyright IBM Corp. 2025
6*1b09c13cSSteffen Eiden  *    Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
7*1b09c13cSSteffen Eiden  */
8*1b09c13cSSteffen Eiden #include <linux/kvm_types.h>
9*1b09c13cSSteffen Eiden #include <linux/kvm_host.h>
10*1b09c13cSSteffen Eiden 
11*1b09c13cSSteffen Eiden #include "gmap.h"
12*1b09c13cSSteffen Eiden #include "faultin.h"
13*1b09c13cSSteffen Eiden 
14*1b09c13cSSteffen Eiden bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu);
15*1b09c13cSSteffen Eiden #define CREATE_TRACE_POINTS
16*1b09c13cSSteffen Eiden #include "trace_gmap.h"
17*1b09c13cSSteffen Eiden 
18*1b09c13cSSteffen Eiden /*
19*1b09c13cSSteffen Eiden  * kvm_s390_faultin_gfn() - handle a dat fault.
20*1b09c13cSSteffen Eiden  * @vcpu: The vCPU whose gmap is to be fixed up, or NULL if operating on the VM.
21*1b09c13cSSteffen Eiden  * @kvm: The VM whose gmap is to be fixed up, or NULL if operating on a vCPU.
22*1b09c13cSSteffen Eiden  * @f: The guest fault that needs to be resolved.
23*1b09c13cSSteffen Eiden  *
24*1b09c13cSSteffen Eiden  * Return:
25*1b09c13cSSteffen Eiden  * * 0 on success
26*1b09c13cSSteffen Eiden  * * < 0 in case of error
27*1b09c13cSSteffen Eiden  * * > 0 in case of guest exceptions
28*1b09c13cSSteffen Eiden  *
29*1b09c13cSSteffen Eiden  * Context:
30*1b09c13cSSteffen Eiden  * * The mm lock must not be held before calling
31*1b09c13cSSteffen Eiden  * * kvm->srcu must be held
32*1b09c13cSSteffen Eiden  * * may sleep
33*1b09c13cSSteffen Eiden  */
34*1b09c13cSSteffen Eiden int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fault *f)
35*1b09c13cSSteffen Eiden {
36*1b09c13cSSteffen Eiden 	struct kvm_s390_mmu_cache *local_mc __free(kvm_s390_mmu_cache) = NULL;
37*1b09c13cSSteffen Eiden 	struct kvm_s390_mmu_cache *mc = NULL;
38*1b09c13cSSteffen Eiden 	struct kvm_memory_slot *slot;
39*1b09c13cSSteffen Eiden 	unsigned long inv_seq;
40*1b09c13cSSteffen Eiden 	int rc = -EAGAIN;
41*1b09c13cSSteffen Eiden 	int foll;
42*1b09c13cSSteffen Eiden 
43*1b09c13cSSteffen Eiden 	foll = f->write_attempt ? FOLL_WRITE : 0;
44*1b09c13cSSteffen Eiden 	foll |= f->attempt_pfault ? FOLL_NOWAIT : 0;
45*1b09c13cSSteffen Eiden 
46*1b09c13cSSteffen Eiden 	if (vcpu) {
47*1b09c13cSSteffen Eiden 		kvm = vcpu->kvm;
48*1b09c13cSSteffen Eiden 		mc = vcpu->arch.mc;
49*1b09c13cSSteffen Eiden 	}
50*1b09c13cSSteffen Eiden 
51*1b09c13cSSteffen Eiden 	lockdep_assert_held(&kvm->srcu);
52*1b09c13cSSteffen Eiden 
53*1b09c13cSSteffen Eiden 	scoped_guard(read_lock, &kvm->mmu_lock) {
54*1b09c13cSSteffen Eiden 		if (gmap_try_fixup_minor(kvm->arch.gmap, f) == 0)
55*1b09c13cSSteffen Eiden 			return 0;
56*1b09c13cSSteffen Eiden 	}
57*1b09c13cSSteffen Eiden 
58*1b09c13cSSteffen Eiden 	if (!mc) {
59*1b09c13cSSteffen Eiden 		local_mc = kvm_s390_new_mmu_cache();
60*1b09c13cSSteffen Eiden 		if (!local_mc)
61*1b09c13cSSteffen Eiden 			return -ENOMEM;
62*1b09c13cSSteffen Eiden 		mc = local_mc;
63*1b09c13cSSteffen Eiden 	}
64*1b09c13cSSteffen Eiden 
65*1b09c13cSSteffen Eiden 	while (rc == -EAGAIN) {
66*1b09c13cSSteffen Eiden 		f->valid = false;
67*1b09c13cSSteffen Eiden 		inv_seq = kvm->mmu_invalidate_seq;
68*1b09c13cSSteffen Eiden 		/* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */
69*1b09c13cSSteffen Eiden 		smp_rmb();
70*1b09c13cSSteffen Eiden 
71*1b09c13cSSteffen Eiden 		if (vcpu)
72*1b09c13cSSteffen Eiden 			slot = kvm_vcpu_gfn_to_memslot(vcpu, f->gfn);
73*1b09c13cSSteffen Eiden 		else
74*1b09c13cSSteffen Eiden 			slot = gfn_to_memslot(kvm, f->gfn);
75*1b09c13cSSteffen Eiden 		f->pfn = __kvm_faultin_pfn(slot, f->gfn, foll, &f->writable, &f->page);
76*1b09c13cSSteffen Eiden 
77*1b09c13cSSteffen Eiden 		/* Needs I/O, try to setup async pfault (only possible with FOLL_NOWAIT). */
78*1b09c13cSSteffen Eiden 		if (f->pfn == KVM_PFN_ERR_NEEDS_IO) {
79*1b09c13cSSteffen Eiden 			if (unlikely(!f->attempt_pfault))
80*1b09c13cSSteffen Eiden 				return -EAGAIN;
81*1b09c13cSSteffen Eiden 			if (unlikely(!vcpu))
82*1b09c13cSSteffen Eiden 				return -EINVAL;
83*1b09c13cSSteffen Eiden 			trace_kvm_s390_major_guest_pfault(vcpu);
84*1b09c13cSSteffen Eiden 			if (kvm_arch_setup_async_pf(vcpu))
85*1b09c13cSSteffen Eiden 				return 0;
86*1b09c13cSSteffen Eiden 			vcpu->stat.pfault_sync++;
87*1b09c13cSSteffen Eiden 			/* Could not setup async pfault, try again synchronously. */
88*1b09c13cSSteffen Eiden 			foll &= ~FOLL_NOWAIT;
89*1b09c13cSSteffen Eiden 			f->pfn = __kvm_faultin_pfn(slot, f->gfn, foll, &f->writable, &f->page);
90*1b09c13cSSteffen Eiden 		}
91*1b09c13cSSteffen Eiden 
92*1b09c13cSSteffen Eiden 		/* Access outside memory, addressing exception. */
93*1b09c13cSSteffen Eiden 		if (is_noslot_pfn(f->pfn))
94*1b09c13cSSteffen Eiden 			return PGM_ADDRESSING;
95*1b09c13cSSteffen Eiden 		/* Fatal signal pending: bail out. */
96*1b09c13cSSteffen Eiden 		if (is_sigpending_pfn(f->pfn))
97*1b09c13cSSteffen Eiden 			return -EINTR;
98*1b09c13cSSteffen Eiden 		/* Check if it's read-only memory; don't try to actually handle that case. */
99*1b09c13cSSteffen Eiden 		if (f->pfn == KVM_PFN_ERR_RO_FAULT)
100*1b09c13cSSteffen Eiden 			return -EOPNOTSUPP;
101*1b09c13cSSteffen Eiden 		/* Any other error. */
102*1b09c13cSSteffen Eiden 		if (is_error_pfn(f->pfn))
103*1b09c13cSSteffen Eiden 			return -EFAULT;
104*1b09c13cSSteffen Eiden 
105*1b09c13cSSteffen Eiden 		/* Loop, release the faulted page. */
106*1b09c13cSSteffen Eiden 		if (mmu_invalidate_retry_gfn_unsafe(kvm, inv_seq, f->gfn)) {
107*1b09c13cSSteffen Eiden 			kvm_release_faultin_page(kvm, f->page, true, false);
108*1b09c13cSSteffen Eiden 			continue;
109*1b09c13cSSteffen Eiden 		}
110*1b09c13cSSteffen Eiden 
111*1b09c13cSSteffen Eiden 		scoped_guard(read_lock, &kvm->mmu_lock) {
112*1b09c13cSSteffen Eiden 			if (!mmu_invalidate_retry_gfn(kvm, inv_seq, f->gfn)) {
113*1b09c13cSSteffen Eiden 				f->valid = true;
114*1b09c13cSSteffen Eiden 				rc = gmap_link(mc, kvm->arch.gmap, f, slot);
115*1b09c13cSSteffen Eiden 			}
116*1b09c13cSSteffen Eiden 			kvm_release_faultin_page(kvm, f->page, !!rc, f->write_attempt);
117*1b09c13cSSteffen Eiden 		}
118*1b09c13cSSteffen Eiden 
119*1b09c13cSSteffen Eiden 		if (rc == -ENOMEM) {
120*1b09c13cSSteffen Eiden 			rc = kvm_s390_mmu_cache_topup(mc);
121*1b09c13cSSteffen Eiden 			if (rc)
122*1b09c13cSSteffen Eiden 				return rc;
123*1b09c13cSSteffen Eiden 			rc = -EAGAIN;
124*1b09c13cSSteffen Eiden 		}
125*1b09c13cSSteffen Eiden 	}
126*1b09c13cSSteffen Eiden 
127*1b09c13cSSteffen Eiden 	return rc;
128*1b09c13cSSteffen Eiden }
129*1b09c13cSSteffen Eiden 
130*1b09c13cSSteffen Eiden int kvm_s390_get_guest_page(struct kvm *kvm, struct guest_fault *f, gfn_t gfn, bool w)
131*1b09c13cSSteffen Eiden {
132*1b09c13cSSteffen Eiden 	struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
133*1b09c13cSSteffen Eiden 	int foll = w ? FOLL_WRITE : 0;
134*1b09c13cSSteffen Eiden 
135*1b09c13cSSteffen Eiden 	f->write_attempt = w;
136*1b09c13cSSteffen Eiden 	f->gfn = gfn;
137*1b09c13cSSteffen Eiden 	f->pfn = __kvm_faultin_pfn(slot, gfn, foll, &f->writable, &f->page);
138*1b09c13cSSteffen Eiden 	if (is_noslot_pfn(f->pfn))
139*1b09c13cSSteffen Eiden 		return PGM_ADDRESSING;
140*1b09c13cSSteffen Eiden 	if (is_sigpending_pfn(f->pfn))
141*1b09c13cSSteffen Eiden 		return -EINTR;
142*1b09c13cSSteffen Eiden 	if (f->pfn == KVM_PFN_ERR_NEEDS_IO)
143*1b09c13cSSteffen Eiden 		return -EAGAIN;
144*1b09c13cSSteffen Eiden 	if (is_error_pfn(f->pfn))
145*1b09c13cSSteffen Eiden 		return -EFAULT;
146*1b09c13cSSteffen Eiden 
147*1b09c13cSSteffen Eiden 	f->valid = true;
148*1b09c13cSSteffen Eiden 	return 0;
149*1b09c13cSSteffen Eiden }
150