aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm
diff options
context:
space:
mode:
authorClaudio Imbrenda <imbrenda@linux.ibm.com>2020-01-31 15:00:39 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2020-02-27 19:47:11 +0100
commit5322781008a9dce894146ef71a09f1770062389a (patch)
treee61f27aa71edd2fb8c4b76006e1f51d296ef064f /arch/s390/kvm
parentKVM: s390: protvirt: handle secure guest prefix pages (diff)
downloadlinux-dev-5322781008a9dce894146ef71a09f1770062389a.tar.xz
linux-dev-5322781008a9dce894146ef71a09f1770062389a.zip
KVM: s390/mm: handle guest unpin events
The current code tries to first pin shared pages, if that fails (e.g. because the page is not shared) it will export them. For shared pages this means that we get a new intercept telling us that the guest is unsharing that page. We will unpin the page at that point in time, following the same rules as for making a page secure (i.e. waiting for writeback, no elevated page references, etc.) Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Acked-by: David Hildenbrand <david@redhat.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> [borntraeger@de.ibm.com: patch merging, splitting, fixing] Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r--arch/s390/kvm/intercept.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index b6b7d4b0e26c..f907715d9479 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -16,6 +16,7 @@
#include <asm/asm-offsets.h>
#include <asm/irq.h>
#include <asm/sysinfo.h>
+#include <asm/uv.h>
#include "kvm-s390.h"
#include "gaccess.h"
@@ -484,12 +485,40 @@ static int handle_pv_sclp(struct kvm_vcpu *vcpu)
return 0;
}
+static int handle_pv_uvc(struct kvm_vcpu *vcpu)
+{
+ struct uv_cb_share *guest_uvcb = (void *)vcpu->arch.sie_block->sidad;
+ struct uv_cb_cts uvcb = {
+ .header.cmd = UVC_CMD_UNPIN_PAGE_SHARED,
+ .header.len = sizeof(uvcb),
+ .guest_handle = kvm_s390_pv_get_handle(vcpu->kvm),
+ .gaddr = guest_uvcb->paddr,
+ };
+ int rc;
+
+ if (guest_uvcb->header.cmd != UVC_CMD_REMOVE_SHARED_ACCESS) {
+ WARN_ONCE(1, "Unexpected notification intercept for UVC 0x%x\n",
+ guest_uvcb->header.cmd);
+ return 0;
+ }
+ rc = gmap_make_secure(vcpu->arch.gmap, uvcb.gaddr, &uvcb);
+ /*
+ * If the unpin did not succeed, the guest will exit again for the UVC
+ * and we will retry the unpin.
+ */
+ if (rc == -EINVAL)
+ return 0;
+ return rc;
+}
+
static int handle_pv_notification(struct kvm_vcpu *vcpu)
{
if (vcpu->arch.sie_block->ipa == 0xb210)
return handle_pv_spx(vcpu);
if (vcpu->arch.sie_block->ipa == 0xb220)
return handle_pv_sclp(vcpu);
+ if (vcpu->arch.sie_block->ipa == 0xb9a4)
+ return handle_pv_uvc(vcpu);
return handle_instruction(vcpu);
}