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