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