KVM: s390: Simplify and move pv code
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>
This commit is contained in:
parent
200197908d
commit
d6c8097803
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -16,9 +16,10 @@
|
||||
#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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -16,13 +16,11 @@
|
||||
#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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user