xref: /linux/arch/s390/kvm/gmap/faultin.h (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 
9*1b09c13cSSteffen Eiden #ifndef ARCH_KVM_GMAP_FAULTIN_H
10*1b09c13cSSteffen Eiden #define ARCH_KVM_GMAP_FAULTIN_H
11*1b09c13cSSteffen Eiden 
12*1b09c13cSSteffen Eiden #include <linux/kvm_host.h>
13*1b09c13cSSteffen Eiden 
14*1b09c13cSSteffen Eiden #include "dat.h"
15*1b09c13cSSteffen Eiden 
16*1b09c13cSSteffen Eiden int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fault *f);
17*1b09c13cSSteffen Eiden int kvm_s390_get_guest_page(struct kvm *kvm, struct guest_fault *f, gfn_t gfn, bool w);
18*1b09c13cSSteffen Eiden 
19*1b09c13cSSteffen Eiden static inline int kvm_s390_faultin_gfn_simple(struct kvm_vcpu *vcpu, struct kvm *kvm,
20*1b09c13cSSteffen Eiden 					      gfn_t gfn, bool wr)
21*1b09c13cSSteffen Eiden {
22*1b09c13cSSteffen Eiden 	struct guest_fault f = { .gfn = gfn, .write_attempt = wr, };
23*1b09c13cSSteffen Eiden 
24*1b09c13cSSteffen Eiden 	return kvm_s390_faultin_gfn(vcpu, kvm, &f);
25*1b09c13cSSteffen Eiden }
26*1b09c13cSSteffen Eiden 
27*1b09c13cSSteffen Eiden static inline int kvm_s390_get_guest_page_and_read_gpa(struct kvm *kvm, struct guest_fault *f,
28*1b09c13cSSteffen Eiden 						       gpa_t gaddr, unsigned long *val)
29*1b09c13cSSteffen Eiden {
30*1b09c13cSSteffen Eiden 	int rc;
31*1b09c13cSSteffen Eiden 
32*1b09c13cSSteffen Eiden 	rc = kvm_s390_get_guest_page(kvm, f, gpa_to_gfn(gaddr), false);
33*1b09c13cSSteffen Eiden 	if (rc)
34*1b09c13cSSteffen Eiden 		return rc;
35*1b09c13cSSteffen Eiden 
36*1b09c13cSSteffen Eiden 	*val = *(unsigned long *)phys_to_virt(pfn_to_phys(f->pfn) | offset_in_page(gaddr));
37*1b09c13cSSteffen Eiden 
38*1b09c13cSSteffen Eiden 	return 0;
39*1b09c13cSSteffen Eiden }
40*1b09c13cSSteffen Eiden 
41*1b09c13cSSteffen Eiden static inline void kvm_s390_release_multiple(struct kvm *kvm, struct guest_fault *guest_faults,
42*1b09c13cSSteffen Eiden 					     int n, bool ignore)
43*1b09c13cSSteffen Eiden {
44*1b09c13cSSteffen Eiden 	int i;
45*1b09c13cSSteffen Eiden 
46*1b09c13cSSteffen Eiden 	for (i = 0; i < n; i++) {
47*1b09c13cSSteffen Eiden 		kvm_release_faultin_page(kvm, guest_faults[i].page, ignore,
48*1b09c13cSSteffen Eiden 					 guest_faults[i].write_attempt);
49*1b09c13cSSteffen Eiden 		guest_faults[i].page = NULL;
50*1b09c13cSSteffen Eiden 	}
51*1b09c13cSSteffen Eiden }
52*1b09c13cSSteffen Eiden 
53*1b09c13cSSteffen Eiden static inline bool kvm_s390_multiple_faults_need_retry(struct kvm *kvm, unsigned long seq,
54*1b09c13cSSteffen Eiden 						       struct guest_fault *guest_faults, int n,
55*1b09c13cSSteffen Eiden 						       bool unsafe)
56*1b09c13cSSteffen Eiden {
57*1b09c13cSSteffen Eiden 	int i;
58*1b09c13cSSteffen Eiden 
59*1b09c13cSSteffen Eiden 	for (i = 0; i < n; i++) {
60*1b09c13cSSteffen Eiden 		if (!guest_faults[i].valid)
61*1b09c13cSSteffen Eiden 			continue;
62*1b09c13cSSteffen Eiden 		if (unsafe && mmu_invalidate_retry_gfn_unsafe(kvm, seq, guest_faults[i].gfn))
63*1b09c13cSSteffen Eiden 			return true;
64*1b09c13cSSteffen Eiden 		if (!unsafe && mmu_invalidate_retry_gfn(kvm, seq, guest_faults[i].gfn))
65*1b09c13cSSteffen Eiden 			return true;
66*1b09c13cSSteffen Eiden 	}
67*1b09c13cSSteffen Eiden 	return false;
68*1b09c13cSSteffen Eiden }
69*1b09c13cSSteffen Eiden 
70*1b09c13cSSteffen Eiden static inline int kvm_s390_get_guest_pages(struct kvm *kvm, struct guest_fault *guest_faults,
71*1b09c13cSSteffen Eiden 					   gfn_t start, int n_pages, bool write_attempt)
72*1b09c13cSSteffen Eiden {
73*1b09c13cSSteffen Eiden 	int i, rc;
74*1b09c13cSSteffen Eiden 
75*1b09c13cSSteffen Eiden 	for (i = 0; i < n_pages; i++) {
76*1b09c13cSSteffen Eiden 		rc = kvm_s390_get_guest_page(kvm, guest_faults + i, start + i, write_attempt);
77*1b09c13cSSteffen Eiden 		if (rc)
78*1b09c13cSSteffen Eiden 			break;
79*1b09c13cSSteffen Eiden 	}
80*1b09c13cSSteffen Eiden 	return rc;
81*1b09c13cSSteffen Eiden }
82*1b09c13cSSteffen Eiden 
83*1b09c13cSSteffen Eiden #define kvm_s390_release_faultin_array(kvm, array, ignore) \
84*1b09c13cSSteffen Eiden 	kvm_s390_release_multiple(kvm, array, ARRAY_SIZE(array), ignore)
85*1b09c13cSSteffen Eiden 
86*1b09c13cSSteffen Eiden #define kvm_s390_array_needs_retry_unsafe(kvm, seq, array) \
87*1b09c13cSSteffen Eiden 	kvm_s390_multiple_faults_need_retry(kvm, seq, array, ARRAY_SIZE(array), true)
88*1b09c13cSSteffen Eiden 
89*1b09c13cSSteffen Eiden #define kvm_s390_array_needs_retry_safe(kvm, seq, array) \
90*1b09c13cSSteffen Eiden 	kvm_s390_multiple_faults_need_retry(kvm, seq, array, ARRAY_SIZE(array), false)
91*1b09c13cSSteffen Eiden 
92*1b09c13cSSteffen Eiden #endif /* ARCH_KVM_GMAP_FAULTIN_H */
93