KVM: s390: Add a generic function for translating guest addresses
authorThomas Huth <thuth@linux.vnet.ibm.com>
Tue, 4 Feb 2014 13:43:25 +0000 (14:43 +0100)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Fri, 30 May 2014 07:39:35 +0000 (09:39 +0200)
This patch adds a function for translating logical guest addresses into
physical guest addresses without touching the memory at the given location.

Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
arch/s390/kvm/gaccess.c
arch/s390/kvm/gaccess.h

index db608c3f9303e5ad798b0661ee11a83a6228c555..5f73826992f237f00a53d0581b59a8fbfa6965c6 100644 (file)
@@ -644,6 +644,59 @@ int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
        return rc;
 }
 
+/**
+ * guest_translate_address - translate guest logical into guest absolute address
+ *
+ * Parameter semantics are the same as the ones from guest_translate.
+ * The memory contents at the guest address are not changed.
+ *
+ * Note: The IPTE lock is not taken during this function, so the caller
+ * has to take care of this.
+ */
+int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva,
+                           unsigned long *gpa, int write)
+{
+       struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
+       psw_t *psw = &vcpu->arch.sie_block->gpsw;
+       struct trans_exc_code_bits *tec;
+       union asce asce;
+       int rc;
+
+       /* Access register mode is not supported yet. */
+       if (psw_bits(*psw).t && psw_bits(*psw).as == PSW_AS_ACCREG)
+               return -EOPNOTSUPP;
+
+       gva = kvm_s390_logical_to_effective(vcpu, gva);
+       memset(pgm, 0, sizeof(*pgm));
+       tec = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
+       tec->as = psw_bits(*psw).as;
+       tec->fsi = write ? FSI_STORE : FSI_FETCH;
+       tec->addr = gva >> PAGE_SHIFT;
+       if (is_low_address(gva) && low_address_protection_enabled(vcpu)) {
+               if (write) {
+                       rc = pgm->code = PGM_PROTECTION;
+                       return rc;
+               }
+       }
+
+       asce.val = get_vcpu_asce(vcpu);
+       if (psw_bits(*psw).t && !asce.r) {      /* Use DAT? */
+               rc = guest_translate(vcpu, gva, gpa, write);
+               if (rc > 0) {
+                       if (rc == PGM_PROTECTION)
+                               tec->b61 = 1;
+                       pgm->code = rc;
+               }
+       } else {
+               rc = 0;
+               *gpa = kvm_s390_real_to_abs(vcpu, gva);
+               if (kvm_is_error_gpa(vcpu->kvm, *gpa))
+                       rc = pgm->code = PGM_ADDRESSING;
+       }
+
+       return rc;
+}
+
 /**
  * kvm_s390_check_low_addr_protection - check for low-address protection
  * @ga: Guest address
index a07ee08ac478cbe77aab0c8118b808a0cc2b6c15..2d37a46195e2cceb702efaf5b63003ddcd24a4e5 100644 (file)
@@ -155,6 +155,9 @@ int read_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
        return kvm_read_guest(vcpu->kvm, gpa, data, len);
 }
 
+int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva,
+                           unsigned long *gpa, int write);
+
 int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
                 unsigned long len, int write);