KVM: s390: Simplify and move pv code
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Wed, 28 May 2025 09:55:02 +0000 (11:55 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Wed, 28 May 2025 15:48:04 +0000 (17:48 +0200)
All functions in kvm/gmap.c fit better in kvm/pv.c instead.
Move and rename them appropriately, then delete the now empty
kvm/gmap.c and kvm/gmap.h.

Reviewed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Link: https://lore.kernel.org/r/20250528095502.226213-5-imbrenda@linux.ibm.com
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20250528095502.226213-5-imbrenda@linux.ibm.com>

arch/s390/kernel/uv.c
arch/s390/kvm/Makefile
arch/s390/kvm/gaccess.c
arch/s390/kvm/gmap-vsie.c
arch/s390/kvm/gmap.c [deleted file]
arch/s390/kvm/gmap.h [deleted file]
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/pv.c
arch/s390/kvm/vsie.c

index d278bf0c09d1b3af2d54c92cfb0ec34a634a430c..cdbdc1fc8964155d8ea7f392f548bd456cc58775 100644 (file)
@@ -136,7 +136,7 @@ int uv_destroy_folio(struct folio *folio)
 {
        int rc;
 
-       /* See gmap_make_secure(): large folios cannot be secure */
+       /* Large folios cannot be secure */
        if (unlikely(folio_test_large(folio)))
                return 0;
 
@@ -185,7 +185,7 @@ int uv_convert_from_secure_folio(struct folio *folio)
 {
        int rc;
 
-       /* See gmap_make_secure(): large folios cannot be secure */
+       /* Large folios cannot be secure */
        if (unlikely(folio_test_large(folio)))
                return 0;
 
@@ -462,15 +462,15 @@ EXPORT_SYMBOL_GPL(make_hva_secure);
 
 /*
  * To be called with the folio locked or with an extra reference! This will
- * prevent gmap_make_secure from touching the folio concurrently. Having 2
- * parallel arch_make_folio_accessible is fine, as the UV calls will become a
- * no-op if the folio is already exported.
+ * prevent kvm_s390_pv_make_secure() from touching the folio concurrently.
+ * Having 2 parallel arch_make_folio_accessible is fine, as the UV calls will
+ * become a no-op if the folio is already exported.
  */
 int arch_make_folio_accessible(struct folio *folio)
 {
        int rc = 0;
 
-       /* See gmap_make_secure(): large folios cannot be secure */
+       /* Large folios cannot be secure */
        if (unlikely(folio_test_large(folio)))
                return 0;
 
index f0ffe874adc21b2ce4b90806ac3571ca92a41d24..9a723c48b05ad6b2f35b94311f1361ec6c335990 100644 (file)
@@ -8,7 +8,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o gmap.o gmap-vsie.o
+kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o gmap-vsie.o
 
 kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
 obj-$(CONFIG_KVM) += kvm.o
index f6fded15633ad87f6b02c2c42aea35a3c9164253..e23670e1949cfe3b2b3f54fe68c4c1b642f56e60 100644 (file)
 #include <asm/gmap.h>
 #include <asm/dat-bits.h>
 #include "kvm-s390.h"
-#include "gmap.h"
 #include "gaccess.h"
 
+#define GMAP_SHADOW_FAKE_TABLE 1ULL
+
 /*
  * vaddress union in order to easily decode a virtual address into its
  * region first index, region second index etc. parts.
index a6d1dbb04c9707c70ad1809bc17785ff2167f054..56ef153eb8fec03bdf9be2ba3acc603da71edd61 100644 (file)
@@ -22,7 +22,6 @@
 #include <asm/uv.h>
 
 #include "kvm-s390.h"
-#include "gmap.h"
 
 /**
  * gmap_find_shadow - find a specific asce in the list of shadow tables
diff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap.c
deleted file mode 100644 (file)
index 6d8944d..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Guest memory management for KVM/s390
- *
- * Copyright IBM Corp. 2008, 2020, 2024
- *
- *    Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
- *               Martin Schwidefsky <schwidefsky@de.ibm.com>
- *               David Hildenbrand <david@redhat.com>
- *               Janosch Frank <frankja@linux.vnet.ibm.com>
- */
-
-#include <linux/compiler.h>
-#include <linux/kvm.h>
-#include <linux/kvm_host.h>
-#include <linux/pgtable.h>
-#include <linux/pagemap.h>
-
-#include <asm/lowcore.h>
-#include <asm/gmap.h>
-#include <asm/uv.h>
-
-#include "gmap.h"
-
-/**
- * gmap_make_secure() - make one guest page secure
- * @gmap: the guest gmap
- * @gaddr: the guest address that needs to be made secure
- * @uvcb: the UVCB specifying which operation needs to be performed
- *
- * Context: needs to be called with kvm->srcu held.
- * Return: 0 on success, < 0 in case of error.
- */
-int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
-{
-       struct kvm *kvm = gmap->private;
-       unsigned long vmaddr;
-
-       lockdep_assert_held(&kvm->srcu);
-
-       vmaddr = gfn_to_hva(kvm, gpa_to_gfn(gaddr));
-       if (kvm_is_error_hva(vmaddr))
-               return -EFAULT;
-       return make_hva_secure(gmap->mm, vmaddr, uvcb);
-}
-
-int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
-{
-       struct uv_cb_cts uvcb = {
-               .header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
-               .header.len = sizeof(uvcb),
-               .guest_handle = gmap->guest_handle,
-               .gaddr = gaddr,
-       };
-
-       return gmap_make_secure(gmap, gaddr, &uvcb);
-}
-
-/**
- * __gmap_destroy_page() - Destroy a guest page.
- * @gmap: the gmap of the guest
- * @page: the page to destroy
- *
- * An attempt will be made to destroy the given guest page. If the attempt
- * fails, an attempt is made to export the page. If both attempts fail, an
- * appropriate error is returned.
- *
- * Context: must be called holding the mm lock for gmap->mm
- */
-static int __gmap_destroy_page(struct gmap *gmap, struct page *page)
-{
-       struct folio *folio = page_folio(page);
-       int rc;
-
-       /*
-        * See gmap_make_secure(): large folios cannot be secure. Small
-        * folio implies FW_LEVEL_PTE.
-        */
-       if (folio_test_large(folio))
-               return -EFAULT;
-
-       rc = uv_destroy_folio(folio);
-       /*
-        * Fault handlers can race; it is possible that two CPUs will fault
-        * on the same secure page. One CPU can destroy the page, reboot,
-        * re-enter secure mode and import it, while the second CPU was
-        * stuck at the beginning of the handler. At some point the second
-        * CPU will be able to progress, and it will not be able to destroy
-        * the page. In that case we do not want to terminate the process,
-        * we instead try to export the page.
-        */
-       if (rc)
-               rc = uv_convert_from_secure_folio(folio);
-
-       return rc;
-}
-
-/**
- * gmap_destroy_page() - Destroy a guest page.
- * @gmap: the gmap of the guest
- * @gaddr: the guest address to destroy
- *
- * An attempt will be made to destroy the given guest page. If the attempt
- * fails, an attempt is made to export the page. If both attempts fail, an
- * appropriate error is returned.
- *
- * Context: may sleep.
- */
-int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr)
-{
-       struct page *page;
-       int rc = 0;
-
-       mmap_read_lock(gmap->mm);
-       page = gfn_to_page(gmap->private, gpa_to_gfn(gaddr));
-       if (page)
-               rc = __gmap_destroy_page(gmap, page);
-       kvm_release_page_clean(page);
-       mmap_read_unlock(gmap->mm);
-       return rc;
-}
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
deleted file mode 100644 (file)
index c8f031c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  KVM guest address space mapping code
- *
- *    Copyright IBM Corp. 2007, 2016, 2025
- *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
- *               Claudio Imbrenda <imbrenda@linux.ibm.com>
- */
-
-#ifndef ARCH_KVM_S390_GMAP_H
-#define ARCH_KVM_S390_GMAP_H
-
-#define GMAP_SHADOW_FAKE_TABLE 1ULL
-
-int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
-int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
-int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
-struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, int edat_level);
-
-/**
- * gmap_shadow_valid - check if a shadow guest address space matches the
- *                     given properties and is still valid
- * @sg: pointer to the shadow guest address space structure
- * @asce: ASCE for which the shadow table is requested
- * @edat_level: edat level to be used for the shadow translation
- *
- * Returns 1 if the gmap shadow is still valid and matches the given
- * properties, the caller can continue using it. Returns 0 otherwise, the
- * caller has to request a new shadow gmap in this case.
- *
- */
-static inline int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
-{
-       if (sg->removed)
-               return 0;
-       return sg->orig_asce == asce && sg->edat_level == edat_level;
-}
-
-#endif
index b4834bd4d21666f2080233eb8ba8f4ef4527976a..c7908950c1f44dd76ad5ace223e06afeed74608d 100644 (file)
 #include <asm/irq.h>
 #include <asm/sysinfo.h>
 #include <asm/uv.h>
-#include <asm/gmap.h>
 
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "trace.h"
 #include "trace-s390.h"
-#include "gmap.h"
 
 u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
 {
@@ -546,7 +544,7 @@ static int handle_pv_uvc(struct kvm_vcpu *vcpu)
                          guest_uvcb->header.cmd);
                return 0;
        }
-       rc = gmap_make_secure(vcpu->arch.gmap, uvcb.gaddr, &uvcb);
+       rc = kvm_s390_pv_make_secure(vcpu->kvm, uvcb.gaddr, &uvcb);
        /*
         * If the unpin did not succeed, the guest will exit again for the UVC
         * and we will retry the unpin.
@@ -654,10 +652,8 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
                break;
        case ICPT_PV_PREF:
                rc = 0;
-               gmap_convert_to_secure(vcpu->arch.gmap,
-                                      kvm_s390_get_prefix(vcpu));
-               gmap_convert_to_secure(vcpu->arch.gmap,
-                                      kvm_s390_get_prefix(vcpu) + PAGE_SIZE);
+               kvm_s390_pv_convert_to_secure(vcpu->kvm, kvm_s390_get_prefix(vcpu));
+               kvm_s390_pv_convert_to_secure(vcpu->kvm, kvm_s390_get_prefix(vcpu) + PAGE_SIZE);
                break;
        default:
                return -EOPNOTSUPP;
index 10cfc047525ddc71ff23bf8303300ad37efc5865..d5ad10791c25fa0939d61b3c4187a108b1ded1b1 100644 (file)
@@ -53,7 +53,6 @@
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "pci.h"
-#include "gmap.h"
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -4976,7 +4975,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
                 * previous protected guest. The old pages need to be destroyed
                 * so the new guest can use them.
                 */
-               if (gmap_destroy_page(vcpu->arch.gmap, gaddr)) {
+               if (kvm_s390_pv_destroy_page(vcpu->kvm, gaddr)) {
                        /*
                         * Either KVM messed up the secure guest mapping or the
                         * same page is mapped into multiple secure guests.
@@ -4998,7 +4997,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
                 * guest has not been imported yet. Try to import the page into
                 * the protected guest.
                 */
-               rc = gmap_convert_to_secure(vcpu->arch.gmap, gaddr);
+               rc = kvm_s390_pv_convert_to_secure(vcpu->kvm, gaddr);
                if (rc == -EINVAL)
                        send_sig(SIGSEGV, current, 0);
                if (rc != -ENXIO)
index 8d3bbb2dd8d27802bbde2a7bd1378033ad614b8e..c44fe0c3a097cf12af23fa2293411110d957e136 100644 (file)
@@ -308,6 +308,9 @@ int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user,
                                u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc);
 int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user,
                              u16 *rc, u16 *rrc);
+int kvm_s390_pv_destroy_page(struct kvm *kvm, unsigned long gaddr);
+int kvm_s390_pv_convert_to_secure(struct kvm *kvm, unsigned long gaddr);
+int kvm_s390_pv_make_secure(struct kvm *kvm, unsigned long gaddr, void *uvcb);
 
 static inline u64 kvm_s390_pv_get_handle(struct kvm *kvm)
 {
@@ -319,6 +322,41 @@ static inline u64 kvm_s390_pv_cpu_get_handle(struct kvm_vcpu *vcpu)
        return vcpu->arch.pv.handle;
 }
 
+/**
+ * __kvm_s390_pv_destroy_page() - Destroy a guest page.
+ * @page: the page to destroy
+ *
+ * An attempt will be made to destroy the given guest page. If the attempt
+ * fails, an attempt is made to export the page. If both attempts fail, an
+ * appropriate error is returned.
+ *
+ * Context: must be called holding the mm lock for gmap->mm
+ */
+static inline int __kvm_s390_pv_destroy_page(struct page *page)
+{
+       struct folio *folio = page_folio(page);
+       int rc;
+
+       /* Large folios cannot be secure. Small folio implies FW_LEVEL_PTE. */
+       if (folio_test_large(folio))
+               return -EFAULT;
+
+       rc = uv_destroy_folio(folio);
+       /*
+        * Fault handlers can race; it is possible that two CPUs will fault
+        * on the same secure page. One CPU can destroy the page, reboot,
+        * re-enter secure mode and import it, while the second CPU was
+        * stuck at the beginning of the handler. At some point the second
+        * CPU will be able to progress, and it will not be able to destroy
+        * the page. In that case we do not want to terminate the process,
+        * we instead try to export the page.
+        */
+       if (rc)
+               rc = uv_convert_from_secure_folio(folio);
+
+       return rc;
+}
+
 /* implemented in interrupt.c */
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
@@ -398,6 +436,10 @@ void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, unsigned long start,
                                 unsigned long end);
 void kvm_s390_vsie_init(struct kvm *kvm);
 void kvm_s390_vsie_destroy(struct kvm *kvm);
+int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level);
+
+/* implemented in gmap-vsie.c */
+struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, int edat_level);
 
 /* implemented in sigp.c */
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
index 22c012aa5206b4e084e9887948ff180a0a50ba6e..14c330ec8cebeca86555d1eee60cef80553b61e5 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/sched/mm.h>
 #include <linux/mmu_notifier.h>
 #include "kvm-s390.h"
-#include "gmap.h"
 
 bool kvm_s390_pv_is_protected(struct kvm *kvm)
 {
@@ -33,6 +32,64 @@ bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_s390_pv_cpu_is_protected);
 
+/**
+ * kvm_s390_pv_make_secure() - make one guest page secure
+ * @kvm: the guest
+ * @gaddr: the guest address that needs to be made secure
+ * @uvcb: the UVCB specifying which operation needs to be performed
+ *
+ * Context: needs to be called with kvm->srcu held.
+ * Return: 0 on success, < 0 in case of error.
+ */
+int kvm_s390_pv_make_secure(struct kvm *kvm, unsigned long gaddr, void *uvcb)
+{
+       unsigned long vmaddr;
+
+       lockdep_assert_held(&kvm->srcu);
+
+       vmaddr = gfn_to_hva(kvm, gpa_to_gfn(gaddr));
+       if (kvm_is_error_hva(vmaddr))
+               return -EFAULT;
+       return make_hva_secure(kvm->mm, vmaddr, uvcb);
+}
+
+int kvm_s390_pv_convert_to_secure(struct kvm *kvm, unsigned long gaddr)
+{
+       struct uv_cb_cts uvcb = {
+               .header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
+               .header.len = sizeof(uvcb),
+               .guest_handle = kvm_s390_pv_get_handle(kvm),
+               .gaddr = gaddr,
+       };
+
+       return kvm_s390_pv_make_secure(kvm, gaddr, &uvcb);
+}
+
+/**
+ * kvm_s390_pv_destroy_page() - Destroy a guest page.
+ * @kvm: the guest
+ * @gaddr: the guest address to destroy
+ *
+ * An attempt will be made to destroy the given guest page. If the attempt
+ * fails, an attempt is made to export the page. If both attempts fail, an
+ * appropriate error is returned.
+ *
+ * Context: may sleep.
+ */
+int kvm_s390_pv_destroy_page(struct kvm *kvm, unsigned long gaddr)
+{
+       struct page *page;
+       int rc = 0;
+
+       mmap_read_lock(kvm->mm);
+       page = gfn_to_page(kvm, gpa_to_gfn(gaddr));
+       if (page)
+               rc = __kvm_s390_pv_destroy_page(page);
+       kvm_release_page_clean(page);
+       mmap_read_unlock(kvm->mm);
+       return rc;
+}
+
 /**
  * struct pv_vm_to_be_destroyed - Represents a protected VM that needs to
  * be destroyed
@@ -638,7 +695,7 @@ static int unpack_one(struct kvm *kvm, unsigned long addr, u64 tweak,
                .tweak[0] = tweak,
                .tweak[1] = offset,
        };
-       int ret = gmap_make_secure(kvm->arch.gmap, addr, &uvcb);
+       int ret = kvm_s390_pv_make_secure(kvm, addr, &uvcb);
        unsigned long vmaddr;
        bool unlocked;
 
index a78df3a4f353093617bc166ed8f4dd332fd6b08e..13a9661d2b28b9039a4a4626db22c4d501060c00 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/facility.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
-#include "gmap.h"
 
 enum vsie_page_flags {
        VSIE_PAGE_IN_USE = 0,
@@ -68,6 +67,24 @@ struct vsie_page {
        __u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
 };
 
+/**
+ * gmap_shadow_valid() - check if a shadow guest address space matches the
+ *                       given properties and is still valid
+ * @sg: pointer to the shadow guest address space structure
+ * @asce: ASCE for which the shadow table is requested
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * Returns 1 if the gmap shadow is still valid and matches the given
+ * properties, the caller can continue using it. Returns 0 otherwise; the
+ * caller has to request a new shadow gmap in this case.
+ */
+int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
+{
+       if (sg->removed)
+               return 0;
+       return sg->orig_asce == asce && sg->edat_level == edat_level;
+}
+
 /* trigger a validity icpt for the given scb */
 static int set_validity_icpt(struct kvm_s390_sie_block *scb,
                             __u16 reason_code)