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
next 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.