aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Huth <thuth@linux.vnet.ibm.com>2014-02-04 08:48:07 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-05-30 03:39:36 -0400
commita0465f9ae4758207264a1318bb8aed617c0ea959 (patch)
tree5ffee52ce78ef810c6ac70fd277eb32046060a78
parent9fbc02760d61fddc7716f9e6aa6ed1ff33e65405 (diff)
KVM: s390: Enable DAT support for TPROT handler
The TPROT instruction can be used to check the accessability of storage for any kind of logical addresses. So far, our handler only supported real addresses. This patch now also enables support for addresses that have to be translated via DAT first. And while we're at it, change the code to use the common KVM function gfn_to_hva_prot() to check for the validity and writability of the memory page. Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
-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)