KVM: s390: handle_tprot: Honor storage keys
authorJanis Schoetterl-Glausch <scgl@linux.ibm.com>
Fri, 11 Feb 2022 18:22:08 +0000 (19:22 +0100)
committerChristian Borntraeger <borntraeger@linux.ibm.com>
Mon, 14 Feb 2022 15:12:57 +0000 (16:12 +0100)
Use the access key operand to check for key protection when
translating guest addresses.
Since the translation code checks for accessing exceptions/error hvas,
we can remove the check here and simplify the control flow.
Keep checking if the memory is read-only even if such memslots are
currently not supported.

handle_tprot was the last user of guest_translate_address,
so remove it.

Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Link: https://lore.kernel.org/r/20220211182215.2730017-4-scgl@linux.ibm.com
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
arch/s390/kvm/gaccess.c
arch/s390/kvm/gaccess.h
arch/s390/kvm/priv.c

index 7fca0cf..37838f6 100644 (file)
@@ -1118,15 +1118,6 @@ int guest_translate_address_with_key(struct kvm_vcpu *vcpu, unsigned long gva, u
                                   access_key);
 }
 
-int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
-                           unsigned long *gpa, enum gacc_mode mode)
-{
-       u8 access_key = psw_bits(vcpu->arch.sie_block->gpsw).key;
-
-       return guest_translate_address_with_key(vcpu, gva, ar, gpa, mode,
-                                               access_key);
-}
-
 /**
  * check_gva_range - test a range of guest virtual addresses for accessibility
  * @vcpu: virtual cpu
index e5b2f56..c5f2e73 100644 (file)
@@ -190,9 +190,6 @@ int guest_translate_address_with_key(struct kvm_vcpu *vcpu, unsigned long gva, u
                                     unsigned long *gpa, enum gacc_mode mode,
                                     u8 access_key);
 
-int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva,
-                           u8 ar, unsigned long *gpa, enum gacc_mode mode);
-
 int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
                    unsigned long length, enum gacc_mode mode, u8 access_key);
 
index 417154b..30b24c4 100644 (file)
@@ -1443,10 +1443,11 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
 
 static int handle_tprot(struct kvm_vcpu *vcpu)
 {
-       u64 address1, address2;
-       unsigned long hva, gpa;
-       int ret = 0, cc = 0;
+       u64 address, operand2;
+       unsigned long gpa;
+       u8 access_key;
        bool writable;
+       int ret, cc;
        u8 ar;
 
        vcpu->stat.instruction_tprot++;
@@ -1454,43 +1455,46 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
                return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
-       kvm_s390_get_base_disp_sse(vcpu, &address1, &address2, &ar, NULL);
+       kvm_s390_get_base_disp_sse(vcpu, &address, &operand2, &ar, NULL);
+       access_key = (operand2 & 0xf0) >> 4;
 
-       /* we only handle the Linux memory detection case:
-        * access key == 0
-        * everything else goes to userspace. */
-       if (address2 & 0xf0)
-               return -EOPNOTSUPP;
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
                ipte_lock(vcpu);
-       ret = guest_translate_address(vcpu, address1, ar, &gpa, GACC_STORE);
-       if (ret == PGM_PROTECTION) {
+
+       ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
+                                              GACC_STORE, access_key);
+       if (ret == 0) {
+               gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
+       } else if (ret == PGM_PROTECTION) {
+               writable = false;
                /* Write protected? Try again with read-only... */
-               cc = 1;
-               ret = guest_translate_address(vcpu, address1, ar, &gpa,
-                                             GACC_FETCH);
+               ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
+                                                      GACC_FETCH, access_key);
        }
-       if (ret) {
-               if (ret == PGM_ADDRESSING || ret == PGM_TRANSLATION_SPEC) {
-                       ret = kvm_s390_inject_program_int(vcpu, ret);
-               } else if (ret > 0) {
-                       /* Translation not available */
-                       kvm_s390_set_psw_cc(vcpu, 3);
+       if (ret >= 0) {
+               cc = -1;
+
+               /* Fetching permitted; storing permitted */
+               if (ret == 0 && writable)
+                       cc = 0;
+               /* Fetching permitted; storing not permitted */
+               else if (ret == 0 && !writable)
+                       cc = 1;
+               /* Fetching not permitted; storing not permitted */
+               else if (ret == PGM_PROTECTION)
+                       cc = 2;
+               /* Translation not available */
+               else if (ret != PGM_ADDRESSING && ret != PGM_TRANSLATION_SPEC)
+                       cc = 3;
+
+               if (cc != -1) {
+                       kvm_s390_set_psw_cc(vcpu, cc);
                        ret = 0;
+               } else {
+                       ret = kvm_s390_inject_program_int(vcpu, ret);
                }
-               goto out_unlock;
        }
 
-       hva = gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
-       if (kvm_is_error_hva(hva)) {
-               ret = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-       } else {
-               if (!writable)
-                       cc = 1;         /* Write not permitted ==> read-only */
-               kvm_s390_set_psw_cc(vcpu, cc);
-               /* Note: CC2 only occurs for storage keys (not supported yet) */
-       }
-out_unlock:
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
                ipte_unlock(vcpu);
        return ret;