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