From: Joao Martins Date: Mon, 18 Jun 2018 16:17:42 +0000 (-0400) Subject: i386/xen: set shared_info page X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=9c993449a61a2dbaa1ad71c21eaed4f6011966b1;p=users%2Fdwmw2%2Fqemu.git i386/xen: set shared_info page This is done by implementing HYPERVISOR_memory_op specifically XENMEM_add_to_physmap with space XENMAPSPACE_shared_info. While Xen removes the page with it's own, we instead use the gfn passed by the guest. Signed-off-by: Joao Martins --- diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index fd92b6f375..e035a01f0c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -110,6 +110,9 @@ struct KVMState /* memory encryption */ void *memcrypt_handle; int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len); + + /* xen guest state */ + struct XenState xen; }; KVMState *kvm_state; @@ -138,6 +141,11 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_LAST_INFO }; +struct XenState *kvm_get_xen_state(KVMState *s) +{ + return &s->xen; +} + int kvm_get_max_memslots(void) { KVMState *s = KVM_STATE(current_machine->accelerator); @@ -347,6 +355,7 @@ int kvm_init_vcpu(CPUState *cpu) cpu->kvm_fd = ret; cpu->kvm_state = s; cpu->vcpu_dirty = true; + cpu->xen_state = &s->xen; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 1d6099e5d4..b9d88f3594 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -452,6 +452,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 a6d1cd190f..2fe9bfcb4d 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -547,4 +547,5 @@ int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source); int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target); struct ppc_radix_page_info *kvm_get_radix_page_info(void); int kvm_get_max_memslots(void); +struct XenState *kvm_get_xen_state(KVMState *s); #endif diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 6a7b0a4d98..996689087f 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1454,6 +1454,21 @@ struct kvm_enc_region { /* Available with KVM_CAP_HYPERV_CPUID */ #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2) +#define KVM_XEN_HVM_GET_ATTR _IOWR(KVMIO, 0xc2, struct kvm_xen_hvm_attr) +#define KVM_XEN_HVM_SET_ATTR _IOW(KVMIO, 0xc3, struct kvm_xen_hvm_attr) + +struct kvm_xen_hvm_attr { + __u16 type; + + union { + struct { + __u64 gfn; + } shared_info; + } u; +}; + +#define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x0 + /* Secure Encrypted Virtualization command */ enum sev_cmd_id { /* Guest initialization commands */ diff --git a/target/i386/cpu.h b/target/i386/cpu.h index cef37a8a2b..e3fc8ce131 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -24,6 +24,7 @@ #include "qemu-common.h" #include "cpu-qom.h" #include "hyperv-proto.h" +#include "xen-proto.h" #ifdef TARGET_X86_64 #define TARGET_LONG_BITS 64 diff --git a/target/i386/trace-events b/target/i386/trace-events index aa7a5c6a5f..444e33d53b 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -18,3 +18,4 @@ kvm_sev_launch_finish(void) "" # target/i386/xen.c kvm_xen_hypercall(int cpu, uint64_t input, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t ret) "xen_hypercall: cpu %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 420a956d77..10bb40c417 100644 --- a/target/i386/xen.c +++ b/target/i386/xen.c @@ -13,13 +13,15 @@ #include "qemu/log.h" #include "linux/kvm.h" #include "exec/address-spaces.h" -#include "standard-headers/xen/version.h" #include "cpu.h" #include "xen.h" - #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: @@ -138,11 +140,70 @@ 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; 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]);