summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/kvm/gaccess.c4
-rw-r--r--arch/s390/kvm/gaccess.h2
-rw-r--r--arch/s390/kvm/priv.c56
3 files changed, 37 insertions, 25 deletions
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 5f73826992f2..4653ac6e182b 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -292,7 +292,7 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
292 wake_up(&vcpu->kvm->arch.ipte_wq); 292 wake_up(&vcpu->kvm->arch.ipte_wq);
293} 293}
294 294
295static void ipte_lock(struct kvm_vcpu *vcpu) 295void ipte_lock(struct kvm_vcpu *vcpu)
296{ 296{
297 if (vcpu->arch.sie_block->eca & 1) 297 if (vcpu->arch.sie_block->eca & 1)
298 ipte_lock_siif(vcpu); 298 ipte_lock_siif(vcpu);
@@ -300,7 +300,7 @@ static void ipte_lock(struct kvm_vcpu *vcpu)
300 ipte_lock_simple(vcpu); 300 ipte_lock_simple(vcpu);
301} 301}
302 302
303static void ipte_unlock(struct kvm_vcpu *vcpu) 303void ipte_unlock(struct kvm_vcpu *vcpu)
304{ 304{
305 if (vcpu->arch.sie_block->eca & 1) 305 if (vcpu->arch.sie_block->eca & 1)
306 ipte_unlock_siif(vcpu); 306 ipte_unlock_siif(vcpu);
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h
index 2d37a46195e2..0149cf15058a 100644
--- a/arch/s390/kvm/gaccess.h
+++ b/arch/s390/kvm/gaccess.h
@@ -327,6 +327,8 @@ int read_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
327 return access_guest_real(vcpu, gra, data, len, 0); 327 return access_guest_real(vcpu, gra, data, len, 0);
328} 328}
329 329
330void ipte_lock(struct kvm_vcpu *vcpu);
331void ipte_unlock(struct kvm_vcpu *vcpu);
330int ipte_lock_held(struct kvm_vcpu *vcpu); 332int ipte_lock_held(struct kvm_vcpu *vcpu);
331int kvm_s390_check_low_addr_protection(struct kvm_vcpu *vcpu, unsigned long ga); 333int kvm_s390_check_low_addr_protection(struct kvm_vcpu *vcpu, unsigned long ga);
332 334
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 6296159ac883..f89c1cd67751 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -930,8 +930,9 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
930static int handle_tprot(struct kvm_vcpu *vcpu) 930static int handle_tprot(struct kvm_vcpu *vcpu)
931{ 931{
932 u64 address1, address2; 932 u64 address1, address2;
933 struct vm_area_struct *vma; 933 unsigned long hva, gpa;
934 unsigned long user_address; 934 int ret = 0, cc = 0;
935 bool writable;
935 936
936 vcpu->stat.instruction_tprot++; 937 vcpu->stat.instruction_tprot++;
937 938
@@ -942,32 +943,41 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
942 943
943 /* we only handle the Linux memory detection case: 944 /* we only handle the Linux memory detection case:
944 * access key == 0 945 * access key == 0
945 * guest DAT == off
946 * everything else goes to userspace. */ 946 * everything else goes to userspace. */
947 if (address2 & 0xf0) 947 if (address2 & 0xf0)
948 return -EOPNOTSUPP; 948 return -EOPNOTSUPP;
949 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) 949 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
950 return -EOPNOTSUPP; 950 ipte_lock(vcpu);
951 951 ret = guest_translate_address(vcpu, address1, &gpa, 1);
952 down_read(&current->mm->mmap_sem); 952 if (ret == PGM_PROTECTION) {
953 user_address = __gmap_translate(address1, vcpu->arch.gmap); 953 /* Write protected? Try again with read-only... */
954 if (IS_ERR_VALUE(user_address)) 954 cc = 1;
955 goto out_inject; 955 ret = guest_translate_address(vcpu, address1, &gpa, 0);
956 vma = find_vma(current->mm, user_address); 956 }
957 if (!vma) 957 if (ret) {
958 goto out_inject; 958 if (ret == PGM_ADDRESSING || ret == PGM_TRANSLATION_SPEC) {
959 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 959 ret = kvm_s390_inject_program_int(vcpu, ret);
960 if (!(vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_READ)) 960 } else if (ret > 0) {
961 vcpu->arch.sie_block->gpsw.mask |= (1ul << 44); 961 /* Translation not available */
962 if (!(vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_READ)) 962 kvm_s390_set_psw_cc(vcpu, 3);
963 vcpu->arch.sie_block->gpsw.mask |= (2ul << 44); 963 ret = 0;
964 964 }
965 up_read(&current->mm->mmap_sem); 965 goto out_unlock;
966 return 0; 966 }
967 967
968out_inject: 968 hva = gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
969 up_read(&current->mm->mmap_sem); 969 if (kvm_is_error_hva(hva)) {
970 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 970 ret = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
971 } else {
972 if (!writable)
973 cc = 1; /* Write not permitted ==> read-only */
974 kvm_s390_set_psw_cc(vcpu, cc);
975 /* Note: CC2 only occurs for storage keys (not supported yet) */
976 }
977out_unlock:
978 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
979 ipte_unlock(vcpu);
980 return ret;
971} 981}
972 982
973int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) 983int kvm_s390_handle_e5(struct kvm_vcpu *vcpu)