diff mbox

[2/2] s390x/mmu: Use ioctl for reading and writing from/to guest memory

Message ID 1424089338-14562-3-git-send-email-thuth@linux.vnet.ibm.com
State New
Headers show

Commit Message

Thomas Huth Feb. 16, 2015, 12:22 p.m. UTC
Add code to make use of the new ioctl for reading from / writing to
virtual guest memory. By using the ioctl, the memory accesses are now
protected with the so-called ipte-lock in the kernel.

Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
---
 target-s390x/cpu.h        |    7 +++++++
 target-s390x/kvm.c        |   35 +++++++++++++++++++++++++++++++++++
 target-s390x/mmu_helper.c |    9 +++++++++
 3 files changed, 51 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index b6b4632..cffdd1b 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -394,6 +394,8 @@  void kvm_s390_service_interrupt(uint32_t parm);
 void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
 void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq);
 int kvm_s390_inject_flic(struct kvm_s390_irq *irq);
+int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
+                    bool is_write);
 void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
 #else
 static inline void kvm_s390_virtio_irq(int config_change, uint64_t token)
@@ -402,6 +404,11 @@  static inline void kvm_s390_virtio_irq(int config_change, uint64_t token)
 static inline void kvm_s390_service_interrupt(uint32_t parm)
 {
 }
+static inline int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, void *hostbuf,
+                                  int len, bool is_write)
+{
+    return -ENOSYS;
+}
 static inline void kvm_s390_access_exception(S390CPU *cpu, uint16_t code,
                                              uint64_t te_code)
 {
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 195493c..57a3aa1 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -117,6 +117,7 @@  const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 
 static int cap_sync_regs;
 static int cap_async_pf;
+static int cap_mem_op;
 
 static void *legacy_s390_alloc(size_t size, uint64_t *align);
 
@@ -176,6 +177,7 @@  int kvm_arch_init(KVMState *s)
 {
     cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
     cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
+    cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
 
     if (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES)) {
         kvm_s390_enable_cmma(s);
@@ -436,6 +438,39 @@  int kvm_arch_get_registers(CPUState *cs)
     return 0;
 }
 
+/**
+ * kvm_s390_mem_op:
+ * @addr:      the logical start address in guest memory
+ * @hostbuf:   buffer in host memory. NULL = do only checks w/o copying
+ * @len:       length that should be transfered
+ * @is_write:  true = write, false = read
+ * Returns:    0 on success, non-zero if an exception or error occured
+ *
+ * Use KVM ioctl to read/write from/to guest memory. An access exception
+ * is injected into the vCPU in case of translation errors.
+ */
+int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
+                    bool is_write)
+{
+    struct kvm_s390_mem_op mem_op = {
+        .gaddr = addr,
+        .flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION,
+        .size = len,
+        .op = is_write ? KVM_S390_MEMOP_LOGICAL_WRITE
+                       : KVM_S390_MEMOP_LOGICAL_READ,
+        .buf = (uint64_t)hostbuf,
+    };
+
+    if (!cap_mem_op) {
+        return -ENOSYS;
+    }
+    if (!hostbuf) {
+        mem_op.flags |= KVM_S390_MEMOP_F_CHECK_ONLY;
+    }
+
+    return kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
+}
+
 /*
  * Legacy layout for s390:
  * Older S390 KVM requires the topmost vma of the RAM to be
diff --git a/target-s390x/mmu_helper.c b/target-s390x/mmu_helper.c
index b061c85..22f965a 100644
--- a/target-s390x/mmu_helper.c
+++ b/target-s390x/mmu_helper.c
@@ -450,6 +450,15 @@  int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, void *hostbuf,
     target_ulong *pages;
     int ret;
 
+    if (kvm_enabled()) {
+        ret = kvm_s390_mem_op(cpu, laddr, hostbuf, len, is_write);
+        if (ret >= 0) {
+            return ret;
+        } else if (ret != -ENOSYS) {
+            error_printf("kvm_s390_mem_op() failed: %s\n", strerror(-ret));
+        }
+    }
+
     nr_pages = (((laddr & ~TARGET_PAGE_MASK) + len - 1) >> TARGET_PAGE_BITS)
                + 1;
     pages = g_malloc(nr_pages * sizeof(*pages));