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@xxxxxxxxxxxxxxxxxx> --- target-s390x/cpu.h | 7 +++++++ target-s390x/kvm.c | 35 +++++++++++++++++++++++++++++++++++ target-s390x/mmu_helper.c | 9 +++++++++ 3 files changed, 51 insertions(+), 0 deletions(-) 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)); -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html