summary refs log tree commit diff
path: root/arch/s390/kvm/intercept.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm/intercept.c')
-rw-r--r--arch/s390/kvm/intercept.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index f7b6df45d8be..c7c51898984e 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -105,6 +105,7 @@ static intercept_handler_t instruction_handlers[256] = {
 	[0xae] = kvm_s390_handle_sigp,
 	[0xb2] = kvm_s390_handle_b2,
 	[0xb7] = handle_lctl,
+	[0xe5] = kvm_s390_handle_e5,
 	[0xeb] = handle_lctlg,
 };
 
@@ -159,22 +160,42 @@ static int handle_stop(struct kvm_vcpu *vcpu)
 
 static int handle_validity(struct kvm_vcpu *vcpu)
 {
+	unsigned long vmaddr;
 	int viwhy = vcpu->arch.sie_block->ipb >> 16;
 	int rc;
 
 	vcpu->stat.exit_validity++;
-	if ((viwhy == 0x37) && (vcpu->arch.sie_block->prefix
-		<= kvm_s390_vcpu_get_memsize(vcpu) - 2*PAGE_SIZE)) {
-		rc = fault_in_pages_writeable((char __user *)
-			 vcpu->arch.sie_block->gmsor +
-			 vcpu->arch.sie_block->prefix,
-			 2*PAGE_SIZE);
-		if (rc)
+	if (viwhy == 0x37) {
+		vmaddr = gmap_fault(vcpu->arch.sie_block->prefix,
+				    vcpu->arch.gmap);
+		if (IS_ERR_VALUE(vmaddr)) {
+			rc = -EOPNOTSUPP;
+			goto out;
+		}
+		rc = fault_in_pages_writeable((char __user *) vmaddr,
+			 PAGE_SIZE);
+		if (rc) {
+			/* user will receive sigsegv, exit to user */
+			rc = -EOPNOTSUPP;
+			goto out;
+		}
+		vmaddr = gmap_fault(vcpu->arch.sie_block->prefix + PAGE_SIZE,
+				    vcpu->arch.gmap);
+		if (IS_ERR_VALUE(vmaddr)) {
+			rc = -EOPNOTSUPP;
+			goto out;
+		}
+		rc = fault_in_pages_writeable((char __user *) vmaddr,
+			 PAGE_SIZE);
+		if (rc) {
 			/* user will receive sigsegv, exit to user */
 			rc = -EOPNOTSUPP;
+			goto out;
+		}
 	} else
 		rc = -EOPNOTSUPP;
 
+out:
 	if (rc)
 		VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
 			   viwhy);