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

