From: Joao Martins <joao.m.mart...@oracle.com> This is done by implementing HYPERVISOR_memory_op specifically XENMEM_add_to_physmap with space XENMAPSPACE_shared_info. While Xen removes the page with its own, we instead use the gfn passed by the guest.
Signed-off-by: Joao Martins <joao.m.mart...@oracle.com> Signed-off-by: David Woodhouse <d...@amazon.co.uk> --- accel/kvm/kvm-all.c | 6 ++++ include/hw/core/cpu.h | 2 ++ include/sysemu/kvm.h | 2 ++ include/sysemu/kvm_int.h | 3 ++ target/i386/cpu.h | 8 ++++++ target/i386/trace-events | 1 + target/i386/xen-proto.h | 19 +++++++++++++ target/i386/xen.c | 61 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 102 insertions(+) create mode 100644 target/i386/xen-proto.h diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f99b0becd8..8a227515b7 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -172,6 +172,11 @@ void kvm_resample_fd_notify(int gsi) } } +struct XenState *kvm_get_xen_state(KVMState *s) +{ + return &s->xen; +} + int kvm_get_max_memslots(void) { KVMState *s = KVM_STATE(current_accel()); @@ -405,6 +410,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) cpu->vcpu_dirty = true; cpu->dirty_pages = 0; cpu->throttle_us_per_full = 0; + cpu->xen_state = &s->xen; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 8830546121..e57b693528 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -443,6 +443,8 @@ struct CPUState { /* track IOMMUs whose translations we've cached in the TCG TLB */ GArray *iommu_notifiers; + + struct XenState *xen_state; }; typedef QTAILQ_HEAD(CPUTailQ, CPUState) CPUTailQ; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index e9a97eda8c..8e882fbe96 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -582,4 +582,6 @@ bool kvm_arch_cpu_check_are_resettable(void); bool kvm_dirty_ring_enabled(void); uint32_t kvm_dirty_ring_size(void); + +struct XenState *kvm_get_xen_state(KVMState *s); #endif diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 3b4adcdc10..0d89cfe273 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -110,6 +110,9 @@ struct KVMState struct KVMDirtyRingReaper reaper; NotifyVmexitOption notify_vmexit; uint32_t notify_window; + + /* xen guest state */ + struct XenState xen; }; void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 5ddd14467e..09c0281b8b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -23,6 +23,14 @@ #include "sysemu/tcg.h" #include "cpu-qom.h" #include "kvm/hyperv-proto.h" +#include "xen-proto.h" + +#ifdef TARGET_X86_64 +#define TARGET_LONG_BITS 64 +#else +#define TARGET_LONG_BITS 32 +#endif + #include "exec/cpu-defs.h" #include "qapi/qapi-types-common.h" #include "qemu/cpu-float.h" diff --git a/target/i386/trace-events b/target/i386/trace-events index 3fb9ee3add..2bf732ee07 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -14,3 +14,4 @@ kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data # target/i386/xen.c kvm_xen_hypercall(int cpu, uint8_t cpl, uint64_t input, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t ret) "xen_hypercall: cpu %d cpl %d input %" PRIu64 " a0 0x%" PRIx64 " a1 0x%" PRIx64 " a2 0x%" PRIx64" ret 0x%" PRIu64 +kvm_xen_set_shared_info(uint64_t gfn) "shared info at gfn 0x%" PRIx64 diff --git a/target/i386/xen-proto.h b/target/i386/xen-proto.h new file mode 100644 index 0000000000..c394909f54 --- /dev/null +++ b/target/i386/xen-proto.h @@ -0,0 +1,19 @@ +/* + * Definitions for Xen guest/hypervisor interaction - x86-specific part + * + * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef TARGET_I386_XEN_PROTO_H +#define TARGET_I386_XEN_PROTO_H + +typedef struct XenState { + struct shared_info *shared_info; +} XenState; + +#endif + diff --git a/target/i386/xen.c b/target/i386/xen.c index ee6f99523d..5d2d8a7e00 100644 --- a/target/i386/xen.c +++ b/target/i386/xen.c @@ -16,8 +16,10 @@ #include "trace.h" #include "standard-headers/xen/version.h" +#include "standard-headers/xen/memory.h" #define PAGE_OFFSET 0xffffffff80000000UL +#define PAGE_SHIFT 12 /* * Unhandled hypercalls error: @@ -123,6 +125,62 @@ static int kvm_xen_hcall_xen_version(struct kvm_xen_exit *exit, X86CPU *cpu, return err ? HCALL_ERR : 0; } +static int xen_set_shared_info(CPUState *cs, struct shared_info *shi, + uint64_t gfn) +{ + struct kvm_xen_hvm_attr xhsi; + XenState *xen = cs->xen_state; + KVMState *s = cs->kvm_state; + int err; + + xhsi.type = KVM_XEN_ATTR_TYPE_SHARED_INFO; + xhsi.u.shared_info.gfn = gfn; + err = kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &xhsi); + trace_kvm_xen_set_shared_info(gfn); + xen->shared_info = shi; + return err; +} + +static int kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, + int cmd, uint64_t arg, X86CPU *cpu) +{ + CPUState *cs = CPU(cpu); + int err = 0; + + switch (cmd) { + case XENMEM_add_to_physmap: { + struct xen_add_to_physmap *xatp; + struct shared_info *shi; + + xatp = gva_to_hva(cs, arg); + if (!xatp) { + err = -EFAULT; + break; + } + + switch (xatp->space) { + case XENMAPSPACE_shared_info: + break; + default: + err = -ENOSYS; + break; + } + + shi = gpa_to_hva(xatp->gpfn << PAGE_SHIFT); + if (!shi) { + err = -EFAULT; + break; + } + + err = xen_set_shared_info(cs, shi, xatp->gpfn); + break; + } + } + + exit->u.hcall.result = err; + return err ? HCALL_ERR : 0; +} + static int __kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit) { uint16_t code = exit->u.hcall.input; @@ -133,6 +191,9 @@ static int __kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit) } switch (code) { + case __HYPERVISOR_memory_op: + return kvm_xen_hcall_memory_op(exit, exit->u.hcall.params[0], + exit->u.hcall.params[1], cpu); case __HYPERVISOR_xen_version: return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0], exit->u.hcall.params[1]); -- 2.35.3