From: Joao Martins Date: Tue, 12 Jun 2018 21:33:05 +0000 (+0100) Subject: i386/xen: handle Xen hypercall page X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=18123ca05bfb06722899eee81fe20ad8708afaa3;p=users%2Fdwmw2%2Fqemu.git i386/xen: handle Xen hypercall page Firstly create the blob and set up the vmmcall. Afterwards we update number of hypercall pages to 1, and then make the vm ioctl to set XEN_HVM_CONFIG. This allows the guest to make hypercalls Signed-off-by: Joao Martins --- diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index cb9c265525..8496f1444e 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -9,6 +9,7 @@ obj-$(CONFIG_KVM) += kvm.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-$(CONFIG_HYPERV) += hyperv.o obj-$(call lnot,$(CONFIG_HYPERV)) += hyperv-stub.o +obj-$(CONFIG_XEN) += xen.o ifeq ($(CONFIG_WIN32),y) obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-windows.o endif diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 8bb5d2d2e9..4eb0629db5 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -29,6 +29,7 @@ #include "kvm_i386.h" #include "hyperv.h" #include "hyperv-proto.h" +#include "xen.h" #include "exec/gdbstub.h" #include "qemu/host-utils.h" @@ -651,12 +652,6 @@ static bool hyperv_enabled(X86CPU *cpu) cpu->hyperv_ipi); } -#define XEN_CPUID_SIGNATURE 0x40000000 -#define XEN_CPUID_VENDOR 0x40000001 -#define XEN_CPUID_HVM_MSR 0x40000002 -#define XEN_CPUID_TIME 0x40000003 -#define XEN_CPUID_HVM 0x40000004 - static bool xen_enabled_on_kvm(X86CPU *cpu) { return cpu->xen; @@ -1058,7 +1053,7 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; c->function = XEN_CPUID_HVM_MSR; /* Number of hypercall-transfer pages */ - c->eax = 0; + c->eax = 1; /* Hypercall MSR base address */ c->ebx = XEN_CPUID_SIGNATURE; c->ecx = 0; @@ -1094,6 +1089,14 @@ int kvm_arch_init_vcpu(CPUState *cs) } } + if (kvm_check_extension(cs->kvm_state, KVM_CAP_XEN_HVM)) { + r = kvm_xen_set_hypercall_page(cs); + if (r) { + error_report("Failed to initialize Xen hypercall page %d", r); + abort(); + } + } + kvm_base = KVM_CPUID_SIGNATURE_NEXT; } diff --git a/target/i386/xen.c b/target/i386/xen.c new file mode 100644 index 0000000000..efd5b91309 --- /dev/null +++ b/target/i386/xen.c @@ -0,0 +1,63 @@ +/* + * Xen HVM emulation support in KVM + * + * 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. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "linux/kvm.h" +#include "cpu.h" +#include "xen.h" + +static void arch_init_hypercall_page(CPUState *cs, void *addr) +{ + CPUX86State *env = cs->env_ptr; + char *p; + int i; + + for (i = 0; i < (TARGET_PAGE_SIZE / 32); i++) { + p = (char *)(addr + (i * 32)); + *(uint8_t *)(p + 0) = 0xb8; /* mov imm32, %eax */ + *(uint32_t *)(p + 1) = i; + *(uint8_t *)(p + 5) = 0x0f; /* vmcall */ + *(uint8_t *)(p + 6) = 0x01; + + if (env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && + env->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && + env->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) + *(uint8_t *)(p + 7) = 0xc1; + else + *(uint8_t *)(p + 7) = 0xd9; + + *(uint8_t *)(p + 8) = 0xc3; /* ret */ + } +} + +int kvm_xen_set_hypercall_page(CPUState *env) +{ + struct kvm_xen_hvm_config cfg; + void *page; + + page = g_malloc(TARGET_PAGE_SIZE); + if (!page) { + return -ENOMEM; + } + + memset(page, 0xCC, TARGET_PAGE_SIZE); + + arch_init_hypercall_page(env, page); + + cfg.msr = XEN_CPUID_SIGNATURE; + cfg.flags = 0; + cfg.blob_addr_32 = (uint64_t) page; + cfg.blob_size_32 = 1; + cfg.blob_addr_64 = (uint64_t) page; + cfg.blob_size_64 = 1; + + return kvm_vm_ioctl(env->kvm_state, KVM_XEN_HVM_CONFIG, &cfg); +} diff --git a/target/i386/xen.h b/target/i386/xen.h new file mode 100644 index 0000000000..4512e12700 --- /dev/null +++ b/target/i386/xen.h @@ -0,0 +1,26 @@ +/* + * Xen HVM emulation support in KVM + * + * 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_H +#define TARGET_I386_XEN_H + +#include "cpu.h" +#include "sysemu/kvm.h" +#include "qemu/event_notifier.h" + +#define XEN_CPUID_SIGNATURE 0x40000000 +#define XEN_CPUID_VENDOR 0x40000001 +#define XEN_CPUID_HVM_MSR 0x40000002 +#define XEN_CPUID_TIME 0x40000003 +#define XEN_CPUID_HVM 0x40000004 + +int kvm_xen_set_hypercall_page(CPUState *env); + +#endif