]> www.infradead.org Git - users/dwmw2/qemu.git/commitdiff
i386/xen: handle Xen hypercall page
authorJoao Martins <joao.m.martins@oracle.com>
Tue, 12 Jun 2018 21:33:05 +0000 (22:33 +0100)
committerJoao Martins <joao.m.martins@oracle.com>
Tue, 19 Feb 2019 14:00:57 +0000 (09:00 -0500)
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 <joao.m.martins@oracle.com>
target/i386/Makefile.objs
target/i386/kvm.c
target/i386/xen.c [new file with mode: 0644]
target/i386/xen.h [new file with mode: 0644]

index cb9c2655259afc729cb0ed84bc1a2404168ff7fc..8496f1444ea10f3fa4c549879ba7b1cdbae8bf03 100644 (file)
@@ -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
index 8bb5d2d2e9a23496bebd478e8508edcc5711c042..4eb0629db577b90f77125a24a8d5ddfbdc1525f1 100644 (file)
@@ -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 (file)
index 0000000..efd5b91
--- /dev/null
@@ -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 (file)
index 0000000..4512e12
--- /dev/null
@@ -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