summaryrefslogtreecommitdiff
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2026-02-11 18:52:27 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2026-02-11 18:52:27 +0100
commitb1195183ed42f1522fae3fe44ebee3af437aa000 (patch)
treea0ea8797c7b816bf50fe57b0a549da325afbd88d /arch/s390/kernel
parentbf2c3138ae3694d4687cbe451c774c288ae2ad06 (diff)
parente3372ffb5f9e2dda3da259b768aab6271672b90d (diff)
Merge tag 'kvm-s390-next-7.0-1' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD
- gmap rewrite: completely new memory management for kvm/s390 - vSIE improvement - maintainership change for s390 vfio-pci - small quality of life improvement for protected guests
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/uv.c142
1 files changed, 23 insertions, 119 deletions
diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c
index ed46950be86f..a284f98d9716 100644
--- a/arch/s390/kernel/uv.c
+++ b/arch/s390/kernel/uv.c
@@ -134,14 +134,15 @@ static int uv_destroy(unsigned long paddr)
*/
int uv_destroy_folio(struct folio *folio)
{
+ unsigned long i;
int rc;
- /* Large folios cannot be secure */
- if (unlikely(folio_test_large(folio)))
- return 0;
-
folio_get(folio);
- rc = uv_destroy(folio_to_phys(folio));
+ for (i = 0; i < (1 << folio_order(folio)); i++) {
+ rc = uv_destroy(folio_to_phys(folio) + i * PAGE_SIZE);
+ if (rc)
+ break;
+ }
if (!rc)
clear_bit(PG_arch_1, &folio->flags.f);
folio_put(folio);
@@ -183,14 +184,15 @@ EXPORT_SYMBOL_GPL(uv_convert_from_secure);
*/
int uv_convert_from_secure_folio(struct folio *folio)
{
+ unsigned long i;
int rc;
- /* Large folios cannot be secure */
- if (unlikely(folio_test_large(folio)))
- return 0;
-
folio_get(folio);
- rc = uv_convert_from_secure(folio_to_phys(folio));
+ for (i = 0; i < (1 << folio_order(folio)); i++) {
+ rc = uv_convert_from_secure(folio_to_phys(folio) + i * PAGE_SIZE);
+ if (rc)
+ break;
+ }
if (!rc)
clear_bit(PG_arch_1, &folio->flags.f);
folio_put(folio);
@@ -207,39 +209,6 @@ int uv_convert_from_secure_pte(pte_t pte)
return uv_convert_from_secure_folio(pfn_folio(pte_pfn(pte)));
}
-/**
- * should_export_before_import - Determine whether an export is needed
- * before an import-like operation
- * @uvcb: the Ultravisor control block of the UVC to be performed
- * @mm: the mm of the process
- *
- * Returns whether an export is needed before every import-like operation.
- * This is needed for shared pages, which don't trigger a secure storage
- * exception when accessed from a different guest.
- *
- * Although considered as one, the Unpin Page UVC is not an actual import,
- * so it is not affected.
- *
- * No export is needed also when there is only one protected VM, because the
- * page cannot belong to the wrong VM in that case (there is no "other VM"
- * it can belong to).
- *
- * Return: true if an export is needed before every import, otherwise false.
- */
-static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
-{
- /*
- * The misc feature indicates, among other things, that importing a
- * shared page from a different protected VM will automatically also
- * transfer its ownership.
- */
- if (uv_has_feature(BIT_UV_FEAT_MISC))
- return false;
- if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
- return false;
- return atomic_read(&mm->context.protected_count) > 1;
-}
-
/*
* Calculate the expected ref_count for a folio that would otherwise have no
* further pins. This was cribbed from similar functions in other places in
@@ -279,7 +248,7 @@ static int expected_folio_refs(struct folio *folio)
* (it's the same logic as split_folio()), and the folio must be
* locked.
*/
-static int __make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
+int __make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
{
int expected, cc = 0;
@@ -309,20 +278,7 @@ static int __make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
return -EAGAIN;
return uvcb->rc == 0x10a ? -ENXIO : -EINVAL;
}
-
-static int make_folio_secure(struct mm_struct *mm, struct folio *folio, struct uv_cb_header *uvcb)
-{
- int rc;
-
- if (!folio_trylock(folio))
- return -EAGAIN;
- if (should_export_before_import(uvcb, mm))
- uv_convert_from_secure(folio_to_phys(folio));
- rc = __make_folio_secure(folio, uvcb);
- folio_unlock(folio);
-
- return rc;
-}
+EXPORT_SYMBOL(__make_folio_secure);
/**
* s390_wiggle_split_folio() - try to drain extra references to a folio and
@@ -337,7 +293,7 @@ static int make_folio_secure(struct mm_struct *mm, struct folio *folio, struct u
* but another attempt can be made;
* -EINVAL in case of other folio splitting errors. See split_folio().
*/
-static int s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio)
+int s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio)
{
int rc, tried_splits;
@@ -409,56 +365,7 @@ static int s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio)
}
return -EAGAIN;
}
-
-int make_hva_secure(struct mm_struct *mm, unsigned long hva, struct uv_cb_header *uvcb)
-{
- struct vm_area_struct *vma;
- struct folio_walk fw;
- struct folio *folio;
- int rc;
-
- mmap_read_lock(mm);
- vma = vma_lookup(mm, hva);
- if (!vma) {
- mmap_read_unlock(mm);
- return -EFAULT;
- }
- folio = folio_walk_start(&fw, vma, hva, 0);
- if (!folio) {
- mmap_read_unlock(mm);
- return -ENXIO;
- }
-
- folio_get(folio);
- /*
- * Secure pages cannot be huge and userspace should not combine both.
- * In case userspace does it anyway this will result in an -EFAULT for
- * the unpack. The guest is thus never reaching secure mode.
- * If userspace plays dirty tricks and decides to map huge pages at a
- * later point in time, it will receive a segmentation fault or
- * KVM_RUN will return -EFAULT.
- */
- if (folio_test_hugetlb(folio))
- rc = -EFAULT;
- else if (folio_test_large(folio))
- rc = -E2BIG;
- else if (!pte_write(fw.pte) || (pte_val(fw.pte) & _PAGE_INVALID))
- rc = -ENXIO;
- else
- rc = make_folio_secure(mm, folio, uvcb);
- folio_walk_end(&fw, vma);
- mmap_read_unlock(mm);
-
- if (rc == -E2BIG || rc == -EBUSY) {
- rc = s390_wiggle_split_folio(mm, folio);
- if (!rc)
- rc = -EAGAIN;
- }
- folio_put(folio);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(make_hva_secure);
+EXPORT_SYMBOL_GPL(s390_wiggle_split_folio);
/*
* To be called with the folio locked or with an extra reference! This will
@@ -470,21 +377,18 @@ int arch_make_folio_accessible(struct folio *folio)
{
int rc = 0;
- /* Large folios cannot be secure */
- if (unlikely(folio_test_large(folio)))
- return 0;
-
/*
- * PG_arch_1 is used in 2 places:
- * 1. for storage keys of hugetlb folios and KVM
- * 2. As an indication that this small folio might be secure. This can
- * overindicate, e.g. we set the bit before calling
- * convert_to_secure.
- * As secure pages are never large folios, both variants can co-exists.
+ * PG_arch_1 is used as an indication that this small folio might be
+ * secure. This can overindicate, e.g. we set the bit before calling
+ * convert_to_secure.
*/
if (!test_bit(PG_arch_1, &folio->flags.f))
return 0;
+ /* Large folios cannot be secure. */
+ if (WARN_ON_ONCE(folio_test_large(folio)))
+ return -EFAULT;
+
rc = uv_pin_shared(folio_to_phys(folio));
if (!rc) {
clear_bit(PG_arch_1, &folio->flags.f);