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