All of lore.kernel.org
 help / color / mirror / Atom feed
From: Assaf Gordon <assafgordon@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] Attempt at Mac OS X acceleration using "Hypervisor.Framwork"
Date: Thu, 12 Nov 2015 12:49:39 +0200	[thread overview]
Message-ID: <784C0637-DC5D-45CA-B989-AF76378201D4@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 756 bytes --]

Hello,

Starting with Mac OS X version 10.10.3, Apple provides a system-level hypervisor framework (similar to KVM's kernel driver functionality on Linux).

a good write-up here:
 http://www.pagetable.com/?p=764
 http://www.pagetable.com/?p=831

a working hypervisor (forked from BSD's bhyve) is here:
  https://github.com/mist64/xhyve

This attached patch attempts to provide the infrastructure glue for qemu to use this framework (when compiled on Mac OS X). It is not yet functional, but enables the following:

  ./configure --enable-hvf --target-list=x86_64-softmmu
  qemu-system-x86_64 -machine accel=hvf [...]

Please advise as to whether this is the right approach, and whether it's worth pursuing.
Comments welcomed,
 - assaf


[-- Attachment #2: accel-hvf.patch --]
[-- Type: application/octet-stream, Size: 15534 bytes --]

From 5825d45140cc7a935d5c35198d4ae41d961252c9 Mon Sep 17 00:00:00 2001
From: Assaf Gordon <assafgordon@gmail.com>
Date: Thu, 12 Nov 2015 12:33:12 +0200
Subject: [PATCH] STUB for Mac OS X Hypervisor.Framework accelerator

An attempt to add stub code for future support of
Mac OS X Hypervisor.Framework (avaialble on OS X>=10.10.3).

Usage will be:
  ./configure --enable-hvf --target-list=x86_64-softmmu
  qemu-system-x86_64 -machine accel=hvf [...]

* configure: new variable 'hvf'.
   accept --{enable,disable}-hvf.
   write CONFIG_HVF=y to <target>/config-target.mak files.
   (During development, don't limit to Darwin hosts.)
* Makefile.target: compile and link either hvf-stub.o or hvf-all.o
   based on CONFIG_HVF.
* cpus.c: qemu_init_vcpu(): use hvf functions.
   qemu_hvf_start_vcpu(), qemu_hvf_cpu_thread_fn() - use hvf
   accelerator.
* include/sysemu/hvf{-int}.h: stub header files for hvf.
* hvf-stub.c: mimic kvm-stub.c, to be compiled with CONFIG_HVF=n .
* hvf-all.c: stub for Hypervisor.Framework accelerator.
---
 Makefile.target          |   2 +
 configure                |  42 +++++++++++
 cpus.c                   |  57 +++++++++++++++
 hvf-all.c                | 179 +++++++++++++++++++++++++++++++++++++++++++++++
 hvf-stub.c               |  30 ++++++++
 include/qom/cpu.h        |   4 ++
 include/sysemu/hvf.h     |  49 +++++++++++++
 include/sysemu/hvf_int.h |  21 ++++++
 8 files changed, 384 insertions(+)
 create mode 100644 hvf-all.c
 create mode 100644 hvf-stub.c
 create mode 100644 include/sysemu/hvf.h
 create mode 100644 include/sysemu/hvf_int.h

diff --git a/Makefile.target b/Makefile.target
index 962d004..5bba20a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,6 +96,7 @@ obj-y += target-$(TARGET_BASE_ARCH)/
 obj-y += disas.o
 obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
+obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o
 
 obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o
 obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decNumber.o
@@ -135,6 +136,7 @@ obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
 obj-y += qtest.o bootdevice.o
 obj-y += hw/
 obj-$(CONFIG_KVM) += kvm-all.o
+obj-$(CONFIG_HVF) += hvf-all.o
 obj-y += memory.o cputlb.o
 obj-y += memory_mapping.o
 obj-y += dump.o
diff --git a/configure b/configure
index 46fd8bd..e46a945 100755
--- a/configure
+++ b/configure
@@ -346,6 +346,9 @@ numa=""
 tcmalloc="no"
 jemalloc="no"
 
+# Mac OS X>=10.10.3 Hypervisor.Framework (hvf)
+hvf="no"
+
 # parse CC options first
 for opt do
   optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
@@ -937,6 +940,10 @@ for opt do
   ;;
   --enable-kvm) kvm="yes"
   ;;
+  --disable-hvf) hvf="no"
+  ;;
+  --enable-hvf) hvf="yes"
+  ;;
   --disable-tcg-interpreter) tcg_interpreter="no"
   ;;
   --enable-tcg-interpreter) tcg_interpreter="yes"
@@ -1360,6 +1367,7 @@ disabled with --disable-FEATURE, default is enabled if available:
   fdt             fdt device tree
   bluez           bluez stack connectivity
   kvm             KVM acceleration support
+  hvf             Mac OS X Hypervisor.Framework
   rdma            RDMA-based migration support
   uuid            uuid support
   vde             support for vde network
@@ -4456,6 +4464,29 @@ elif test "$debug" = "no"; then
 fi
 
 ##########################################
+# Hypervisor.Framework check
+
+if test "$hvf" != "no" ; then
+    if test "$darwin" != yes ; then
+            feature_not_found "hvf" "Hypervisor.Framework requires Mac/Darwin"
+    fi
+    cat > $TMPC << EOF
+#include <Hypervisor/hv.h>
+#include <Hypervisor/hv_vmx.h>
+int main(void) { hv_vm_create(HV_VM_DEFAULT); return 0; }
+EOF
+    if compile_prog "" "-framework Hypervisor" ; then
+        libs_softmmu="$libs_softmmu -framework Hypervisor"
+        hvf="yes"
+    else
+        if test "$hvf" = "yes"; then
+            feature_not_found "hvf" "Hypervisor.Framework not found"
+        fi
+        hvf="no"
+    fi
+fi
+
+##########################################
 # Do we have libnfs
 if test "$libnfs" != "no" ; then
   if $pkg_config --atleast-version=1.9.3 libnfs; then
@@ -4741,6 +4772,7 @@ echo "Linux AIO support $linux_aio"
 echo "ATTR/XATTR support $attr"
 echo "Install blobs     $blobs"
 echo "KVM support       $kvm"
+echo "HVF support       $hvf"
 echo "RDMA support      $rdma"
 echo "TCG interpreter   $tcg_interpreter"
 echo "fdt support       $fdt"
@@ -5646,6 +5678,16 @@ case "$target_name" in
   *)
 esac
 case "$target_name" in
+  i386|x86_64)
+    if test "$hvf" = yes; then
+      echo "CONFIG_HVF=y" >> $config_target_mak
+      #TODO: avoid writing 'CONFIG_VHOST_NET=y' twice (below in kvm)
+      if test "$vhost_net" = "yes" ; then
+        echo "CONFIG_VHOST_NET=y" >> $config_target_mak
+      fi
+    fi
+esac
+case "$target_name" in
   aarch64|arm|i386|x86_64|ppcemb|ppc|ppc64|s390x|mipsel|mips)
     # Make sure the target and host cpus are compatible
     if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
diff --git a/cpus.c b/cpus.c
index 877bd70..e578221 100644
--- a/cpus.c
+++ b/cpus.c
@@ -32,6 +32,7 @@
 #include "exec/gdbstub.h"
 #include "sysemu/dma.h"
 #include "sysemu/kvm.h"
+#include "sysemu/hvf.h"
 #include "qmp-commands.h"
 
 #include "qemu/thread.h"
@@ -1058,6 +1059,44 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
     return NULL;
 }
 
+static void *qemu_hvf_cpu_thread_fn(void *arg)
+{
+    CPUState *cpu = arg;
+    int r;
+
+    qemu_mutex_lock_iothread();
+    qemu_thread_get_self(cpu->thread);
+    cpu->thread_id = qemu_get_thread_id();
+    cpu->can_do_io = 1;
+    current_cpu = cpu;
+
+    r = hvf_init_vcpu(cpu) ;
+    if (r < 0) {
+        fprintf(stderr, "hvf_init_vcpu failed: %s\n", strerror(-r));
+        exit(1);
+    }
+
+    //TODO: implement with hvf
+    //qemu_kvm_init_cpu_signals(cpu);
+
+    /* signal CPU creation */
+    cpu->created = true;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    while (1) {
+        if (cpu_can_run(cpu)) {
+            r = hvf_cpu_exec(cpu);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(cpu);
+            }
+        }
+        //TODO: implement with hvf
+        //qemu_kvm_wait_io_event(cpu);
+    }
+
+    return NULL;
+}
+
 static void *qemu_dummy_cpu_thread_fn(void *arg)
 {
 #ifdef _WIN32
@@ -1367,6 +1406,22 @@ static void qemu_dummy_start_vcpu(CPUState *cpu)
     }
 }
 
+static void qemu_hvf_start_vcpu(CPUState *cpu)
+{
+    char thread_name[VCPU_THREAD_NAME_SIZE];
+
+    cpu->thread = g_malloc0(sizeof(QemuThread));
+    cpu->halt_cond = g_malloc0(sizeof(QemuCond));
+    qemu_cond_init(cpu->halt_cond);
+    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF",
+             cpu->cpu_index);
+    qemu_thread_create(cpu->thread, thread_name, qemu_hvf_cpu_thread_fn, cpu,
+                       QEMU_THREAD_JOINABLE);
+    while (!cpu->created) {
+        qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+    }
+}
+
 void qemu_init_vcpu(CPUState *cpu)
 {
     cpu->nr_cores = smp_cores;
@@ -1374,6 +1429,8 @@ void qemu_init_vcpu(CPUState *cpu)
     cpu->stopped = true;
     if (kvm_enabled()) {
         qemu_kvm_start_vcpu(cpu);
+    } else if (hvf_enabled()) {
+        qemu_hvf_start_vcpu(cpu);
     } else if (tcg_enabled()) {
         qemu_tcg_init_vcpu(cpu);
     } else {
diff --git a/hvf-all.c b/hvf-all.c
new file mode 100644
index 0000000..23e8aa1
--- /dev/null
+++ b/hvf-all.c
@@ -0,0 +1,179 @@
+/*
+ * QEMU HVF support
+ *
+ * Copyright (C) 2015 Assaf Gordon
+ *
+ * Based on kvm-all.c:
+ *    Copyright IBM, Corp. 2008
+ *              Red Hat, Inc. 2008
+ *    Authors:
+ *      Anthony Liguori   <aliguori@us.ibm.com>
+ *      Glauber Costa     <gcosta@redhat.com>
+ *
+ * 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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+
+#include "sysemu/hvf_int.h"
+#include "qemu/bswap.h"
+#include "exec/memory.h"
+#include "exec/ram_addr.h"
+#include "exec/address-spaces.h"
+#include "qemu/event_notifier.h"
+#include "trace.h"
+#include "hw/irq.h"
+
+#include "hw/boards.h"
+
+#define DEBUG_HVF
+
+#ifdef DEBUG_HVF
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define KVM_MSI_HASHTAB_SIZE    256
+
+struct HVFState
+{
+    AccelState parent_obj;
+
+    /* get hypervisor enforced capabilities of the machine, (see Intel docs) */
+    uint64_t vmx_cap_pinbased;
+    uint64_t vmx_cap_procbased;
+    uint64_t vmx_cap_procbased2;
+    uint64_t vmx_cap_entry;
+
+    /* TODO: move this to CPUState, allow multiple CPUs */
+    hv_vcpuid_t vcpu;
+
+    /* TODO: use qemu's memory management instead of this hack */
+    void *mem;
+};
+
+HVFState *hvf_state;
+bool hvf_allowed;
+
+int hvf_init_vcpu(CPUState *cpu)
+{
+    HVFState *s = hvf_state;
+    int ret;
+
+    DPRINTF("hvf_init_vcpu\n");
+
+    /* TODO:
+       Use Hypervisor.Framework, as described here:
+        http://www.pagetable.com/?p=764
+        http://www.pagetable.com/?p=831
+    */
+    cpu->hvf_state = s;
+
+    if ( (ret = hv_vcpu_create(&s->vcpu, HV_VCPU_DEFAULT)) ) {
+        DPRINTF("hv_vcpu_create failed (err=%d)\n", ret);
+        goto err;
+    }
+
+    /* TODO: Allocate memory the QEMU way */
+#define VM_MEM_SIZE (1 * 1024 * 1024)
+    void *vm_mem = valloc(VM_MEM_SIZE);
+    if (vm_mem == NULL) {
+        DPRINTF("valloc failed, errno=%d\n",errno);
+        goto err;
+    }
+    s->mem = vm_mem;
+
+    if ( (ret = hv_vm_map(vm_mem, 0, VM_MEM_SIZE, HV_MEMORY_READ |
+                    HV_MEMORY_WRITE | HV_MEMORY_EXEC)) ) {
+        DPRINTF("hv_vm_map failed (err=%d)\n", ret);
+        goto err;
+    }
+
+    DPRINTF("hvf_init_vcpu - done\n");
+    ret = 0;
+
+err:
+    return ret;
+}
+
+int hvf_cpu_exec(CPUState *cpu)
+{
+    DPRINTF("hvf_cpu_exec()\n");
+
+    return -1;
+}
+
+static int hvf_init(MachineState *ms)
+{
+    HVFState *s;
+    int ret;
+
+    DPRINTF("hvf_init\n");
+    s = HVF_STATE(ms->accelerator);
+
+
+    /* TODO: should 'ret' be modified/update errno? */
+    if ( (ret = hv_vm_create(HV_VM_DEFAULT)) ) {
+        DPRINTF("hv_vm_create failed (err=%d)\n",ret);
+        goto err;
+    }
+
+    if ( (ret = hv_vmx_read_capability(HV_VMX_CAP_PINBASED,
+                                       &s->vmx_cap_pinbased)) ) {
+        DPRINTF("v_vmx_read_cap(PINBASED) failed (err=%d)\n", ret);
+        goto err;
+    }
+    if ( (ret = hv_vmx_read_capability(HV_VMX_CAP_PROCBASED,
+                                       &s->vmx_cap_procbased)) ) {
+        DPRINTF("v_vmx_read_cap(PROCBASED) failed (err=%d)\n", ret);
+        goto err;
+    }
+    if ( (ret = hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2,
+                                       &s->vmx_cap_procbased2)) ) {
+        DPRINTF("v_vmx_read_cap(PROCBASED2) failed (err=%d)\n", ret);
+        goto err;
+    }
+    if ( (ret = hv_vmx_read_capability(HV_VMX_CAP_ENTRY,
+                                       &s->vmx_cap_entry)) ) {
+        DPRINTF("v_vmx_read_cap(CAP_ENTRY) failed (err=%d)\n", ret);
+        goto err;
+    }
+
+    hvf_state = s;
+
+    DPRINTF("hvf_init - done\n");
+    return 0;
+
+err:
+    return ret;
+}
+
+static void hvf_accel_class_init(ObjectClass *oc, void *data)
+{
+    AccelClass *ac = ACCEL_CLASS(oc);
+    ac->name = "HVF";
+    ac->init_machine = hvf_init;
+    ac->allowed = &hvf_allowed;
+}
+
+static const TypeInfo hvf_accel_type = {
+    .name = TYPE_HVF_ACCEL,
+    .parent = TYPE_ACCEL,
+    .class_init = hvf_accel_class_init,
+    .instance_size = sizeof(HVFState),
+};
+
+static void hvf_type_init(void)
+{
+    type_register_static(&hvf_accel_type);
+}
+
+type_init(hvf_type_init);
diff --git a/hvf-stub.c b/hvf-stub.c
new file mode 100644
index 0000000..8ba0371
--- /dev/null
+++ b/hvf-stub.c
@@ -0,0 +1,30 @@
+/*
+ * QEMU HVF stub
+ *
+ * Copyright (C) 2015 Assaf Gordon
+ *
+ * Based on kvm-stub.c:
+ *   Copyright Red Hat, Inc. 2010
+ *   Author: Paolo Bonzini     <pbonzini@redhat.com>
+ *
+ * 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-common.h"
+#include "hw/hw.h"
+#include "cpu.h"
+#include "sysemu/hvf.h"
+
+bool hvf_allowed;
+
+int hvf_init_vcpu(CPUState *cpu)
+{
+    return -ENOSYS;
+}
+
+int hvf_cpu_exec(CPUState *cpu)
+{
+    abort();
+}
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 51a1323..544f8d8 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -207,6 +207,8 @@ typedef struct CPUWatchpoint {
 struct KVMState;
 struct kvm_run;
 
+struct HVFState;
+
 #define TB_JMP_CACHE_BITS 12
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
 
@@ -314,6 +316,8 @@ struct CPUState {
     struct KVMState *kvm_state;
     struct kvm_run *kvm_run;
 
+    struct HVFState *hvf_state;
+
     /* TODO Move common fields from CPUArchState here. */
     int cpu_index; /* used by alpha TCG */
     uint32_t halted; /* used by alpha, cris, ppc TCG */
diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
new file mode 100644
index 0000000..cf51c6c
--- /dev/null
+++ b/include/sysemu/hvf.h
@@ -0,0 +1,49 @@
+/*
+ * QEMU HVF support
+ *
+ * Copyright (C) 2015 Assaf Gordon
+ *
+ * Based on ./include/sysemu/kvm.h:
+ *    Copyright IBM, Corp. 2008
+ *    Authors:
+ *      Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * 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 QEMU_HVF_H
+#define QEMU_HVF_H
+
+#include <errno.h>
+#include "config-host.h"
+#include "qemu/queue.h"
+#include "qom/cpu.h"
+#include "exec/memattrs.h"
+#include "hw/irq.h"
+
+#ifdef CONFIG_HVF
+#include <Hypervisor/hv.h>
+#include <Hypervisor/hv_vmx.h>
+#include <Hypervisor/hv_error.h>
+#endif
+
+extern bool hvf_allowed;
+
+#if defined CONFIG_HVF || !defined NEED_CPU_H
+#define hvf_enabled()           (hvf_allowed)
+#else
+#define hvf_enabled()           (0)
+#endif
+
+struct HVFState;
+typedef struct HVFState HVFState;
+extern HVFState *hvf_state;
+
+/* external API */
+
+int hvf_init_vcpu(CPUState *cpu);
+int hvf_cpu_exec(CPUState *cpu);
+
+#endif
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
new file mode 100644
index 0000000..ffab64a
--- /dev/null
+++ b/include/sysemu/hvf_int.h
@@ -0,0 +1,21 @@
+/*
+ * Internal definitions for a target's HVF support
+ *
+ * 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 QEMU_HVF_INT_H
+#define QEMU_HVF_INT_H
+
+#include "sysemu/sysemu.h"
+#include "sysemu/accel.h"
+#include "sysemu/hvf.h"
+
+#define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf")
+
+#define HVF_STATE(obj) \
+    OBJECT_CHECK(HVFState, (obj), TYPE_HVF_ACCEL)
+
+#endif
-- 
2.4.3


             reply	other threads:[~2015-11-12 10:49 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-12 10:49 Assaf Gordon [this message]
2015-11-12 14:39 ` [Qemu-devel] Attempt at Mac OS X acceleration using "Hypervisor.Framwork" Peter Maydell
2015-11-12 16:18   ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=784C0637-DC5D-45CA-B989-AF76378201D4@gmail.com \
    --to=assafgordon@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.