summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--Makefile.target5
-rw-r--r--arch_init.c21
-rwxr-xr-xconfigure27
-rw-r--r--cpus.c79
-rw-r--r--exec.c6
-rw-r--r--gdbstub.c1
-rw-r--r--hax-stub.c34
-rw-r--r--hw/Makefile.objs6
-rw-r--r--hw/acpi/Makefile.objs17
-rw-r--r--hw/acpi/acpi-stub.c29
-rw-r--r--hw/acpi/ipmi-stub.c (renamed from stubs/ipmi.c)0
-rw-r--r--hw/char/serial.c10
-rw-r--r--hw/core/Makefile.objs2
-rw-r--r--hw/core/reset.c72
-rw-r--r--hw/i386/kvm/apic.c1
-rw-r--r--hw/i386/kvmvapic.c1
-rw-r--r--hw/i386/pc.c4
-rw-r--r--hw/intc/apic_common.c3
-rw-r--r--hw/intc/ioapic.c22
-rw-r--r--hw/intc/ioapic_common.c3
-rw-r--r--hw/intc/trace-events7
-rw-r--r--hw/misc/vmport.c2
-rw-r--r--hw/ppc/pnv_xscom.c2
-rw-r--r--hw/ppc/ppce500_spin.c4
-rw-r--r--hw/ppc/spapr.c2
-rw-r--r--hw/ppc/spapr_hcall.c2
-rw-r--r--hw/s390x/s390-pci-inst.c1
-rw-r--r--hw/scsi/megasas.c11
-rw-r--r--hw/scsi/scsi-disk.c2
-rw-r--r--hw/smbios/Makefile.objs12
-rw-r--r--hw/smbios/smbios-stub.c31
-rw-r--r--hw/smbios/smbios.c2
-rw-r--r--hw/smbios/smbios_type_38-stub.c (renamed from stubs/smbios_type_38.c)0
-rw-r--r--hw/timer/mc146818rtc.c12
-rw-r--r--hw/usb/ccid-card-emulated.c2
-rw-r--r--hw/virtio/Makefile.objs6
-rw-r--r--hw/virtio/vhost-stub.c (renamed from stubs/vhost.c)0
-rw-r--r--hw/virtio/virtio.c10
-rw-r--r--include/exec/memory.h6
-rw-r--r--include/exec/ram_addr.h46
-rw-r--r--include/exec/ramlist.h72
-rw-r--r--include/hw/hw.h6
-rw-r--r--include/hw/i386/pc.h7
-rw-r--r--include/hw/smbios/smbios.h2
-rw-r--r--include/io/dns-resolver.h228
-rw-r--r--include/io/task.h154
-rw-r--r--include/qemu/event_notifier.h3
-rw-r--r--include/qemu/main-loop.h15
-rw-r--r--include/qemu/sockets.h2
-rw-r--r--include/qom/cpu.h5
-rw-r--r--include/sysemu/arch_init.h2
-rw-r--r--include/sysemu/hax.h56
-rw-r--r--include/sysemu/hw_accel.h48
-rw-r--r--include/sysemu/kvm.h23
-rw-r--r--include/sysemu/reset.h10
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--io/Makefile.objs1
-rw-r--r--io/channel-socket.c44
-rw-r--r--io/channel-tls.c16
-rw-r--r--io/channel-websock.c8
-rw-r--r--io/dns-resolver.c276
-rw-r--r--io/task.c62
-rw-r--r--io/trace-events1
-rw-r--r--iohandler.c8
-rw-r--r--migration/Makefile.objs3
-rw-r--r--migration/socket.c11
-rw-r--r--migration/tls.c19
-rw-r--r--monitor.c2
-rw-r--r--nbd/common.c8
-rw-r--r--nbd/nbd-internal.h3
-rw-r--r--numa.c29
-rw-r--r--qapi-schema.json5
-rw-r--r--qemu-char.c33
-rw-r--r--qemu-options-wrapper.h2
-rw-r--r--qemu-options.hx42
-rw-r--r--qom/cpu.c2
-rw-r--r--qom/object.c6
-rw-r--r--scripts/hxtool11
-rw-r--r--stubs/Makefile.objs19
-rw-r--r--stubs/cpus.c11
-rw-r--r--stubs/fdset-add-fd.c8
-rw-r--r--stubs/fdset-find-fd.c8
-rw-r--r--stubs/fdset-get-fd.c8
-rw-r--r--stubs/fdset-remove-fd.c7
-rw-r--r--stubs/fdset.c22
-rw-r--r--stubs/get-next-serial.c4
-rw-r--r--stubs/iohandler.c8
-rw-r--r--stubs/kvm.c8
-rw-r--r--stubs/migration-colo.c46
-rw-r--r--stubs/mon-is-qmp.c10
-rw-r--r--stubs/monitor-init.c7
-rw-r--r--stubs/monitor.c (renamed from stubs/get-fd.c)6
-rw-r--r--stubs/replay-user.c33
-rw-r--r--stubs/reset.c14
-rw-r--r--target/arm/cpu.c2
-rw-r--r--target/i386/Makefile.objs7
-rw-r--r--target/i386/hax-all.c1155
-rw-r--r--target/i386/hax-darwin.c316
-rw-r--r--target/i386/hax-darwin.h63
-rw-r--r--target/i386/hax-i386.h94
-rw-r--r--target/i386/hax-interface.h361
-rw-r--r--target/i386/hax-mem.c289
-rw-r--r--target/i386/hax-windows.c479
-rw-r--r--target/i386/hax-windows.h89
-rw-r--r--target/i386/helper.c1
-rw-r--r--target/i386/hyperv.c7
-rw-r--r--target/i386/kvm.c1
-rw-r--r--target/mips/kvm.c5
-rw-r--r--target/ppc/kvm.c7
-rw-r--r--target/ppc/kvm_ppc.h12
-rw-r--r--target/ppc/mmu-hash64.c2
-rw-r--r--target/ppc/translate_init.c2
-rw-r--r--target/s390x/gdbstub.c1
-rw-r--r--target/s390x/kvm.c5
-rw-r--r--tests/Makefile.include1
-rw-r--r--tests/device-introspect-test.c60
-rw-r--r--tests/test-io-channel-socket.c5
-rw-r--r--tests/test-io-channel-tls.c5
-rw-r--r--tests/test-io-task.c31
-rw-r--r--ui/vnc-auth-vencrypt.c7
-rw-r--r--ui/vnc-ws.c14
-rw-r--r--user-exec-stub.c34
-rw-r--r--util/bitmap.c8
-rw-r--r--util/event_notifier-posix.c9
-rw-r--r--util/event_notifier-win32.c12
-rw-r--r--util/qemu-sockets.c11
-rw-r--r--util/qemu-thread-posix.c12
-rw-r--r--util/qemu-thread-win32.c4
-rw-r--r--vl.c62
-rw-r--r--xen-mapcache.c3
131 files changed, 4488 insertions, 637 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 44c42fb764..60b0b0922c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1507,6 +1507,7 @@ M: Riku Voipio <riku.voipio@iki.fi>
S: Maintained
F: thunk.c
F: user-exec.c
+F: user-exec-stub.c
BSD user
S: Orphan
diff --git a/Makefile.target b/Makefile.target
index 8ae82cb311..fa2b151caa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -97,6 +97,7 @@ obj-y += target/$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-y += tcg-runtime.o
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
+obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o
@@ -115,7 +116,7 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
-I$(SRC_PATH)/linux-user
obj-y += linux-user/
-obj-y += gdbstub.o thunk.o user-exec.o
+obj-y += gdbstub.o thunk.o user-exec.o user-exec-stub.o
endif #CONFIG_LINUX_USER
@@ -128,7 +129,7 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
-I$(SRC_PATH)/bsd-user/$(HOST_VARIANT_DIR)
obj-y += bsd-user/
-obj-y += gdbstub.o user-exec.o
+obj-y += gdbstub.o user-exec.o user-exec-stub.o
endif #CONFIG_BSD_USER
diff --git a/arch_init.c b/arch_init.c
index 5cc58b2c35..6c4e287d57 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -28,7 +28,6 @@
#include "sysemu/arch_init.h"
#include "hw/pci/pci.h"
#include "hw/audio/audio.h"
-#include "hw/smbios/smbios.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qmp-commands.h"
@@ -235,26 +234,6 @@ void audio_init(void)
}
}
-void do_acpitable_option(const QemuOpts *opts)
-{
-#ifdef TARGET_I386
- Error *err = NULL;
-
- acpi_table_add(opts, &err);
- if (err) {
- error_reportf_err(err, "Wrong acpi table provided: ");
- exit(1);
- }
-#endif
-}
-
-void do_smbios_option(QemuOpts *opts)
-{
-#ifdef TARGET_I386
- smbios_entry_add(opts);
-#endif
-}
-
int kvm_available(void)
{
#ifdef CONFIG_KVM
diff --git a/configure b/configure
index 90f01e8a35..1004ef5573 100755
--- a/configure
+++ b/configure
@@ -228,7 +228,7 @@ vhost_net="no"
vhost_scsi="no"
vhost_vsock="no"
kvm="no"
-colo="yes"
+hax="no"
rdma=""
gprof="no"
debug_tcg="no"
@@ -562,6 +562,7 @@ CYGWIN*)
;;
MINGW32*)
mingw32="yes"
+ hax="yes"
audio_possible_drivers="dsound sdl"
if check_include dsound.h; then
audio_drv_list="dsound"
@@ -611,6 +612,7 @@ OpenBSD)
Darwin)
bsd="yes"
darwin="yes"
+ hax="yes"
LDFLAGS_SHARED="-bundle -undefined dynamic_lookup"
if [ "$cpu" = "x86_64" ] ; then
QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
@@ -920,9 +922,9 @@ for opt do
;;
--enable-kvm) kvm="yes"
;;
- --disable-colo) colo="no"
+ --disable-hax) hax="no"
;;
- --enable-colo) colo="yes"
+ --enable-hax) hax="yes"
;;
--disable-tcg-interpreter) tcg_interpreter="no"
;;
@@ -1372,7 +1374,7 @@ disabled with --disable-FEATURE, default is enabled if available:
fdt fdt device tree
bluez bluez stack connectivity
kvm KVM acceleration support
- colo COarse-grain LOck-stepping VM for Non-stop Service
+ hax HAX acceleration support
rdma RDMA-based migration support
vde support for vde network
netmap support for netmap network
@@ -3077,7 +3079,7 @@ fi
# g_test_trap_subprocess added in 2.38. Used by some tests.
glib_subprocess=yes
-if test "$mingw32" = "yes" || ! $pkg_config --atleast-version=2.38 glib-2.0; then
+if ! $pkg_config --atleast-version=2.38 glib-2.0; then
glib_subprocess=no
fi
@@ -5062,7 +5064,7 @@ echo "Linux AIO support $linux_aio"
echo "ATTR/XATTR support $attr"
echo "Install blobs $blobs"
echo "KVM support $kvm"
-echo "COLO support $colo"
+echo "HAX support $hax"
echo "RDMA support $rdma"
echo "TCG interpreter $tcg_interpreter"
echo "fdt support $fdt"
@@ -5701,10 +5703,6 @@ if have_backend "syslog"; then
fi
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
-if test "$colo" = "yes"; then
- echo "CONFIG_COLO=y" >> $config_host_mak
-fi
-
if test "$rdma" = "yes" ; then
echo "CONFIG_RDMA=y" >> $config_host_mak
fi
@@ -6052,6 +6050,15 @@ case "$target_name" in
fi
fi
esac
+if test "$hax" = "yes" ; then
+ if test "$target_softmmu" = "yes" ; then
+ case "$target_name" in
+ i386|x86_64)
+ echo "CONFIG_HAX=y" >> $config_target_mak
+ ;;
+ esac
+ fi
+fi
if test "$target_bigendian" = "yes" ; then
echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
fi
diff --git a/cpus.c b/cpus.c
index 5213351c6d..71a82e5004 100644
--- a/cpus.c
+++ b/cpus.c
@@ -33,7 +33,9 @@
#include "sysemu/block-backend.h"
#include "exec/gdbstub.h"
#include "sysemu/dma.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
+#include "sysemu/hax.h"
#include "qmp-commands.h"
#include "exec/exec-all.h"
@@ -1220,6 +1222,46 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
return NULL;
}
+static void *qemu_hax_cpu_thread_fn(void *arg)
+{
+ CPUState *cpu = arg;
+ int r;
+ qemu_thread_get_self(cpu->thread);
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ cpu->thread_id = qemu_get_thread_id();
+ cpu->created = true;
+ cpu->halted = 0;
+ current_cpu = cpu;
+
+ hax_init_vcpu(cpu);
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ while (1) {
+ if (cpu_can_run(cpu)) {
+ r = hax_smp_cpu_exec(cpu);
+ if (r == EXCP_DEBUG) {
+ cpu_handle_guest_debug(cpu);
+ }
+ }
+
+ while (cpu_thread_is_idle(cpu)) {
+ qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
+ }
+#ifdef _WIN32
+ SleepEx(0, TRUE);
+#endif
+ qemu_wait_io_event_common(cpu);
+ }
+ return NULL;
+}
+
+#ifdef _WIN32
+static void CALLBACK dummy_apc_func(ULONG_PTR unused)
+{
+}
+#endif
+
static void qemu_cpu_kick_thread(CPUState *cpu)
{
#ifndef _WIN32
@@ -1235,7 +1277,13 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
exit(1);
}
#else /* _WIN32 */
- abort();
+ if (!qemu_cpu_is_self(cpu)) {
+ if (!QueueUserAPC(dummy_apc_func, cpu->hThread, 0)) {
+ fprintf(stderr, "%s: QueueUserAPC failed with error %lu\n",
+ __func__, GetLastError());
+ exit(1);
+ }
+ }
#endif
}
@@ -1258,6 +1306,13 @@ void qemu_cpu_kick(CPUState *cpu)
if (tcg_enabled()) {
qemu_cpu_kick_no_halt();
} else {
+ if (hax_enabled()) {
+ /*
+ * FIXME: race condition with the exit_request check in
+ * hax_vcpu_hax_exec
+ */
+ cpu->exit_request = 1;
+ }
qemu_cpu_kick_thread(cpu);
}
}
@@ -1418,6 +1473,26 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)
}
}
+static void qemu_hax_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/HAX",
+ cpu->cpu_index);
+ qemu_thread_create(cpu->thread, thread_name, qemu_hax_cpu_thread_fn,
+ cpu, QEMU_THREAD_JOINABLE);
+#ifdef _WIN32
+ cpu->hThread = qemu_thread_get_handle(cpu->thread);
+#endif
+ while (!cpu->created) {
+ qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+ }
+}
+
static void qemu_kvm_start_vcpu(CPUState *cpu)
{
char thread_name[VCPU_THREAD_NAME_SIZE];
@@ -1468,6 +1543,8 @@ void qemu_init_vcpu(CPUState *cpu)
if (kvm_enabled()) {
qemu_kvm_start_vcpu(cpu);
+ } else if (hax_enabled()) {
+ qemu_hax_start_vcpu(cpu);
} else if (tcg_enabled()) {
qemu_tcg_init_vcpu(cpu);
} else {
diff --git a/exec.c b/exec.c
index 401a9127c2..f2bed92b64 100644
--- a/exec.c
+++ b/exec.c
@@ -1687,6 +1687,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
/* MADV_DONTFORK is also needed by KVM in absence of synchronous MMU */
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
+ ram_block_notify_add(new_block->host, new_block->max_length);
}
}
@@ -1817,6 +1818,10 @@ void qemu_ram_free(RAMBlock *block)
return;
}
+ if (block->host) {
+ ram_block_notify_remove(block->host, block->max_length);
+ }
+
qemu_mutex_lock_ramlist();
QLIST_REMOVE_RCU(block, next);
ram_list.mru_block = NULL;
@@ -2960,6 +2965,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
if (!memory_access_is_direct(mr, is_write)) {
l = memory_access_size(mr, l, addr);
if (!memory_region_access_valid(mr, xlat, l, is_write)) {
+ rcu_read_unlock();
return false;
}
}
diff --git a/gdbstub.c b/gdbstub.c
index de62d26096..de9b62b8f8 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -32,6 +32,7 @@
#define MAX_PACKET_LENGTH 4096
#include "qemu/sockets.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h"
#include "exec/exec-all.h"
diff --git a/hax-stub.c b/hax-stub.c
new file mode 100644
index 0000000000..c0e6f892e5
--- /dev/null
+++ b/hax-stub.c
@@ -0,0 +1,34 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2015, Intel Corporation
+ *
+ * Copyright 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "sysemu/hax.h"
+
+int hax_sync_vcpus(void)
+{
+ return 0;
+}
+
+int hax_init_vcpu(CPUState *cpu)
+{
+ return -ENOSYS;
+}
+
+int hax_smp_cpu_exec(CPUState *cpu)
+{
+ return -ENOSYS;
+}
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 0ffd281145..a2c61f6b09 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,5 +1,5 @@
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
-devices-dirs-$(CONFIG_ACPI) += acpi/
+devices-dirs-$(CONFIG_SOFTMMU) += acpi/
devices-dirs-$(CONFIG_SOFTMMU) += adc/
devices-dirs-$(CONFIG_SOFTMMU) += audio/
devices-dirs-$(CONFIG_SOFTMMU) += block/
@@ -29,11 +29,11 @@ devices-dirs-$(CONFIG_SOFTMMU) += timer/
devices-dirs-$(CONFIG_TPM) += tpm/
devices-dirs-$(CONFIG_SOFTMMU) += usb/
devices-dirs-$(CONFIG_SOFTMMU) += vfio/
-devices-dirs-$(CONFIG_VIRTIO) += virtio/
+devices-dirs-$(CONFIG_SOFTMMU) += virtio/
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/
-devices-dirs-$(CONFIG_SMBIOS) += smbios/
+devices-dirs-$(CONFIG_SOFTMMU) += smbios/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 834c63b980..6acf79860a 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -1,10 +1,19 @@
+ifeq ($(CONFIG_ACPI),y)
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
-common-obj-$(CONFIG_ACPI) += acpi_interface.o
-common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
-common-obj-$(CONFIG_ACPI) += aml-build.o
-common-obj-$(call land,$(CONFIG_ACPI),$(CONFIG_IPMI)) += ipmi.o
+common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
+
+common-obj-y += acpi_interface.o
+common-obj-y += bios-linker-loader.o
+common-obj-y += aml-build.o
+
+common-obj-$(CONFIG_IPMI) += ipmi.o
+common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o
+else
+common-obj-y += acpi-stub.o
+endif
+common-obj-$(CONFIG_ALL) += acpi-stub.o ipmi-stub.o
diff --git a/hw/acpi/acpi-stub.c b/hw/acpi/acpi-stub.c
new file mode 100644
index 0000000000..26bd22f7ec
--- /dev/null
+++ b/hw/acpi/acpi-stub.c
@@ -0,0 +1,29 @@
+/*
+ * ACPI stubs for platforms that don't support ACPI.
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qerror.h"
+#include "qmp-commands.h"
+#include "hw/acpi/acpi.h"
+
+void acpi_table_add(const QemuOpts *opts, Error **errp)
+{
+ error_setg(errp, QERR_UNSUPPORTED);
+}
diff --git a/stubs/ipmi.c b/hw/acpi/ipmi-stub.c
index 98b6dcee0d..98b6dcee0d 100644
--- a/stubs/ipmi.c
+++ b/hw/acpi/ipmi-stub.c
diff --git a/hw/char/serial.c b/hw/char/serial.c
index ffbacd8227..67b18eda12 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -906,6 +906,16 @@ void serial_realize_core(SerialState *s, Error **errp)
void serial_exit_core(SerialState *s)
{
qemu_chr_fe_deinit(&s->chr);
+
+ timer_del(s->modem_status_poll);
+ timer_free(s->modem_status_poll);
+
+ timer_del(s->fifo_timeout_timer);
+ timer_free(s->fifo_timeout_timer);
+
+ fifo8_destroy(&s->recv_fifo);
+ fifo8_destroy(&s->xmit_fifo);
+
qemu_unregister_reset(serial_reset, s);
}
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index a4c94e522d..833fd46897 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -1,6 +1,6 @@
# core qdev-related obj files, also used by *-user:
common-obj-y += qdev.o qdev-properties.o
-common-obj-y += bus.o
+common-obj-y += bus.o reset.o
common-obj-y += fw-path-provider.o
# irq.o needed for qdev GPIO handling:
common-obj-y += irq.o
diff --git a/hw/core/reset.c b/hw/core/reset.c
new file mode 100644
index 0000000000..84c8869371
--- /dev/null
+++ b/hw/core/reset.c
@@ -0,0 +1,72 @@
+/*
+ * Reset handlers.
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/queue.h"
+#include "sysemu/reset.h"
+
+/* reset/shutdown handler */
+
+typedef struct QEMUResetEntry {
+ QTAILQ_ENTRY(QEMUResetEntry) entry;
+ QEMUResetHandler *func;
+ void *opaque;
+} QEMUResetEntry;
+
+static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
+ QTAILQ_HEAD_INITIALIZER(reset_handlers);
+
+void qemu_register_reset(QEMUResetHandler *func, void *opaque)
+{
+ QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry));
+
+ re->func = func;
+ re->opaque = opaque;
+ QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
+}
+
+void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
+{
+ QEMUResetEntry *re;
+
+ QTAILQ_FOREACH(re, &reset_handlers, entry) {
+ if (re->func == func && re->opaque == opaque) {
+ QTAILQ_REMOVE(&reset_handlers, re, entry);
+ g_free(re);
+ return;
+ }
+ }
+}
+
+void qemu_devices_reset(void)
+{
+ QEMUResetEntry *re, *nre;
+
+ /* reset all devices */
+ QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
+ re->func(re->opaque);
+ }
+}
+
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index df5180b1e0..1df6d26816 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -14,6 +14,7 @@
#include "cpu.h"
#include "hw/i386/apic_internal.h"
#include "hw/pci/msi.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
#include "target/i386/kvm_i386.h"
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index b30d1b90c6..2f767b620e 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -14,6 +14,7 @@
#include "exec/exec-all.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
#include "hw/i386/apic_internal.h"
#include "hw/sysbus.h"
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 25e8586b48..f721fde0c2 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1820,8 +1820,10 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev,
/* increment the number of CPUs */
pcms->boot_cpus++;
- if (dev->hotplugged) {
+ if (pcms->rtc) {
rtc_set_cpus_count(pcms->rtc, pcms->boot_cpus);
+ }
+ if (pcms->fw_cfg) {
fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
}
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index d78c885509..3945dfd7b9 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -26,6 +26,7 @@
#include "hw/i386/apic.h"
#include "hw/i386/apic_internal.h"
#include "trace.h"
+#include "sysemu/hax.h"
#include "sysemu/kvm.h"
#include "hw/qdev.h"
#include "hw/sysbus.h"
@@ -316,7 +317,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
/* Note: We need at least 1M to map the VAPIC option ROM */
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
- ram_size >= 1024 * 1024) {
+ !hax_enabled() && ram_size >= 1024 * 1024) {
vapic = sysbus_create_simple("kvmvapic", -1, NULL);
}
s->vapic = vapic;
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index ea7ea0bce8..9047b8950a 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -33,6 +33,7 @@
#include "target/i386/cpu.h"
#include "hw/i386/apic-msidef.h"
#include "hw/i386/x86-iommu.h"
+#include "trace.h"
//#define DEBUG_IOAPIC
@@ -115,6 +116,7 @@ static void ioapic_service(IOAPICCommonState *s)
s->irr &= ~mask;
} else {
coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
+ trace_ioapic_set_remote_irr(i);
s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
}
@@ -220,6 +222,8 @@ void ioapic_eoi_broadcast(int vector)
uint64_t entry;
int i, n;
+ trace_ioapic_eoi_broadcast(vector);
+
for (i = 0; i < MAX_IOAPICS; i++) {
s = ioapics[i];
if (!s) {
@@ -229,6 +233,7 @@ void ioapic_eoi_broadcast(int vector)
entry = s->ioredtbl[n];
if ((entry & IOAPIC_LVT_REMOTE_IRR)
&& (entry & IOAPIC_VECTOR_MASK) == vector) {
+ trace_ioapic_clear_remote_irr(n, vector);
s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
ioapic_service(s);
@@ -256,7 +261,9 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
int index;
uint32_t val = 0;
- switch (addr & 0xff) {
+ addr &= 0xff;
+
+ switch (addr) {
case IOAPIC_IOREGSEL:
val = s->ioregsel;
break;
@@ -286,6 +293,9 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
break;
}
+
+ trace_ioapic_mem_read(addr, size, val);
+
return val;
}
@@ -324,7 +334,10 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
IOAPICCommonState *s = opaque;
int index;
- switch (addr & 0xff) {
+ addr &= 0xff;
+ trace_ioapic_mem_write(addr, size, val);
+
+ switch (addr) {
case IOAPIC_IOREGSEL:
s->ioregsel = val;
break;
@@ -426,6 +439,11 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
k->realize = ioapic_realize;
+ /*
+ * If APIC is in kernel, we need to update the kernel cache after
+ * migration, otherwise first 24 gsi routes will be invalid.
+ */
+ k->post_load = ioapic_update_kvm_routes;
dc->reset = ioapic_reset_common;
dc->props = ioapic_properties;
}
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
index 1b7ec5ec20..97c4f9c2df 100644
--- a/hw/intc/ioapic_common.c
+++ b/hw/intc/ioapic_common.c
@@ -58,7 +58,8 @@ void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s)
uint32_t remote_irr = 0;
int i;
- monitor_printf(mon, "ioapic id=0x%02x sel=0x%02x", s->id, s->ioregsel);
+ monitor_printf(mon, "ioapic ver=0x%x id=0x%02x sel=0x%02x",
+ s->version, s->id, s->ioregsel);
if (s->ioregsel) {
monitor_printf(mon, " (redir[%u])\n",
(s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1);
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 6116df5436..92a6171692 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -14,6 +14,13 @@ apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t
apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
+# hw/intc/ioapic.c
+ioapic_set_remote_irr(int n) "set remote irr for pin %d"
+ioapic_clear_remote_irr(int n, int vector) "clear remote irr for pin %d vector %d"
+ioapic_eoi_broadcast(int vector) "EOI broadcast for vector %d"
+ioapic_mem_read(uint8_t addr, uint8_t size, uint32_t val) "ioapic mem read addr 0x%"PRIx8" size 0x%"PRIx8" retval 0x%"PRIx32
+ioapic_mem_write(uint8_t addr, uint8_t size, uint32_t val) "ioapic mem write addr 0x%"PRIx8" size 0x%"PRIx8" val 0x%"PRIx32
+
# hw/intc/slavio_intctl.c
slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x"
slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x"
diff --git a/hw/misc/vmport.c b/hw/misc/vmport.c
index c763811a9f..be40930b8b 100644
--- a/hw/misc/vmport.c
+++ b/hw/misc/vmport.c
@@ -25,7 +25,7 @@
#include "hw/hw.h"
#include "hw/isa/isa.h"
#include "hw/i386/pc.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "hw/qdev.h"
//#define VMPORT_DEBUG
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index b82af4f086..38bc85f117 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -20,7 +20,7 @@
#include "qapi/error.h"
#include "hw/hw.h"
#include "qemu/log.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "target/ppc/cpu.h"
#include "hw/sysbus.h"
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index cf958a9e00..eb219abdff 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -29,9 +29,9 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/sysemu.h"
#include "e500.h"
#define MAX_CPUS 32
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 208ef7b110..a642e663d4 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -36,7 +36,7 @@
#include "sysemu/device_tree.h"
#include "sysemu/block-backend.h"
#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "kvm_ppc.h"
#include "migration/migration.h"
#include "mmu-hash64.h"
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 9a9bedf1bd..b2a8e48569 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
#include "cpu.h"
@@ -9,7 +10,6 @@
#include "mmu-hash64.h"
#include "cpu-models.h"
#include "trace.h"
-#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "hw/ppc/spapr_ovec.h"
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 405cccd2d0..d2a8c0a083 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -18,6 +18,7 @@
#include "s390-pci-bus.h"
#include "exec/memory-internal.h"
#include "qemu/error-report.h"
+#include "sysemu/hw_accel.h"
/* #define DEBUG_S390PCI_INST */
#ifdef DEBUG_S390PCI_INST
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 67fc1e7893..6233865494 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -683,14 +683,14 @@ static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
trace_megasas_dcmd_invalid_sge(cmd->index,
cmd->frame->header.sge_count);
cmd->iov_size = 0;
- return -1;
+ return -EINVAL;
}
iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), 1);
qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
cmd->iov_size = iov_size;
- return cmd->iov_size;
+ return 0;
}
static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
@@ -1559,19 +1559,20 @@ static const struct dcmd_cmd_tbl_t {
static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd)
{
- int opcode, len;
+ int opcode;
int retval = 0;
+ size_t len;
const struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
trace_megasas_handle_dcmd(cmd->index, opcode);
- len = megasas_map_dcmd(s, cmd);
- if (len < 0) {
+ if (megasas_map_dcmd(s, cmd) < 0) {
return MFI_STAT_MEMORY_NOT_AVAILABLE;
}
while (cmdptr->opcode != -1 && cmdptr->opcode != opcode) {
cmdptr++;
}
+ len = cmd->iov_size;
if (cmdptr->opcode == -1) {
trace_megasas_dcmd_unhandled(cmd->index, opcode, len);
retval = megasas_dcmd_dummy(s, cmd);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index bdd1e5f86c..c080888413 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2701,7 +2701,7 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf)
* for the number of logical blocks specified in the length
* field). For other modes, do not use scatter/gather operation.
*/
- if ((buf[1] & 6) != 2) {
+ if ((buf[1] & 6) == 2) {
return false;
}
break;
diff --git a/hw/smbios/Makefile.objs b/hw/smbios/Makefile.objs
index c3d3753602..23bb2bac07 100644
--- a/hw/smbios/Makefile.objs
+++ b/hw/smbios/Makefile.objs
@@ -1,2 +1,10 @@
-common-obj-$(CONFIG_SMBIOS) += smbios.o
-common-obj-$(call land,$(CONFIG_SMBIOS),$(CONFIG_IPMI)) += smbios_type_38.o
+ifeq ($(CONFIG_SMBIOS),y)
+common-obj-y += smbios.o
+common-obj-$(CONFIG_IPMI) += smbios_type_38.o
+common-obj-$(call lnot,$(CONFIG_IPMI)) += smbios_type_38-stub.o
+else
+common-obj-y += smbios-stub.o
+endif
+
+common-obj-$(CONFIG_ALL) += smbios-stub.o
+common-obj-$(CONFIG_ALL) += smbios_type_38-stub.o
diff --git a/hw/smbios/smbios-stub.c b/hw/smbios/smbios-stub.c
new file mode 100644
index 0000000000..308739410f
--- /dev/null
+++ b/hw/smbios/smbios-stub.c
@@ -0,0 +1,31 @@
+/*
+ * SMBIOS stubs for platforms that don't support SMBIOS.
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ * Copyright (c) 2016 Leif Lindholm <leif.lindholm@linaro.org>
+ * Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qerror.h"
+#include "qmp-commands.h"
+#include "hw/smbios/smbios.h"
+
+void smbios_entry_add(QemuOpts *opts, Error **errp)
+{
+ error_setg(errp, QERR_UNSUPPORTED);
+}
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index 3a96cededd..1a5437a07d 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -882,7 +882,7 @@ static void save_opt(const char **dest, QemuOpts *opts, const char *name)
}
}
-void smbios_entry_add(QemuOpts *opts)
+void smbios_entry_add(QemuOpts *opts, Error **errp)
{
const char *val;
diff --git a/stubs/smbios_type_38.c b/hw/smbios/smbios_type_38-stub.c
index 9528c2c28e..9528c2c28e 100644
--- a/stubs/smbios_type_38.c
+++ b/hw/smbios/smbios_type_38-stub.c
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index da209d02f0..637f8722a7 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -946,11 +946,23 @@ static Property mc146818rtc_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void rtc_resetdev(DeviceState *d)
+{
+ RTCState *s = MC146818_RTC(d);
+
+ /* Reason: VM do suspend self will set 0xfe
+ * Reset any values other than 0xfe(Guest suspend case) */
+ if (s->cmos_data[0x0f] != 0xfe) {
+ s->cmos_data[0x0f] = 0x00;
+ }
+}
+
static void rtc_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = rtc_realizefn;
+ dc->reset = rtc_resetdev;
dc->vmsd = &vmstate_rtc;
dc->props = mc146818rtc_properties;
/* Reason: needs to be wired up by rtc_init() */
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index eceb5f3ee2..99627860a3 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -407,7 +407,7 @@ static int init_event_notifier(EmulatedState *card)
DPRINTF(card, 2, "event notifier creation failed\n");
return -1;
}
- event_notifier_set_handler(&card->notifier, false, card_event_handler);
+ event_notifier_set_handler(&card->notifier, card_event_handler);
return 0;
}
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 95c4c30ea1..765d363c1f 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -1,3 +1,4 @@
+ifeq ($(CONFIG_VIRTIO),y)
common-obj-y += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += virtio-bus.o
@@ -5,7 +6,10 @@ common-obj-y += virtio-mmio.o
obj-y += virtio.o virtio-balloon.o
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
-
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
obj-y += virtio-crypto.o
obj-$(CONFIG_VIRTIO_PCI) += virtio-crypto-pci.o
+endif
+
+common-obj-$(call lnot,$(CONFIG_LINUX)) += vhost-stub.o
+common-obj-$(CONFIG_ALL) += vhost-stub.o
diff --git a/stubs/vhost.c b/hw/virtio/vhost-stub.c
index 2d76cdebdc..2d76cdebdc 100644
--- a/stubs/vhost.c
+++ b/hw/virtio/vhost-stub.c
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index ac9b99b928..cc17b97899 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2082,10 +2082,10 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
bool with_irqfd)
{
if (assign && !with_irqfd) {
- event_notifier_set_handler(&vq->guest_notifier, false,
+ event_notifier_set_handler(&vq->guest_notifier,
virtio_queue_guest_notifier_read);
} else {
- event_notifier_set_handler(&vq->guest_notifier, false, NULL);
+ event_notifier_set_handler(&vq->guest_notifier, NULL);
}
if (!assign) {
/* Test and clear notifier before closing it,
@@ -2257,7 +2257,7 @@ static int virtio_device_start_ioeventfd_impl(VirtIODevice *vdev)
err = r;
goto assign_error;
}
- event_notifier_set_handler(&vq->host_notifier, true,
+ event_notifier_set_handler(&vq->host_notifier,
virtio_queue_host_notifier_read);
}
@@ -2278,7 +2278,7 @@ assign_error:
continue;
}
- event_notifier_set_handler(&vq->host_notifier, true, NULL);
+ event_notifier_set_handler(&vq->host_notifier, NULL);
r = virtio_bus_set_host_notifier(qbus, n, false);
assert(r >= 0);
}
@@ -2304,7 +2304,7 @@ static void virtio_device_stop_ioeventfd_impl(VirtIODevice *vdev)
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
- event_notifier_set_handler(&vq->host_notifier, true, NULL);
+ event_notifier_set_handler(&vq->host_notifier, NULL);
r = virtio_bus_set_host_notifier(qbus, n, false);
assert(r >= 0);
}
diff --git a/include/exec/memory.h b/include/exec/memory.h
index bec9756667..a10044f08f 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -16,16 +16,12 @@
#ifndef CONFIG_USER_ONLY
-#define DIRTY_MEMORY_VGA 0
-#define DIRTY_MEMORY_CODE 1
-#define DIRTY_MEMORY_MIGRATION 2
-#define DIRTY_MEMORY_NUM 3 /* num of dirty bits */
-
#include "exec/cpu-common.h"
#ifndef CONFIG_USER_ONLY
#include "exec/hwaddr.h"
#endif
#include "exec/memattrs.h"
+#include "exec/ramlist.h"
#include "qemu/queue.h"
#include "qemu/int128.h"
#include "qemu/notify.h"
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 54d7108a9e..3e79466a44 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -21,6 +21,7 @@
#ifndef CONFIG_USER_ONLY
#include "hw/xen/xen.h"
+#include "exec/ramlist.h"
struct RAMBlock {
struct rcu_head rcu;
@@ -35,6 +36,7 @@ struct RAMBlock {
char idstr[256];
/* RCU-enabled, writes protected by the ramlist lock */
QLIST_ENTRY(RAMBlock) next;
+ QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
int fd;
size_t page_size;
};
@@ -50,51 +52,7 @@ static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset)
return (char *)block->host + offset;
}
-/* The dirty memory bitmap is split into fixed-size blocks to allow growth
- * under RCU. The bitmap for a block can be accessed as follows:
- *
- * rcu_read_lock();
- *
- * DirtyMemoryBlocks *blocks =
- * atomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]);
- *
- * ram_addr_t idx = (addr >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE;
- * unsigned long *block = blocks.blocks[idx];
- * ...access block bitmap...
- *
- * rcu_read_unlock();
- *
- * Remember to check for the end of the block when accessing a range of
- * addresses. Move on to the next block if you reach the end.
- *
- * Organization into blocks allows dirty memory to grow (but not shrink) under
- * RCU. When adding new RAMBlocks requires the dirty memory to grow, a new
- * DirtyMemoryBlocks array is allocated with pointers to existing blocks kept
- * the same. Other threads can safely access existing blocks while dirty
- * memory is being grown. When no threads are using the old DirtyMemoryBlocks
- * anymore it is freed by RCU (but the underlying blocks stay because they are
- * pointed to from the new DirtyMemoryBlocks).
- */
-#define DIRTY_MEMORY_BLOCK_SIZE ((ram_addr_t)256 * 1024 * 8)
-typedef struct {
- struct rcu_head rcu;
- unsigned long *blocks[];
-} DirtyMemoryBlocks;
-
-typedef struct RAMList {
- QemuMutex mutex;
- RAMBlock *mru_block;
- /* RCU-enabled, writes protected by the ramlist lock. */
- QLIST_HEAD(, RAMBlock) blocks;
- DirtyMemoryBlocks *dirty_memory[DIRTY_MEMORY_NUM];
- uint32_t version;
-} RAMList;
-extern RAMList ram_list;
-
ram_addr_t last_ram_offset(void);
-void qemu_mutex_lock_ramlist(void);
-void qemu_mutex_unlock_ramlist(void);
-
RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
bool share, const char *mem_path,
Error **errp);
diff --git a/include/exec/ramlist.h b/include/exec/ramlist.h
new file mode 100644
index 0000000000..c59880de82
--- /dev/null
+++ b/include/exec/ramlist.h
@@ -0,0 +1,72 @@
+#ifndef RAMLIST_H
+#define RAMLIST_H
+
+#include "qemu/queue.h"
+#include "qemu/thread.h"
+#include "qemu/rcu.h"
+
+typedef struct RAMBlockNotifier RAMBlockNotifier;
+
+#define DIRTY_MEMORY_VGA 0
+#define DIRTY_MEMORY_CODE 1
+#define DIRTY_MEMORY_MIGRATION 2
+#define DIRTY_MEMORY_NUM 3 /* num of dirty bits */
+
+/* The dirty memory bitmap is split into fixed-size blocks to allow growth
+ * under RCU. The bitmap for a block can be accessed as follows:
+ *
+ * rcu_read_lock();
+ *
+ * DirtyMemoryBlocks *blocks =
+ * atomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]);
+ *
+ * ram_addr_t idx = (addr >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE;
+ * unsigned long *block = blocks.blocks[idx];
+ * ...access block bitmap...
+ *
+ * rcu_read_unlock();
+ *
+ * Remember to check for the end of the block when accessing a range of
+ * addresses. Move on to the next block if you reach the end.
+ *
+ * Organization into blocks allows dirty memory to grow (but not shrink) under
+ * RCU. When adding new RAMBlocks requires the dirty memory to grow, a new
+ * DirtyMemoryBlocks array is allocated with pointers to existing blocks kept
+ * the same. Other threads can safely access existing blocks while dirty
+ * memory is being grown. When no threads are using the old DirtyMemoryBlocks
+ * anymore it is freed by RCU (but the underlying blocks stay because they are
+ * pointed to from the new DirtyMemoryBlocks).
+ */
+#define DIRTY_MEMORY_BLOCK_SIZE ((ram_addr_t)256 * 1024 * 8)
+typedef struct {
+ struct rcu_head rcu;
+ unsigned long *blocks[];
+} DirtyMemoryBlocks;
+
+typedef struct RAMList {
+ QemuMutex mutex;
+ RAMBlock *mru_block;
+ /* RCU-enabled, writes protected by the ramlist lock. */
+ QLIST_HEAD(, RAMBlock) blocks;
+ DirtyMemoryBlocks *dirty_memory[DIRTY_MEMORY_NUM];
+ uint32_t version;
+ QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
+} RAMList;
+extern RAMList ram_list;
+
+void qemu_mutex_lock_ramlist(void);
+void qemu_mutex_unlock_ramlist(void);
+
+struct RAMBlockNotifier {
+ void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size);
+ void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size);
+ QLIST_ENTRY(RAMBlockNotifier) next;
+};
+
+void ram_block_notifier_add(RAMBlockNotifier *n);
+void ram_block_notifier_remove(RAMBlockNotifier *n);
+void ram_block_notify_add(void *host, size_t size);
+void ram_block_notify_remove(void *host, size_t size);
+
+
+#endif /* RAMLIST_H */
diff --git a/include/hw/hw.h b/include/hw/hw.h
index 3669ebd916..e22d4ce5fa 100644
--- a/include/hw/hw.h
+++ b/include/hw/hw.h
@@ -12,11 +12,7 @@
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-
-typedef void QEMUResetHandler(void *opaque);
-
-void qemu_register_reset(QEMUResetHandler *func, void *opaque);
-void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
+#include "sysemu/reset.h"
void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 230e9e70c5..738bfd6c60 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -376,15 +376,14 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_2_8 \
HW_COMPAT_2_8 \
-
-
-#define PC_COMPAT_2_7 \
- HW_COMPAT_2_7 \
{\
.driver = "kvmclock",\
.property = "x-mach-use-reliable-get-clock",\
.value = "off",\
},\
+
+#define PC_COMPAT_2_7 \
+ HW_COMPAT_2_7 \
{\
.driver = TYPE_X86_CPU,\
.property = "l3-cache",\
diff --git a/include/hw/smbios/smbios.h b/include/hw/smbios/smbios.h
index 1cd53cc58c..31e8d5f47e 100644
--- a/include/hw/smbios/smbios.h
+++ b/include/hw/smbios/smbios.h
@@ -257,7 +257,7 @@ struct smbios_type_127 {
struct smbios_structure_header header;
} QEMU_PACKED;
-void smbios_entry_add(QemuOpts *opts);
+void smbios_entry_add(QemuOpts *opts, Error **errp);
void smbios_set_cpuid(uint32_t version, uint32_t features);
void smbios_set_defaults(const char *manufacturer, const char *product,
const char *version, bool legacy_mode,
diff --git a/include/io/dns-resolver.h b/include/io/dns-resolver.h
new file mode 100644
index 0000000000..2f69c08c13
--- /dev/null
+++ b/include/io/dns-resolver.h
@@ -0,0 +1,228 @@
+/*
+ * QEMU DNS resolver
+ *
+ * Copyright (c) 2016-2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QIO_DNS_RESOLVER_H
+#define QIO_DNS_RESOLVER_H
+
+#include "qemu-common.h"
+#include "qom/object.h"
+#include "io/task.h"
+
+#define TYPE_QIO_DNS_RESOLVER "qio-dns-resolver"
+#define QIO_DNS_RESOLVER(obj) \
+ OBJECT_CHECK(QIODNSResolver, (obj), TYPE_QIO_DNS_RESOLVER)
+#define QIO_DNS_RESOLVER_CLASS(klass) \
+ OBJECT_CLASS_CHECK(QIODNSResolverClass, klass, TYPE_QIO_DNS_RESOLVER)
+#define QIO_DNS_RESOLVER_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(QIODNSResolverClass, obj, TYPE_QIO_DNS_RESOLVER)
+
+typedef struct QIODNSResolver QIODNSResolver;
+typedef struct QIODNSResolverClass QIODNSResolverClass;
+
+/**
+ * QIODNSResolver:
+ *
+ * The QIODNSResolver class provides a framework for doing
+ * DNS resolution on SocketAddress objects, independently
+ * of socket creation.
+ *
+ * <example>
+ * <title>Resolving addresses synchronously</title>
+ * <programlisting>
+ * int mylisten(SocketAddress *addr, Error **errp) {
+ * QIODNSResolver *resolver = qio_dns_resolver_get_instance();
+ * SocketAddress **rawaddrs = NULL;
+ * size_t nrawaddrs = 0;
+ * Error *err = NULL;
+ * QIOChannel **socks = NULL;
+ * size_t nsocks = 0;
+ *
+ * if (qio_dns_resolver_lookup_sync(dns, addr, &nrawaddrs,
+ * &rawaddrs, errp) < 0) {
+ * return -1;
+ * }
+ *
+ * for (i = 0; i < nrawaddrs; i++) {
+ * QIOChannel *sock = qio_channel_new();
+ * Error *local_err = NULL;
+ * qio_channel_listen_sync(sock, rawaddrs[i], &local_err);
+ * if (local_err) {
+ * error_propagate(&err, local_err);
+ * } else {
+ * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1);
+ * socks[nsocks++] = sock;
+ * }
+ * qapi_free_SocketAddress(rawaddrs[i]);
+ * }
+ * g_free(rawaddrs);
+ *
+ * if (nsocks == 0) {
+ * error_propagate(errp, err);
+ * } else {
+ * error_free(err);
+ * }
+ * }
+ * </programlisting>
+ * </example>
+ *
+ * <example>
+ * <title>Resolving addresses asynchronously</title>
+ * <programlisting>
+ * typedef struct MyListenData {
+ * Error *err;
+ * QIOChannelSocket **socks;
+ * size_t nsocks;
+ * } MyListenData;
+ *
+ * void mylistenresult(QIOTask *task, void *opaque) {
+ * MyListenData *data = opaque;
+ * QIODNSResolver *resolver =
+ * QIO_DNS_RESOLVER(qio_task_get_source(task);
+ * SocketAddress **rawaddrs = NULL;
+ * size_t nrawaddrs = 0;
+ * Error *err = NULL;
+ *
+ * if (qio_task_propagate_error(task, &data->err)) {
+ * return;
+ * }
+ *
+ * qio_dns_resolver_lookup_result(resolver, task,
+ * &nrawaddrs, &rawaddrs);
+ *
+ * for (i = 0; i < nrawaddrs; i++) {
+ * QIOChannel *sock = qio_channel_new();
+ * Error *local_err = NULL;
+ * qio_channel_listen_sync(sock, rawaddrs[i], &local_err);
+ * if (local_err) {
+ * error_propagate(&err, local_err);
+ * } else {
+ * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1);
+ * socks[nsocks++] = sock;
+ * }
+ * qapi_free_SocketAddress(rawaddrs[i]);
+ * }
+ * g_free(rawaddrs);
+ *
+ * if (nsocks == 0) {
+ * error_propagate(&data->err, err);
+ * } else {
+ * error_free(err);
+ * }
+ * }
+ *
+ * void mylisten(SocketAddress *addr, MyListenData *data) {
+ * QIODNSResolver *resolver = qio_dns_resolver_get_instance();
+ * qio_dns_resolver_lookup_async(dns, addr,
+ * mylistenresult, data, NULL);
+ * }
+ * </programlisting>
+ * </example>
+ */
+struct QIODNSResolver {
+ Object parent;
+};
+
+struct QIODNSResolverClass {
+ ObjectClass parent;
+};
+
+
+/**
+ * qio_dns_resolver_get_instance:
+ *
+ * Get the singleton dns resolver instance. The caller
+ * does not own a reference on the returned object.
+ *
+ * Returns: the single dns resolver instance
+ */
+QIODNSResolver *qio_dns_resolver_get_instance(void);
+
+/**
+ * qio_dns_resolver_lookup_sync:
+ * @resolver: the DNS resolver instance
+ * @addr: the address to resolve
+ * @naddr: pointer to hold number of resolved addresses
+ * @addrs: pointer to hold resolved addresses
+ * @errp: pointer to NULL initialized error object
+ *
+ * This will attempt to resolve the address provided
+ * in @addr. If resolution succeeds, @addrs will be filled
+ * with all the resolved addresses. @naddrs will specify
+ * the number of entries allocated in @addrs. The caller
+ * is responsible for freeing each entry in @addrs, as
+ * well as @addrs itself. @naddrs is guaranteed to be
+ * greater than zero on success.
+ *
+ * DNS resolution will be done synchronously so execution
+ * of the caller may be blocked for an arbitrary length
+ * of time.
+ *
+ * Returns: 0 if resolution was successful, -1 on error
+ */
+int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
+ SocketAddress *addr,
+ size_t *naddrs,
+ SocketAddress ***addrs,
+ Error **errp);
+
+/**
+ * qio_dns_resolver_lookup_async:
+ * @resolver: the DNS resolver instance
+ * @addr: the address to resolve
+ * @func: the callback to invoke on lookup completion
+ * @opaque: data blob to pass to @func
+ * @notify: the callback to free @opaque, or NULL
+ *
+ * This will attempt to resolve the address provided
+ * in @addr. The callback @func will be invoked when
+ * resolution has either completed or failed. On
+ * success, the @func should call the method
+ * qio_dns_resolver_lookup_result() to obtain the
+ * results.
+ *
+ * DNS resolution will be done asynchronously so execution
+ * of the caller will not be blocked.
+ */
+void qio_dns_resolver_lookup_async(QIODNSResolver *resolver,
+ SocketAddress *addr,
+ QIOTaskFunc func,
+ gpointer opaque,
+ GDestroyNotify notify);
+
+/**
+ * qio_dns_resolver_lookup_result:
+ * @resolver: the DNS resolver instance
+ * @task: the task object to get results for
+ * @naddr: pointer to hold number of resolved addresses
+ * @addrs: pointer to hold resolved addresses
+ *
+ * This method should be called from the callback passed
+ * to qio_dns_resolver_lookup_async() in order to obtain
+ * results. @addrs will be filled with all the resolved
+ * addresses. @naddrs will specify the number of entries
+ * allocated in @addrs. The caller is responsible for
+ * freeing each entry in @addrs, as well as @addrs itself.
+ */
+void qio_dns_resolver_lookup_result(QIODNSResolver *resolver,
+ QIOTask *task,
+ size_t *naddrs,
+ SocketAddress ***addrs);
+
+#endif /* QIO_DNS_RESOLVER_H */
diff --git a/include/io/task.h b/include/io/task.h
index 42028cb424..6021f51336 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -26,13 +26,11 @@
typedef struct QIOTask QIOTask;
-typedef void (*QIOTaskFunc)(Object *source,
- Error *err,
+typedef void (*QIOTaskFunc)(QIOTask *task,
gpointer opaque);
-typedef int (*QIOTaskWorker)(QIOTask *task,
- Error **errp,
- gpointer opaque);
+typedef void (*QIOTaskWorker)(QIOTask *task,
+ gpointer opaque);
/**
* QIOTask:
@@ -44,12 +42,12 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
* a public API which accepts a task callback:
*
* <example>
- * <title>Task callback function signature</title>
+ * <title>Task function signature</title>
* <programlisting>
* void myobject_operation(QMyObject *obj,
* QIOTaskFunc *func,
* gpointer opaque,
- * GDestroyNotify *notify);
+ * GDestroyNotify notify);
* </programlisting>
* </example>
*
@@ -57,17 +55,41 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
* is data to pass to it. The optional 'notify' function is used
* to free 'opaque' when no longer needed.
*
- * Now, lets say the implementation of this method wants to set
- * a timer to run once a second checking for completion of some
- * activity. It would do something like
+ * When the operation completes, the 'func' callback will be
+ * invoked, allowing the calling code to determine the result
+ * of the operation. An example QIOTaskFunc implementation may
+ * look like
*
* <example>
- * <title>Task callback function implementation</title>
+ * <title>Task callback implementation</title>
+ * <programlisting>
+ * static void myobject_operation_notify(QIOTask *task,
+ * gpointer opaque)
+ * {
+ * Error *err = NULL;
+ * if (qio_task_propagate_error(task, &err)) {
+ * ...deal with the failure...
+ * error_free(err);
+ * } else {
+ * QMyObject *src = QMY_OBJECT(qio_task_get_source(task));
+ * ...deal with the completion...
+ * }
+ * }
+ * </programlisting>
+ * </example>
+ *
+ * Now, lets say the implementation of the method using the
+ * task wants to set a timer to run once a second checking
+ * for completion of some activity. It would do something
+ * like
+ *
+ * <example>
+ * <title>Task function implementation</title>
* <programlisting>
* void myobject_operation(QMyObject *obj,
* QIOTaskFunc *func,
* gpointer opaque,
- * GDestroyNotify *notify)
+ * GDestroyNotify notify)
* {
* QIOTask *task;
*
@@ -102,8 +124,8 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
*
* ...check something important...
* if (err) {
- * qio_task_abort(task, err);
- * error_free(task);
+ * qio_task_set_error(task, err);
+ * qio_task_complete(task);
* return FALSE;
* } else if (...work is completed ...) {
* qio_task_complete(task);
@@ -115,6 +137,10 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
* </programlisting>
* </example>
*
+ * The 'qio_task_complete' call in this method will trigger
+ * the callback func 'myobject_operation_notify' shown
+ * earlier to deal with the results.
+ *
* Once this function returns false, object_unref will be called
* automatically on the task causing it to be released and the
* ref on QMyObject dropped too.
@@ -136,25 +162,23 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
* socket listen using QIOTask would require:
*
* <example>
- * static int myobject_listen_worker(QIOTask *task,
- * Error **errp,
- * gpointer opaque)
+ * static void myobject_listen_worker(QIOTask *task,
+ * gpointer opaque)
* {
* QMyObject obj = QMY_OBJECT(qio_task_get_source(task));
* SocketAddress *addr = opaque;
+ * Error *err = NULL;
*
- * obj->fd = socket_listen(addr, errp);
- * if (obj->fd < 0) {
- * return -1;
- * }
- * return 0;
+ * obj->fd = socket_listen(addr, &err);
+ *
+ qio_task_set_error(task, err);
* }
*
* void myobject_listen_async(QMyObject *obj,
* SocketAddress *addr,
* QIOTaskFunc *func,
* gpointer opaque,
- * GDestroyNotify *notify)
+ * GDestroyNotify notify)
* {
* QIOTask *task;
* SocketAddress *addrCopy;
@@ -187,8 +211,8 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
* 'err' attribute in the task object to determine if
* the operation was successful or not.
*
- * The returned task will be released when one of
- * qio_task_abort() or qio_task_complete() are invoked.
+ * The returned task will be released when qio_task_complete()
+ * is invoked.
*
* Returns: the task struct
*/
@@ -204,10 +228,8 @@ QIOTask *qio_task_new(Object *source,
* @opaque: opaque data to pass to @worker
* @destroy: function to free @opaque
*
- * Run a task in a background thread. If @worker
- * returns 0 it will call qio_task_complete() in
- * the main event thread context. If @worker
- * returns -1 it will call qio_task_abort() in
+ * Run a task in a background thread. When @worker
+ * returns it will call qio_task_complete() in
* the main event thread context.
*/
void qio_task_run_in_thread(QIOTask *task,
@@ -219,24 +241,69 @@ void qio_task_run_in_thread(QIOTask *task,
* qio_task_complete:
* @task: the task struct
*
- * Mark the operation as successfully completed
- * and free the memory for @task.
+ * Invoke the completion callback for @task and
+ * then free its memory.
*/
void qio_task_complete(QIOTask *task);
+
+/**
+ * qio_task_set_error:
+ * @task: the task struct
+ * @err: pointer to the error, or NULL
+ *
+ * Associate an error with the task, which can later
+ * be retrieved with the qio_task_propagate_error()
+ * method. This method takes ownership of @err, so
+ * it is not valid to access it after this call
+ * completes. If @err is NULL this is a no-op. If
+ * this is call multiple times, only the first
+ * provided @err will be recorded, later ones will
+ * be discarded and freed.
+ */
+void qio_task_set_error(QIOTask *task,
+ Error *err);
+
+
/**
- * qio_task_abort:
+ * qio_task_propagate_error:
* @task: the task struct
- * @err: the error to record for the operation
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Propagate the error associated with @task
+ * into @errp.
+ *
+ * Returns: true if an error was propagated, false otherwise
+ */
+bool qio_task_propagate_error(QIOTask *task,
+ Error **errp);
+
+
+/**
+ * qio_task_set_result_pointer:
+ * @task: the task struct
+ * @result: pointer to the result data
+ *
+ * Associate an opaque result with the task,
+ * which can later be retrieved with the
+ * qio_task_get_result_pointer() method
+ *
+ */
+void qio_task_set_result_pointer(QIOTask *task,
+ gpointer result,
+ GDestroyNotify notify);
+
+
+/**
+ * qio_task_get_result_pointer:
+ * @task: the task struct
+ *
+ * Retrieve the opaque result data associated
+ * with the task, if any.
*
- * Mark the operation as failed, with @err providing
- * details about the failure. The @err may be freed
- * afer the function returns, as the notification
- * callback is invoked synchronously. The @task will
- * be freed when this call completes.
+ * Returns: the task result, or NULL
*/
-void qio_task_abort(QIOTask *task,
- Error *err);
+gpointer qio_task_get_result_pointer(QIOTask *task);
/**
@@ -244,9 +311,10 @@ void qio_task_abort(QIOTask *task,
* @task: the task struct
*
* Get the source object associated with the background
- * task. This returns a new reference to the object,
- * which the caller must released with object_unref()
- * when no longer required.
+ * task. The caller does not own a reference on the
+ * returned Object, and so should call object_ref()
+ * if it wants to keep the object pointer outside the
+ * lifetime of the QIOTask object.
*
* Returns: the source object
*/
diff --git a/include/qemu/event_notifier.h b/include/qemu/event_notifier.h
index e326990db4..599c99f1a5 100644
--- a/include/qemu/event_notifier.h
+++ b/include/qemu/event_notifier.h
@@ -34,9 +34,6 @@ int event_notifier_init(EventNotifier *, int active);
void event_notifier_cleanup(EventNotifier *);
int event_notifier_set(EventNotifier *);
int event_notifier_test_and_clear(EventNotifier *);
-int event_notifier_set_handler(EventNotifier *,
- bool is_external,
- EventNotifierHandler *);
#ifdef CONFIG_POSIX
void event_notifier_init_fd(EventNotifier *, int fd);
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index a9d4f23cd9..d7e24af78d 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -203,6 +203,21 @@ void qemu_set_fd_handler(int fd,
IOHandler *fd_write,
void *opaque);
+
+/**
+ * event_notifier_set_handler: Register an EventNotifier with the main loop
+ *
+ * This function tells the main loop to wake up whenever the
+ * #EventNotifier was set.
+ *
+ * @e: The #EventNotifier to be observed.
+ *
+ * @handler: A level-triggered callback that is fired when @e
+ * has been set. @e is passed to it as a parameter.
+ */
+void event_notifier_set_handler(EventNotifier *e,
+ EventNotifierHandler *handler);
+
GSource *iohandler_get_g_source(void);
AioContext *iohandler_get_aio_context(void);
#ifdef CONFIG_POSIX
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 5589e6842b..5f1bab9b3e 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -32,6 +32,8 @@ int socket_set_fast_reuse(int fd);
*/
typedef void NonBlockingConnectHandler(int fd, Error *err, void *opaque);
+int inet_ai_family_from_address(InetSocketAddress *addr,
+ Error **errp);
InetSocketAddress *inet_parse(const char *str, Error **errp);
int inet_connect(const char *str, Error **errp);
int inet_connect_saddr(InetSocketAddress *saddr, Error **errp,
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 3f79a8e955..ca4d0fb1b4 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -227,6 +227,8 @@ struct CPUWatchpoint {
struct KVMState;
struct kvm_run;
+struct hax_vcpu_state;
+
#define TB_JMP_CACHE_BITS 12
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
@@ -392,6 +394,9 @@ struct CPUState {
(absolute value) offset as small as possible. This reduces code
size, especially for hosts without large memory offsets. */
uint32_t tcg_exit_req;
+
+ bool hax_vcpu_dirty;
+ struct hax_vcpu_state *hax_vcpu;
};
QTAILQ_HEAD(CPUTailQ, CPUState);
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 1c9dad1b72..20b01e3004 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -28,8 +28,6 @@ enum {
extern const uint32_t arch_type;
void select_soundhw(const char *optarg);
-void do_acpitable_option(const QemuOpts *opts);
-void do_smbios_option(QemuOpts *opts);
void audio_init(void);
int kvm_available(void);
int xen_available(void);
diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h
new file mode 100644
index 0000000000..d9f023918e
--- /dev/null
+++ b/include/sysemu/hax.h
@@ -0,0 +1,56 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.com>
+ * Xin Xiaohui<xiaohui.xin@intel.com>
+ * Zhang Xiantao<xiantao.zhang@intel.com>
+ *
+ * Copyright 2016 Google, Inc.
+ *
+ * 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_HAX_H
+#define QEMU_HAX_H
+
+#include "config-host.h"
+#include "qemu-common.h"
+
+int hax_sync_vcpus(void);
+int hax_init_vcpu(CPUState *cpu);
+int hax_smp_cpu_exec(CPUState *cpu);
+int hax_populate_ram(uint64_t va, uint32_t size);
+
+void hax_cpu_synchronize_state(CPUState *cpu);
+void hax_cpu_synchronize_post_reset(CPUState *cpu);
+void hax_cpu_synchronize_post_init(CPUState *cpu);
+
+#ifdef CONFIG_HAX
+
+int hax_enabled(void);
+
+#include "hw/hw.h"
+#include "qemu/bitops.h"
+#include "exec/memory.h"
+int hax_vcpu_destroy(CPUState *cpu);
+void hax_raise_event(CPUState *cpu);
+void hax_reset_vcpu_state(void *opaque);
+#include "target/i386/hax-interface.h"
+#include "target/i386/hax-i386.h"
+
+#else /* CONFIG_HAX */
+
+#define hax_enabled() (0)
+
+#endif /* CONFIG_HAX */
+
+#endif /* QEMU_HAX_H */
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
new file mode 100644
index 0000000000..c9b3105bc7
--- /dev/null
+++ b/include/sysemu/hw_accel.h
@@ -0,0 +1,48 @@
+/*
+ * QEMU Hardware accelertors support
+ *
+ * Copyright 2016 Google, Inc.
+ *
+ * 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_HW_ACCEL_H
+#define QEMU_HW_ACCEL_H
+
+#include "qom/cpu.h"
+#include "sysemu/hax.h"
+#include "sysemu/kvm.h"
+
+static inline void cpu_synchronize_state(CPUState *cpu)
+{
+ if (kvm_enabled()) {
+ kvm_cpu_synchronize_state(cpu);
+ }
+ if (hax_enabled()) {
+ hax_cpu_synchronize_state(cpu);
+ }
+}
+
+static inline void cpu_synchronize_post_reset(CPUState *cpu)
+{
+ if (kvm_enabled()) {
+ kvm_cpu_synchronize_post_reset(cpu);
+ }
+ if (hax_enabled()) {
+ hax_cpu_synchronize_post_reset(cpu);
+ }
+}
+
+static inline void cpu_synchronize_post_init(CPUState *cpu)
+{
+ if (kvm_enabled()) {
+ kvm_cpu_synchronize_post_init(cpu);
+ }
+ if (hax_enabled()) {
+ hax_cpu_synchronize_post_init(cpu);
+ }
+}
+
+#endif /* QEMU_HW_ACCEL_H */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index df67cc0672..3045ee7678 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -461,29 +461,6 @@ void kvm_cpu_synchronize_state(CPUState *cpu);
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
void kvm_cpu_synchronize_post_init(CPUState *cpu);
-/* generic hooks - to be moved/refactored once there are more users */
-
-static inline void cpu_synchronize_state(CPUState *cpu)
-{
- if (kvm_enabled()) {
- kvm_cpu_synchronize_state(cpu);
- }
-}
-
-static inline void cpu_synchronize_post_reset(CPUState *cpu)
-{
- if (kvm_enabled()) {
- kvm_cpu_synchronize_post_reset(cpu);
- }
-}
-
-static inline void cpu_synchronize_post_init(CPUState *cpu)
-{
- if (kvm_enabled()) {
- kvm_cpu_synchronize_post_init(cpu);
- }
-}
-
/**
* kvm_irqchip_add_msi_route - Add MSI route for specific vector
* @s: KVM state
diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h
new file mode 100644
index 0000000000..0b0d6d7598
--- /dev/null
+++ b/include/sysemu/reset.h
@@ -0,0 +1,10 @@
+#ifndef QEMU_SYSEMU_RESET_H
+#define QEMU_SYSEMU_RESET_H
+
+typedef void QEMUResetHandler(void *opaque);
+
+void qemu_register_reset(QEMUResetHandler *func, void *opaque);
+void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
+void qemu_devices_reset(void);
+
+#endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index cccde56454..ff8ffb5e47 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -63,7 +63,6 @@ void qemu_system_vmstop_request_prepare(void);
int qemu_shutdown_requested_get(void);
int qemu_reset_requested_get(void);
void qemu_system_killed(int signal, pid_t pid);
-void qemu_devices_reset(void);
void qemu_system_reset(bool report);
void qemu_system_guest_panicked(void);
size_t qemu_target_page_bits(void);
diff --git a/io/Makefile.objs b/io/Makefile.objs
index 9d8337d89a..12983cca79 100644
--- a/io/Makefile.objs
+++ b/io/Makefile.objs
@@ -7,4 +7,5 @@ io-obj-y += channel-tls.o
io-obj-y += channel-watch.o
io-obj-y += channel-websock.o
io-obj-y += channel-util.o
+io-obj-y += dns-resolver.o
io-obj-y += task.o
diff --git a/io/channel-socket.c b/io/channel-socket.c
index d7e03f6266..f385233f18 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -156,20 +156,16 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
}
-static int qio_channel_socket_connect_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void qio_channel_socket_connect_worker(QIOTask *task,
+ gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
SocketAddress *addr = opaque;
- int ret;
+ Error *err = NULL;
- ret = qio_channel_socket_connect_sync(ioc,
- addr,
- errp);
+ qio_channel_socket_connect_sync(ioc, addr, &err);
- object_unref(OBJECT(ioc));
- return ret;
+ qio_task_set_error(task, err);
}
@@ -219,20 +215,16 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
}
-static int qio_channel_socket_listen_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void qio_channel_socket_listen_worker(QIOTask *task,
+ gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
SocketAddress *addr = opaque;
- int ret;
+ Error *err = NULL;
- ret = qio_channel_socket_listen_sync(ioc,
- addr,
- errp);
+ qio_channel_socket_listen_sync(ioc, addr, &err);
- object_unref(OBJECT(ioc));
- return ret;
+ qio_task_set_error(task, err);
}
@@ -295,22 +287,18 @@ static void qio_channel_socket_dgram_worker_free(gpointer opaque)
g_free(data);
}
-static int qio_channel_socket_dgram_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void qio_channel_socket_dgram_worker(QIOTask *task,
+ gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
struct QIOChannelSocketDGramWorkerData *data = opaque;
- int ret;
+ Error *err = NULL;
/* socket_dgram() blocks in DNS lookups, so we must use a thread */
- ret = qio_channel_socket_dgram_sync(ioc,
- data->localAddr,
- data->remoteAddr,
- errp);
+ qio_channel_socket_dgram_sync(ioc, data->localAddr,
+ data->remoteAddr, &err);
- object_unref(OBJECT(ioc));
- return ret;
+ qio_task_set_error(task, err);
}
diff --git a/io/channel-tls.c b/io/channel-tls.c
index d24dc8c613..f25ab0ae53 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -153,8 +153,9 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
trace_qio_channel_tls_handshake_fail(ioc);
- qio_task_abort(task, err);
- goto cleanup;
+ qio_task_set_error(task, err);
+ qio_task_complete(task);
+ return;
}
status = qcrypto_tls_session_get_handshake_status(ioc->session);
@@ -163,10 +164,10 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
if (qcrypto_tls_session_check_credentials(ioc->session,
&err) < 0) {
trace_qio_channel_tls_credentials_deny(ioc);
- qio_task_abort(task, err);
- goto cleanup;
+ qio_task_set_error(task, err);
+ } else {
+ trace_qio_channel_tls_credentials_allow(ioc);
}
- trace_qio_channel_tls_credentials_allow(ioc);
qio_task_complete(task);
} else {
GIOCondition condition;
@@ -183,9 +184,6 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
task,
NULL);
}
-
- cleanup:
- error_free(err);
}
@@ -200,8 +198,6 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
qio_channel_tls_handshake_task(
tioc, task);
- object_unref(OBJECT(tioc));
-
return FALSE;
}
diff --git a/io/channel-websock.c b/io/channel-websock.c
index f45bced82a..e47279a1ae 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -279,8 +279,8 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
if (ret < 0) {
trace_qio_channel_websock_handshake_fail(ioc);
- qio_task_abort(task, err);
- error_free(err);
+ qio_task_set_error(task, err);
+ qio_task_complete(task);
return FALSE;
}
@@ -307,8 +307,8 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
ret = qio_channel_websock_handshake_read(wioc, &err);
if (ret < 0) {
trace_qio_channel_websock_handshake_fail(ioc);
- qio_task_abort(task, err);
- error_free(err);
+ qio_task_set_error(task, err);
+ qio_task_complete(task);
return FALSE;
}
if (ret == 0) {
diff --git a/io/dns-resolver.c b/io/dns-resolver.c
new file mode 100644
index 0000000000..0ac6b23c02
--- /dev/null
+++ b/io/dns-resolver.c
@@ -0,0 +1,276 @@
+/*
+ * QEMU DNS resolver
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "io/dns-resolver.h"
+#include "qapi/clone-visitor.h"
+#include "qemu/sockets.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+
+#ifndef AI_NUMERICSERV
+# define AI_NUMERICSERV 0
+#endif
+
+static QIODNSResolver *instance;
+static GOnce instance_init = G_ONCE_INIT;
+
+static gpointer qio_dns_resolve_init_instance(gpointer unused G_GNUC_UNUSED)
+{
+ instance = QIO_DNS_RESOLVER(object_new(TYPE_QIO_DNS_RESOLVER));
+ return NULL;
+}
+
+QIODNSResolver *qio_dns_resolver_get_instance(void)
+{
+ g_once(&instance_init, qio_dns_resolve_init_instance, NULL);
+ return instance;
+}
+
+static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
+ SocketAddress *addr,
+ size_t *naddrs,
+ SocketAddress ***addrs,
+ Error **errp)
+{
+ struct addrinfo ai, *res, *e;
+ InetSocketAddress *iaddr = addr->u.inet.data;
+ char port[33];
+ char uaddr[INET6_ADDRSTRLEN + 1];
+ char uport[33];
+ int rc;
+ Error *err = NULL;
+ size_t i;
+
+ *naddrs = 0;
+ *addrs = NULL;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_flags = AI_PASSIVE;
+ if (iaddr->has_numeric && iaddr->numeric) {
+ ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+ }
+ ai.ai_family = inet_ai_family_from_address(iaddr, &err);
+ ai.ai_socktype = SOCK_STREAM;
+
+ if (err) {
+ error_propagate(errp, err);
+ return -1;
+ }
+
+ if (iaddr->host == NULL) {
+ error_setg(errp, "host not specified");
+ return -1;
+ }
+ if (iaddr->port != NULL) {
+ pstrcpy(port, sizeof(port), iaddr->port);
+ } else {
+ port[0] = '\0';
+ }
+
+ rc = getaddrinfo(strlen(iaddr->host) ? iaddr->host : NULL,
+ strlen(port) ? port : NULL, &ai, &res);
+ if (rc != 0) {
+ error_setg(errp, "address resolution failed for %s:%s: %s",
+ iaddr->host, port, gai_strerror(rc));
+ return -1;
+ }
+
+ for (e = res; e != NULL; e = e->ai_next) {
+ (*naddrs)++;
+ }
+
+ *addrs = g_new0(SocketAddress *, *naddrs);
+
+ /* create socket + bind */
+ for (i = 0, e = res; e != NULL; i++, e = e->ai_next) {
+ SocketAddress *newaddr = g_new0(SocketAddress, 1);
+ InetSocketAddress *newiaddr = g_new0(InetSocketAddress, 1);
+ newaddr->u.inet.data = newiaddr;
+ newaddr->type = SOCKET_ADDRESS_KIND_INET;
+
+ getnameinfo((struct sockaddr *)e->ai_addr, e->ai_addrlen,
+ uaddr, INET6_ADDRSTRLEN, uport, 32,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ *newiaddr = (InetSocketAddress){
+ .host = g_strdup(uaddr),
+ .port = g_strdup(uport),
+ .has_numeric = true,
+ .numeric = true,
+ .has_to = iaddr->has_to,
+ .to = iaddr->to,
+ .has_ipv4 = false,
+ .has_ipv6 = false,
+ };
+
+ (*addrs)[i] = newaddr;
+ }
+ freeaddrinfo(res);
+ return 0;
+}
+
+
+static int qio_dns_resolver_lookup_sync_nop(QIODNSResolver *resolver,
+ SocketAddress *addr,
+ size_t *naddrs,
+ SocketAddress ***addrs,
+ Error **errp)
+{
+ *naddrs = 1;
+ *addrs = g_new0(SocketAddress *, 1);
+ (*addrs)[0] = QAPI_CLONE(SocketAddress, addr);
+
+ return 0;
+}
+
+
+int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
+ SocketAddress *addr,
+ size_t *naddrs,
+ SocketAddress ***addrs,
+ Error **errp)
+{
+ switch (addr->type) {
+ case SOCKET_ADDRESS_KIND_INET:
+ return qio_dns_resolver_lookup_sync_inet(resolver,
+ addr,
+ naddrs,
+ addrs,
+ errp);
+
+ case SOCKET_ADDRESS_KIND_UNIX:
+ case SOCKET_ADDRESS_KIND_VSOCK:
+ return qio_dns_resolver_lookup_sync_nop(resolver,
+ addr,
+ naddrs,
+ addrs,
+ errp);
+
+ default:
+ error_setg(errp, "Unknown socket address kind");
+ return -1;
+ }
+}
+
+
+struct QIODNSResolverLookupData {
+ SocketAddress *addr;
+ SocketAddress **addrs;
+ size_t naddrs;
+};
+
+
+static void qio_dns_resolver_lookup_data_free(gpointer opaque)
+{
+ struct QIODNSResolverLookupData *data = opaque;
+ size_t i;
+
+ qapi_free_SocketAddress(data->addr);
+ for (i = 0; i < data->naddrs; i++) {
+ qapi_free_SocketAddress(data->addrs[i]);
+ }
+
+ g_free(data->addrs);
+ g_free(data);
+}
+
+
+static void qio_dns_resolver_lookup_worker(QIOTask *task,
+ gpointer opaque)
+{
+ QIODNSResolver *resolver = QIO_DNS_RESOLVER(qio_task_get_source(task));
+ struct QIODNSResolverLookupData *data = opaque;
+ Error *err = NULL;
+
+ qio_dns_resolver_lookup_sync(resolver,
+ data->addr,
+ &data->naddrs,
+ &data->addrs,
+ &err);
+ if (err) {
+ qio_task_set_error(task, err);
+ } else {
+ qio_task_set_result_pointer(task, opaque, NULL);
+ }
+
+ object_unref(OBJECT(resolver));
+}
+
+
+void qio_dns_resolver_lookup_async(QIODNSResolver *resolver,
+ SocketAddress *addr,
+ QIOTaskFunc func,
+ gpointer opaque,
+ GDestroyNotify notify)
+{
+ QIOTask *task;
+ struct QIODNSResolverLookupData *data =
+ g_new0(struct QIODNSResolverLookupData, 1);
+
+ data->addr = QAPI_CLONE(SocketAddress, addr);
+
+ task = qio_task_new(OBJECT(resolver), func, opaque, notify);
+
+ qio_task_run_in_thread(task,
+ qio_dns_resolver_lookup_worker,
+ data,
+ qio_dns_resolver_lookup_data_free);
+}
+
+
+void qio_dns_resolver_lookup_result(QIODNSResolver *resolver,
+ QIOTask *task,
+ size_t *naddrs,
+ SocketAddress ***addrs)
+{
+ struct QIODNSResolverLookupData *data =
+ qio_task_get_result_pointer(task);
+ size_t i;
+
+ *naddrs = 0;
+ *addrs = NULL;
+ if (!data) {
+ return;
+ }
+
+ *naddrs = data->naddrs;
+ *addrs = g_new0(SocketAddress *, data->naddrs);
+ for (i = 0; i < data->naddrs; i++) {
+ (*addrs)[i] = QAPI_CLONE(SocketAddress, data->addrs[i]);
+ }
+}
+
+
+static const TypeInfo qio_dns_resolver_info = {
+ .parent = TYPE_OBJECT,
+ .name = TYPE_QIO_DNS_RESOLVER,
+ .instance_size = sizeof(QIODNSResolver),
+ .class_size = sizeof(QIODNSResolverClass),
+};
+
+
+static void qio_dns_resolver_register_types(void)
+{
+ type_register_static(&qio_dns_resolver_info);
+}
+
+
+type_init(qio_dns_resolver_register_types);
diff --git a/io/task.c b/io/task.c
index c7f97a9b16..60bf1a94d5 100644
--- a/io/task.c
+++ b/io/task.c
@@ -29,6 +29,9 @@ struct QIOTask {
QIOTaskFunc func;
gpointer opaque;
GDestroyNotify destroy;
+ Error *err;
+ gpointer result;
+ GDestroyNotify destroyResult;
};
@@ -57,6 +60,12 @@ static void qio_task_free(QIOTask *task)
if (task->destroy) {
task->destroy(task->opaque);
}
+ if (task->destroyResult) {
+ task->destroyResult(task->result);
+ }
+ if (task->err) {
+ error_free(task->err);
+ }
object_unref(task->source);
g_free(task);
@@ -68,8 +77,6 @@ struct QIOTaskThreadData {
QIOTaskWorker worker;
gpointer opaque;
GDestroyNotify destroy;
- Error *err;
- int ret;
};
@@ -78,13 +85,8 @@ static gboolean gio_task_thread_result(gpointer opaque)
struct QIOTaskThreadData *data = opaque;
trace_qio_task_thread_result(data->task);
- if (data->ret == 0) {
- qio_task_complete(data->task);
- } else {
- qio_task_abort(data->task, data->err);
- }
+ qio_task_complete(data->task);
- error_free(data->err);
if (data->destroy) {
data->destroy(data->opaque);
}
@@ -100,10 +102,7 @@ static gpointer qio_task_thread_worker(gpointer opaque)
struct QIOTaskThreadData *data = opaque;
trace_qio_task_thread_run(data->task);
- data->ret = data->worker(data->task, &data->err, data->opaque);
- if (data->ret < 0 && data->err == NULL) {
- error_setg(&data->err, "Task worker failed but did not set an error");
- }
+ data->worker(data->task, data->opaque);
/* We're running in the background thread, and must only
* ever report the task results in the main event loop
@@ -140,22 +139,47 @@ void qio_task_run_in_thread(QIOTask *task,
void qio_task_complete(QIOTask *task)
{
- task->func(task->source, NULL, task->opaque);
+ task->func(task, task->opaque);
trace_qio_task_complete(task);
qio_task_free(task);
}
-void qio_task_abort(QIOTask *task,
- Error *err)
+
+void qio_task_set_error(QIOTask *task,
+ Error *err)
{
- task->func(task->source, err, task->opaque);
- trace_qio_task_abort(task);
- qio_task_free(task);
+ error_propagate(&task->err, err);
+}
+
+
+bool qio_task_propagate_error(QIOTask *task,
+ Error **errp)
+{
+ if (task->err) {
+ error_propagate(errp, task->err);
+ return true;
+ }
+
+ return false;
+}
+
+
+void qio_task_set_result_pointer(QIOTask *task,
+ gpointer result,
+ GDestroyNotify destroy)
+{
+ task->result = result;
+ task->destroyResult = destroy;
+}
+
+
+gpointer qio_task_get_result_pointer(QIOTask *task)
+{
+ return task->result;
}
Object *qio_task_get_source(QIOTask *task)
{
- object_ref(task->source);
return task->source;
}
diff --git a/io/trace-events b/io/trace-events
index e31b596ca1..ff993bef45 100644
--- a/io/trace-events
+++ b/io/trace-events
@@ -3,7 +3,6 @@
# io/task.c
qio_task_new(void *task, void *source, void *func, void *opaque) "Task new task=%p source=%p func=%p opaque=%p"
qio_task_complete(void *task) "Task complete task=%p"
-qio_task_abort(void *task) "Task abort task=%p"
qio_task_thread_start(void *task, void *worker, void *opaque) "Task thread start task=%p worker=%p opaque=%p"
qio_task_thread_run(void *task) "Task thread run task=%p"
qio_task_thread_exit(void *task) "Task thread exit task=%p"
diff --git a/iohandler.c b/iohandler.c
index eb625d93dd..623b55b9ec 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -66,6 +66,14 @@ void qemu_set_fd_handler(int fd,
fd_read, fd_write, NULL, opaque);
}
+void event_notifier_set_handler(EventNotifier *e,
+ EventNotifierHandler *handler)
+{
+ iohandler_init();
+ aio_set_event_notifier(iohandler_ctx, e, false,
+ handler, NULL);
+}
+
/* reaping of zombies. right now we're not passing the status to
anyone, but it would be possible to add a callback. */
#ifndef _WIN32
diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 3f3e237142..480dd493a9 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,7 +1,6 @@
common-obj-y += migration.o socket.o fd.o exec.o
common-obj-y += tls.o
-common-obj-y += colo-comm.o
-common-obj-$(CONFIG_COLO) += colo.o colo-failover.o
+common-obj-y += colo-comm.o colo.o colo-failover.o
common-obj-y += vmstate.o
common-obj-y += qemu-file.o
common-obj-y += qemu-file-channel.o
diff --git a/migration/socket.c b/migration/socket.c
index 11f80b119b..13966f1d26 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -70,22 +70,23 @@ static void socket_connect_data_free(void *opaque)
g_free(data);
}
-static void socket_outgoing_migration(Object *src,
- Error *err,
+static void socket_outgoing_migration(QIOTask *task,
gpointer opaque)
{
struct SocketConnectData *data = opaque;
- QIOChannel *sioc = QIO_CHANNEL(src);
+ QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
trace_migration_socket_outgoing_error(error_get_pretty(err));
data->s->to_dst_file = NULL;
migrate_fd_error(data->s, err);
+ error_free(err);
} else {
trace_migration_socket_outgoing_connected(data->hostname);
migration_channel_connect(data->s, sioc, data->hostname);
}
- object_unref(src);
+ object_unref(OBJECT(sioc));
}
static void socket_start_outgoing_migration(MigrationState *s,
diff --git a/migration/tls.c b/migration/tls.c
index 49ca9a8930..203c11d025 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -61,15 +61,15 @@ migration_tls_get_creds(MigrationState *s,
}
-static void migration_tls_incoming_handshake(Object *src,
- Error *err,
+static void migration_tls_incoming_handshake(QIOTask *task,
gpointer opaque)
{
- QIOChannel *ioc = QIO_CHANNEL(src);
+ QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
trace_migration_tls_incoming_handshake_error(error_get_pretty(err));
- error_report("%s", error_get_pretty(err));
+ error_report_err(err);
} else {
trace_migration_tls_incoming_handshake_complete();
migration_channel_process_incoming(migrate_get_current(), ioc);
@@ -107,17 +107,18 @@ void migration_tls_channel_process_incoming(MigrationState *s,
}
-static void migration_tls_outgoing_handshake(Object *src,
- Error *err,
+static void migration_tls_outgoing_handshake(QIOTask *task,
gpointer opaque)
{
MigrationState *s = opaque;
- QIOChannel *ioc = QIO_CHANNEL(src);
+ QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
s->to_dst_file = NULL;
migrate_fd_error(s, err);
+ error_free(err);
} else {
trace_migration_tls_outgoing_handshake_complete();
migration_channel_connect(s, ioc, NULL);
diff --git a/monitor.c b/monitor.c
index 90c5bafcc3..8b06b63729 100644
--- a/monitor.c
+++ b/monitor.c
@@ -50,7 +50,7 @@
#include "sysemu/balloon.h"
#include "qemu/timer.h"
#include "migration/migration.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "qemu/acl.h"
#include "sysemu/tpm.h"
#include "qapi/qmp/qerror.h"
diff --git a/nbd/common.c b/nbd/common.c
index b583a4f4cf..a5f39ea58e 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -78,15 +78,13 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
}
-void nbd_tls_handshake(Object *src,
- Error *err,
+void nbd_tls_handshake(QIOTask *task,
void *opaque)
{
struct NBDTLSHandshakeData *data = opaque;
- if (err) {
- TRACE("TLS failed %s", error_get_pretty(err));
- data->error = error_copy(err);
+ if (qio_task_propagate_error(task, &data->error)) {
+ TRACE("TLS failed %s", error_get_pretty(data->error));
}
data->complete = true;
g_main_loop_quit(data->loop);
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index eee20abc25..f43d990a05 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -120,8 +120,7 @@ struct NBDTLSHandshakeData {
};
-void nbd_tls_handshake(Object *src,
- Error *err,
+void nbd_tls_handshake(QIOTask *task,
void *opaque);
#endif
diff --git a/numa.c b/numa.c
index 379bc8a140..9f56be960f 100644
--- a/numa.c
+++ b/numa.c
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "sysemu/numa.h"
#include "exec/cpu-common.h"
+#include "exec/ramlist.h"
#include "qemu/bitmap.h"
#include "qom/cpu.h"
#include "qemu/error-report.h"
@@ -572,3 +573,31 @@ int numa_get_node_for_cpu(int idx)
}
return i;
}
+
+void ram_block_notifier_add(RAMBlockNotifier *n)
+{
+ QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next);
+}
+
+void ram_block_notifier_remove(RAMBlockNotifier *n)
+{
+ QLIST_REMOVE(n, next);
+}
+
+void ram_block_notify_add(void *host, size_t size)
+{
+ RAMBlockNotifier *notifier;
+
+ QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
+ notifier->ram_block_added(notifier, host, size);
+ }
+}
+
+void ram_block_notify_remove(void *host, size_t size)
+{
+ RAMBlockNotifier *notifier;
+
+ QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
+ notifier->ram_block_removed(notifier, host, size);
+ }
+}
diff --git a/qapi-schema.json b/qapi-schema.json
index ddc878390e..ac55f4a41b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3983,6 +3983,10 @@
#
# @port: port part of the address, or lowest port if @to is present
#
+# @numeric: #optional true if the host/port are guaranteed to be numeric,
+# false if name resolution should be attempted. Defaults to false.
+# (Since 2.9)
+#
# @to: highest port to try
#
# @ipv4: whether to accept IPv4 addresses, default try both IPv4 and IPv6
@@ -3997,6 +4001,7 @@
'data': {
'host': 'str',
'port': 'str',
+ '*numeric': 'bool',
'*to': 'uint16',
'*ipv4': 'bool',
'*ipv6': 'bool' } }
diff --git a/qemu-char.c b/qemu-char.c
index 2c9940cea4..d8da1677ff 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -499,7 +499,7 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
static void remove_fd_in_watch(CharDriverState *chr);
static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
-static void mux_set_focus(MuxDriver *d, int focus);
+static void mux_set_focus(CharDriverState *chr, int focus);
static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
@@ -666,7 +666,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
case 'c':
assert(d->mux_cnt > 0); /* handler registered with first fe */
/* Switch to the next registered device */
- mux_set_focus(d, (d->focus + 1) % d->mux_cnt);
+ mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
break;
case 't':
d->timestamps = !d->timestamps;
@@ -826,8 +826,10 @@ static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
context, true);
}
-static void mux_set_focus(MuxDriver *d, int focus)
+static void mux_set_focus(CharDriverState *chr, int focus)
{
+ MuxDriver *d = chr->opaque;
+
assert(focus >= 0);
assert(focus < d->mux_cnt);
@@ -836,6 +838,7 @@ static void mux_set_focus(MuxDriver *d, int focus)
}
d->focus = focus;
+ chr->be = d->backends[focus];
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
}
@@ -935,7 +938,9 @@ void qemu_chr_fe_deinit(CharBackend *b)
if (b->chr) {
qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
- b->chr->be = NULL;
+ if (b->chr->be == b) {
+ b->chr->be = NULL;
+ }
if (b->chr->is_mux) {
MuxDriver *d = b->chr->opaque;
d->backends[b->tag] = NULL;
@@ -999,7 +1004,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
}
if (b->chr->is_mux) {
- mux_set_focus(b->chr->opaque, b->tag);
+ mux_set_focus(b->chr, b->tag);
}
}
@@ -3272,14 +3277,13 @@ static void tcp_chr_telnet_init(CharDriverState *chr)
}
-static void tcp_chr_tls_handshake(Object *source,
- Error *err,
+static void tcp_chr_tls_handshake(QIOTask *task,
gpointer user_data)
{
CharDriverState *chr = user_data;
TCPCharDriver *s = chr->opaque;
- if (err) {
+ if (qio_task_propagate_error(task, NULL)) {
tcp_chr_disconnect(chr);
} else {
if (s->do_telnetopt) {
@@ -3487,20 +3491,23 @@ static void tcp_chr_free(CharDriverState *chr)
}
-static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
+static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
{
- QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
check_report_connect_error(chr, err);
- object_unref(src);
- return;
+ error_free(err);
+ goto cleanup;
}
s->connect_err_reported = false;
tcp_chr_new_client(chr, sioc);
+
+ cleanup:
object_unref(OBJECT(sioc));
}
diff --git a/qemu-options-wrapper.h b/qemu-options-wrapper.h
index 13bfea0294..4d7aeb1352 100644
--- a/qemu-options-wrapper.h
+++ b/qemu-options-wrapper.h
@@ -14,7 +14,7 @@
#define ARCHHEADING(text, arch_mask) \
if ((arch_mask) & arch_type) \
- puts(stringify(text));
+ puts(stringify(text) ":");
#define DEFHEADING(text) ARCHHEADING(text, QEMU_ARCH_ALL)
diff --git a/qemu-options.hx b/qemu-options.hx
index c534a2f7f9..80df52651a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -6,7 +6,7 @@ HXCOMM construct option structures, enums and help message for specified
HXCOMM architectures.
HXCOMM HXCOMM can be used for comments, discarded from both texi and C
-DEFHEADING(Standard options:)
+DEFHEADING(Standard options)
STEXI
@table @option
ETEXI
@@ -468,7 +468,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(Block device options:)
+DEFHEADING(Block device options)
STEXI
@table @option
ETEXI
@@ -856,7 +856,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(USB options:)
+DEFHEADING(USB options)
STEXI
@table @option
ETEXI
@@ -920,7 +920,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(Display options:)
+DEFHEADING(Display options)
STEXI
@table @option
ETEXI
@@ -1449,7 +1449,7 @@ STEXI
ETEXI
ARCHHEADING(, QEMU_ARCH_I386)
-ARCHHEADING(i386 target only:, QEMU_ARCH_I386)
+ARCHHEADING(i386 target only, QEMU_ARCH_I386)
STEXI
@table @option
ETEXI
@@ -1565,7 +1565,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(Network options:)
+DEFHEADING(Network options)
STEXI
@table @option
ETEXI
@@ -2146,7 +2146,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(Character device options:)
+DEFHEADING(Character device options)
STEXI
The general form of a character device option is:
@@ -2481,7 +2481,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(Device URL Syntax:)
+DEFHEADING(Device URL Syntax)
STEXI
In addition to using normal file images for the emulated storage devices,
@@ -2711,7 +2711,7 @@ STEXI
@end table
ETEXI
-DEFHEADING(Bluetooth(R) options:)
+DEFHEADING(Bluetooth(R) options)
STEXI
@table @option
ETEXI
@@ -2787,7 +2787,7 @@ ETEXI
DEFHEADING()
#ifdef CONFIG_TPM
-DEFHEADING(TPM device options:)
+DEFHEADING(TPM device options)
DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
@@ -2861,7 +2861,7 @@ DEFHEADING()
#endif
-DEFHEADING(Linux/Multiboot boot specific:)
+DEFHEADING(Linux/Multiboot boot specific)
STEXI
When using these options, you can use a given Linux or Multiboot
@@ -2917,7 +2917,7 @@ STEXI
ETEXI
DEFHEADING()
-DEFHEADING(Debug/Expert options:)
+DEFHEADING(Debug/Expert options)
STEXI
@table @option
ETEXI
@@ -3280,6 +3280,17 @@ Enable KVM full virtualization support. This option is only available
if KVM support is enabled when compiling.
ETEXI
+DEF("enable-hax", 0, QEMU_OPTION_enable_hax, \
+ "-enable-hax enable HAX virtualization support\n", QEMU_ARCH_I386)
+STEXI
+@item -enable-hax
+@findex -enable-hax
+Enable HAX (Hardware-based Acceleration eXecution) support. This option
+is only available if HAX support is enabled when compiling. HAX is only
+applicable to MAC and Windows platform, and thus does not conflict with
+KVM.
+ETEXI
+
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
"-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL)
DEF("xen-create", 0, QEMU_OPTION_xen_create,
@@ -3775,7 +3786,14 @@ Dump json-encoded vmstate information for current machine type to file
in @var{file}
ETEXI
+STEXI
+@end table
+ETEXI
+DEFHEADING()
DEFHEADING(Generic object creation)
+STEXI
+@table @option
+ETEXI
DEF("object", HAS_ARG, QEMU_OPTION_object,
"-object TYPENAME[,PROP1=VALUE1,...]\n"
diff --git a/qom/cpu.c b/qom/cpu.c
index cee4e6f7b0..7f575879f6 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -22,7 +22,7 @@
#include "qapi/error.h"
#include "qemu-common.h"
#include "qom/cpu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "qemu/notify.h"
#include "qemu/log.h"
#include "exec/log.h"
diff --git a/qom/object.c b/qom/object.c
index 7a05e35ed9..760fafb0dc 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -272,6 +272,12 @@ static void type_initialize(TypeImpl *ti)
ti->class_size = type_class_get_size(ti);
ti->instance_size = type_object_get_size(ti);
+ /* Any type with zero instance_size is implicitly abstract.
+ * This means interface types are all abstract.
+ */
+ if (ti->instance_size == 0) {
+ ti->abstract = true;
+ }
ti->class = g_malloc0(ti->class_size);
diff --git a/scripts/hxtool b/scripts/hxtool
index 04f7d7b0ed..5468cd7782 100644
--- a/scripts/hxtool
+++ b/scripts/hxtool
@@ -16,6 +16,13 @@ hxtoh()
done
}
+print_texi_heading()
+{
+ if test "$*" != ""; then
+ printf "@subsection %s\n" "$*"
+ fi
+}
+
hxtotexi()
{
flag=0
@@ -45,10 +52,10 @@ hxtotexi()
fi
;;
DEFHEADING*)
- printf '%s\n' "$(expr "$str" : "DEFHEADING(\(.*\))")"
+ print_texi_heading "$(expr "$str" : "DEFHEADING(\(.*\))")"
;;
ARCHHEADING*)
- printf '%s\n' "$(expr "$str" : "ARCHHEADING(\(.*\),.*)")"
+ print_texi_heading "$(expr "$str" : "ARCHHEADING(\(.*\),.*)")"
;;
*)
test $flag -eq 1 && printf '%s\n' "$str"
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 2b5bb74fce..a187295161 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -10,26 +10,18 @@ stub-obj-y += cpu-get-clock.o
stub-obj-y += cpu-get-icount.o
stub-obj-y += dump.o
stub-obj-y += error-printf.o
-stub-obj-y += fdset-add-fd.o
-stub-obj-y += fdset-find-fd.o
-stub-obj-y += fdset-get-fd.o
-stub-obj-y += fdset-remove-fd.o
+stub-obj-y += fdset.o
stub-obj-y += gdbstub.o
-stub-obj-y += get-fd.o
-stub-obj-y += get-next-serial.o
stub-obj-y += get-vm-name.o
stub-obj-y += iothread.o
stub-obj-y += iothread-lock.o
stub-obj-y += is-daemonized.o
stub-obj-y += machine-init-done.o
stub-obj-y += migr-blocker.o
-stub-obj-y += mon-is-qmp.o
-stub-obj-y += monitor-init.o
+stub-obj-y += monitor.o
stub-obj-y += notify-event.o
stub-obj-y += qtest.o
stub-obj-y += replay.o
-stub-obj-y += replay-user.o
-stub-obj-y += reset.o
stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o
stub-obj-y += slirp.o
@@ -39,14 +31,7 @@ stub-obj-y += uuid.o
stub-obj-y += vm-stop.o
stub-obj-y += vmstate.o
stub-obj-$(CONFIG_WIN32) += fd-register.o
-stub-obj-y += cpus.o
-stub-obj-y += kvm.o
stub-obj-y += qmp_pc_dimm_device_list.o
stub-obj-y += target-monitor-defs.o
stub-obj-y += target-get-monitor-def.o
-stub-obj-y += vhost.o
-stub-obj-y += iohandler.o
-stub-obj-y += smbios_type_38.o
-stub-obj-y += ipmi.o
stub-obj-y += pc_madt_cpu_entry.o
-stub-obj-y += migration-colo.o
diff --git a/stubs/cpus.c b/stubs/cpus.c
deleted file mode 100644
index e19272297a..0000000000
--- a/stubs/cpus.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qom/cpu.h"
-
-void cpu_resume(CPUState *cpu)
-{
-}
-
-void qemu_init_vcpu(CPUState *cpu)
-{
-}
diff --git a/stubs/fdset-add-fd.c b/stubs/fdset-add-fd.c
deleted file mode 100644
index bf9e60aed5..0000000000
--- a/stubs/fdset-add-fd.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-
-int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
-{
- return -1;
-}
diff --git a/stubs/fdset-find-fd.c b/stubs/fdset-find-fd.c
deleted file mode 100644
index 1d9caf37ec..0000000000
--- a/stubs/fdset-find-fd.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-
-int monitor_fdset_dup_fd_find(int dup_fd)
-{
- return -1;
-}
diff --git a/stubs/fdset-get-fd.c b/stubs/fdset-get-fd.c
deleted file mode 100644
index 5325044b5a..0000000000
--- a/stubs/fdset-get-fd.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-
-int monitor_fdset_get_fd(int64_t fdset_id, int flags)
-{
- return -1;
-}
diff --git a/stubs/fdset-remove-fd.c b/stubs/fdset-remove-fd.c
deleted file mode 100644
index 47ea297210..0000000000
--- a/stubs/fdset-remove-fd.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-
-void monitor_fdset_dup_fd_remove(int dupfd)
-{
-}
diff --git a/stubs/fdset.c b/stubs/fdset.c
new file mode 100644
index 0000000000..6020cf28c8
--- /dev/null
+++ b/stubs/fdset.c
@@ -0,0 +1,22 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "monitor/monitor.h"
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+ return -1;
+}
+
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+ return -1;
+}
+
+void monitor_fdset_dup_fd_remove(int dupfd)
+{
+}
diff --git a/stubs/get-next-serial.c b/stubs/get-next-serial.c
deleted file mode 100644
index 6ff6a6d3b2..0000000000
--- a/stubs/get-next-serial.c
+++ /dev/null
@@ -1,4 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-
-CharDriverState *serial_hds[0];
diff --git a/stubs/iohandler.c b/stubs/iohandler.c
deleted file mode 100644
index 22b0ee5b0a..0000000000
--- a/stubs/iohandler.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/main-loop.h"
-
-AioContext *iohandler_get_aio_context(void)
-{
- abort();
-}
diff --git a/stubs/kvm.c b/stubs/kvm.c
deleted file mode 100644
index ddd620499d..0000000000
--- a/stubs/kvm.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/kvm.h"
-
-int kvm_arch_irqchip_create(MachineState *ms, KVMState *s)
-{
- return 0;
-}
diff --git a/stubs/migration-colo.c b/stubs/migration-colo.c
deleted file mode 100644
index 7811764c4b..0000000000
--- a/stubs/migration-colo.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO)
- * (a.k.a. Fault Tolerance or Continuous Replication)
- *
- * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
- * Copyright (c) 2016 FUJITSU LIMITED
- * Copyright (c) 2016 Intel Corporation
- *
- * 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 "migration/colo.h"
-#include "qmp-commands.h"
-
-bool colo_supported(void)
-{
- return false;
-}
-
-bool migration_in_colo_state(void)
-{
- return false;
-}
-
-bool migration_incoming_in_colo_state(void)
-{
- return false;
-}
-
-void migrate_start_colo_process(MigrationState *s)
-{
-}
-
-void *colo_process_incoming_thread(void *opaque)
-{
- return NULL;
-}
-
-void qmp_x_colo_lost_heartbeat(Error **errp)
-{
- error_setg(errp, "COLO is not supported, please rerun configure"
- " with --enable-colo option in order to support"
- " COLO feature");
-}
diff --git a/stubs/mon-is-qmp.c b/stubs/mon-is-qmp.c
deleted file mode 100644
index a8344ced80..0000000000
--- a/stubs/mon-is-qmp.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-
-Monitor *cur_mon;
-
-bool monitor_cur_is_qmp(void)
-{
- return false;
-}
diff --git a/stubs/monitor-init.c b/stubs/monitor-init.c
deleted file mode 100644
index de1bc7cd54..0000000000
--- a/stubs/monitor-init.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-
-void monitor_init(CharDriverState *chr, int flags)
-{
-}
diff --git a/stubs/get-fd.c b/stubs/monitor.c
index 7dfdfb55f7..1d574b1c6f 100644
--- a/stubs/get-fd.c
+++ b/stubs/monitor.c
@@ -3,8 +3,14 @@
#include "qemu-common.h"
#include "monitor/monitor.h"
+Monitor *cur_mon = NULL;
+
int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
{
error_setg(errp, "only QEMU supports file descriptor passing");
return -1;
}
+
+void monitor_init(CharDriverState *chr, int flags)
+{
+}
diff --git a/stubs/replay-user.c b/stubs/replay-user.c
deleted file mode 100644
index b29e7ebba1..0000000000
--- a/stubs/replay-user.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * replay.c
- *
- * Copyright (c) 2010-2015 Institute for System Programming
- * of the Russian Academy of Sciences.
- *
- * 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 "sysemu/replay.h"
-
-bool replay_exception(void)
-{
- return true;
-}
-
-bool replay_has_exception(void)
-{
- return false;
-}
-
-bool replay_interrupt(void)
-{
- return true;
-}
-
-bool replay_has_interrupt(void)
-{
- return false;
-}
diff --git a/stubs/reset.c b/stubs/reset.c
deleted file mode 100644
index 5d47711f9a..0000000000
--- a/stubs/reset.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-
-/* Stub functions for binaries that never call qemu_devices_reset(),
- * and don't need to keep track of the reset handler list.
- */
-
-void qemu_register_reset(QEMUResetHandler *func, void *opaque)
-{
-}
-
-void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
-{
-}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 3f2cdb65bf..a941f6611b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -31,7 +31,7 @@
#endif
#include "hw/arm/arm.h"
#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "kvm_arm.h"
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs
index b223d7932b..4fcb7f3df0 100644
--- a/target/i386/Makefile.objs
+++ b/target/i386/Makefile.objs
@@ -5,3 +5,10 @@ obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
+# HAX support
+ifdef CONFIG_WIN32
+obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-windows.o
+endif
+ifdef CONFIG_DARWIN
+obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-darwin.o
+endif
diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c
new file mode 100644
index 0000000000..ef13015215
--- /dev/null
+++ b/target/i386/hax-all.c
@@ -0,0 +1,1155 @@
+/*
+ * QEMU HAX support
+ *
+ * Copyright IBM, Corp. 2008
+ * Red Hat, Inc. 2008
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Glauber Costa <gcosta@redhat.com>
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.com>
+ * Xin Xiaohui<xiaohui.xin@intel.com>
+ * Zhang Xiantao<xiantao.zhang@intel.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.
+ *
+ */
+
+/*
+ * HAX common code for both windows and darwin
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/address-spaces.h"
+#include "exec/exec-all.h"
+#include "exec/ioport.h"
+
+#include "qemu-common.h"
+#include "strings.h"
+#include "hax-i386.h"
+#include "sysemu/accel.h"
+#include "sysemu/sysemu.h"
+#include "qemu/main-loop.h"
+#include "hw/boards.h"
+
+#define DEBUG_HAX 0
+
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_HAX) { \
+ fprintf(stdout, fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+/* Current version */
+const uint32_t hax_cur_version = 0x4; /* API v4: unmapping and MMIO moves */
+/* Minimum HAX kernel version */
+const uint32_t hax_min_version = 0x4; /* API v4: supports unmapping */
+
+static bool hax_allowed;
+
+struct hax_state hax_global;
+
+static void hax_vcpu_sync_state(CPUArchState *env, int modified);
+static int hax_arch_get_registers(CPUArchState *env);
+
+int hax_enabled(void)
+{
+ return hax_allowed;
+}
+
+int valid_hax_tunnel_size(uint16_t size)
+{
+ return size >= sizeof(struct hax_tunnel);
+}
+
+hax_fd hax_vcpu_get_fd(CPUArchState *env)
+{
+ struct hax_vcpu_state *vcpu = ENV_GET_CPU(env)->hax_vcpu;
+ if (!vcpu) {
+ return HAX_INVALID_FD;
+ }
+ return vcpu->fd;
+}
+
+static int hax_get_capability(struct hax_state *hax)
+{
+ int ret;
+ struct hax_capabilityinfo capinfo, *cap = &capinfo;
+
+ ret = hax_capability(hax, cap);
+ if (ret) {
+ return ret;
+ }
+
+ if ((cap->wstatus & HAX_CAP_WORKSTATUS_MASK) == HAX_CAP_STATUS_NOTWORKING) {
+ if (cap->winfo & HAX_CAP_FAILREASON_VT) {
+ DPRINTF
+ ("VTX feature is not enabled, HAX driver will not work.\n");
+ } else if (cap->winfo & HAX_CAP_FAILREASON_NX) {
+ DPRINTF
+ ("NX feature is not enabled, HAX driver will not work.\n");
+ }
+ return -ENXIO;
+
+ }
+
+ if (!(cap->winfo & HAX_CAP_UG)) {
+ fprintf(stderr, "UG mode is not supported by the hardware.\n");
+ return -ENOTSUP;
+ }
+
+ if (cap->wstatus & HAX_CAP_MEMQUOTA) {
+ if (cap->mem_quota < hax->mem_quota) {
+ fprintf(stderr, "The VM memory needed exceeds the driver limit.\n");
+ return -ENOSPC;
+ }
+ }
+ return 0;
+}
+
+static int hax_version_support(struct hax_state *hax)
+{
+ int ret;
+ struct hax_module_version version;
+
+ ret = hax_mod_version(hax, &version);
+ if (ret < 0) {
+ return 0;
+ }
+
+ if (hax_min_version > version.cur_version) {
+ fprintf(stderr, "Incompatible HAX module version %d,",
+ version.cur_version);
+ fprintf(stderr, "requires minimum version %d\n", hax_min_version);
+ return 0;
+ }
+ if (hax_cur_version < version.compat_version) {
+ fprintf(stderr, "Incompatible QEMU HAX API version %x,",
+ hax_cur_version);
+ fprintf(stderr, "requires minimum HAX API version %x\n",
+ version.compat_version);
+ return 0;
+ }
+
+ return 1;
+}
+
+int hax_vcpu_create(int id)
+{
+ struct hax_vcpu_state *vcpu = NULL;
+ int ret;
+
+ if (!hax_global.vm) {
+ fprintf(stderr, "vcpu %x created failed, vm is null\n", id);
+ return -1;
+ }
+
+ if (hax_global.vm->vcpus[id]) {
+ fprintf(stderr, "vcpu %x allocated already\n", id);
+ return 0;
+ }
+
+ vcpu = g_malloc(sizeof(struct hax_vcpu_state));
+ if (!vcpu) {
+ fprintf(stderr, "Failed to alloc vcpu state\n");
+ return -ENOMEM;
+ }
+
+ memset(vcpu, 0, sizeof(struct hax_vcpu_state));
+
+ ret = hax_host_create_vcpu(hax_global.vm->fd, id);
+ if (ret) {
+ fprintf(stderr, "Failed to create vcpu %x\n", id);
+ goto error;
+ }
+
+ vcpu->vcpu_id = id;
+ vcpu->fd = hax_host_open_vcpu(hax_global.vm->id, id);
+ if (hax_invalid_fd(vcpu->fd)) {
+ fprintf(stderr, "Failed to open the vcpu\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ hax_global.vm->vcpus[id] = vcpu;
+
+ ret = hax_host_setup_vcpu_channel(vcpu);
+ if (ret) {
+ fprintf(stderr, "Invalid hax tunnel size\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ return 0;
+
+ error:
+ /* vcpu and tunnel will be closed automatically */
+ if (vcpu && !hax_invalid_fd(vcpu->fd)) {
+ hax_close_fd(vcpu->fd);
+ }
+
+ hax_global.vm->vcpus[id] = NULL;
+ g_free(vcpu);
+ return -1;
+}
+
+int hax_vcpu_destroy(CPUState *cpu)
+{
+ struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+
+ if (!hax_global.vm) {
+ fprintf(stderr, "vcpu %x destroy failed, vm is null\n", vcpu->vcpu_id);
+ return -1;
+ }
+
+ if (!vcpu) {
+ return 0;
+ }
+
+ /*
+ * 1. The hax_tunnel is also destroied when vcpu destroy
+ * 2. close fd will cause hax module vcpu be cleaned
+ */
+ hax_close_fd(vcpu->fd);
+ hax_global.vm->vcpus[vcpu->vcpu_id] = NULL;
+ g_free(vcpu);
+ return 0;
+}
+
+int hax_init_vcpu(CPUState *cpu)
+{
+ int ret;
+
+ ret = hax_vcpu_create(cpu->cpu_index);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to create HAX vcpu\n");
+ exit(-1);
+ }
+
+ cpu->hax_vcpu = hax_global.vm->vcpus[cpu->cpu_index];
+ cpu->hax_vcpu_dirty = true;
+ qemu_register_reset(hax_reset_vcpu_state, (CPUArchState *) (cpu->env_ptr));
+
+ return ret;
+}
+
+struct hax_vm *hax_vm_create(struct hax_state *hax)
+{
+ struct hax_vm *vm;
+ int vm_id = 0, ret;
+
+ if (hax_invalid_fd(hax->fd)) {
+ return NULL;
+ }
+
+ if (hax->vm) {
+ return hax->vm;
+ }
+
+ vm = g_malloc(sizeof(struct hax_vm));
+ if (!vm) {
+ return NULL;
+ }
+ memset(vm, 0, sizeof(struct hax_vm));
+ ret = hax_host_create_vm(hax, &vm_id);
+ if (ret) {
+ fprintf(stderr, "Failed to create vm %x\n", ret);
+ goto error;
+ }
+ vm->id = vm_id;
+ vm->fd = hax_host_open_vm(hax, vm_id);
+ if (hax_invalid_fd(vm->fd)) {
+ fprintf(stderr, "Failed to open vm %d\n", vm_id);
+ goto error;
+ }
+
+ hax->vm = vm;
+ return vm;
+
+ error:
+ g_free(vm);
+ hax->vm = NULL;
+ return NULL;
+}
+
+int hax_vm_destroy(struct hax_vm *vm)
+{
+ int i;
+
+ for (i = 0; i < HAX_MAX_VCPU; i++)
+ if (vm->vcpus[i]) {
+ fprintf(stderr, "VCPU should be cleaned before vm clean\n");
+ return -1;
+ }
+ hax_close_fd(vm->fd);
+ g_free(vm);
+ hax_global.vm = NULL;
+ return 0;
+}
+
+static void hax_handle_interrupt(CPUState *cpu, int mask)
+{
+ cpu->interrupt_request |= mask;
+
+ if (!qemu_cpu_is_self(cpu)) {
+ qemu_cpu_kick(cpu);
+ }
+}
+
+static int hax_init(ram_addr_t ram_size)
+{
+ struct hax_state *hax = NULL;
+ struct hax_qemu_version qversion;
+ int ret;
+
+ hax = &hax_global;
+
+ memset(hax, 0, sizeof(struct hax_state));
+ hax->mem_quota = ram_size;
+
+ hax->fd = hax_mod_open();
+ if (hax_invalid_fd(hax->fd)) {
+ hax->fd = 0;
+ ret = -ENODEV;
+ goto error;
+ }
+
+ ret = hax_get_capability(hax);
+
+ if (ret) {
+ if (ret != -ENOSPC) {
+ ret = -EINVAL;
+ }
+ goto error;
+ }
+
+ if (!hax_version_support(hax)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ hax->vm = hax_vm_create(hax);
+ if (!hax->vm) {
+ fprintf(stderr, "Failed to create HAX VM\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ hax_memory_init();
+
+ qversion.cur_version = hax_cur_version;
+ qversion.min_version = hax_min_version;
+ hax_notify_qemu_version(hax->vm->fd, &qversion);
+ cpu_interrupt_handler = hax_handle_interrupt;
+
+ return ret;
+ error:
+ if (hax->vm) {
+ hax_vm_destroy(hax->vm);
+ }
+ if (hax->fd) {
+ hax_mod_close(hax);
+ }
+
+ return ret;
+}
+
+static int hax_accel_init(MachineState *ms)
+{
+ int ret = hax_init(ms->ram_size);
+
+ if (ret && (ret != -ENOSPC)) {
+ fprintf(stderr, "No accelerator found.\n");
+ } else {
+ fprintf(stdout, "HAX is %s and emulator runs in %s mode.\n",
+ !ret ? "working" : "not working",
+ !ret ? "fast virt" : "emulation");
+ }
+ return ret;
+}
+
+static int hax_handle_fastmmio(CPUArchState *env, struct hax_fastmmio *hft)
+{
+ if (hft->direction < 2) {
+ cpu_physical_memory_rw(hft->gpa, (uint8_t *) &hft->value, hft->size,
+ hft->direction);
+ } else {
+ /*
+ * HAX API v4 supports transferring data between two MMIO addresses,
+ * hft->gpa and hft->gpa2 (instructions such as MOVS require this):
+ * hft->direction == 2: gpa ==> gpa2
+ */
+ uint64_t value;
+ cpu_physical_memory_rw(hft->gpa, (uint8_t *) &value, hft->size, 0);
+ cpu_physical_memory_rw(hft->gpa2, (uint8_t *) &value, hft->size, 1);
+ }
+
+ return 0;
+}
+
+static int hax_handle_io(CPUArchState *env, uint32_t df, uint16_t port,
+ int direction, int size, int count, void *buffer)
+{
+ uint8_t *ptr;
+ int i;
+ MemTxAttrs attrs = { 0 };
+
+ if (!df) {
+ ptr = (uint8_t *) buffer;
+ } else {
+ ptr = buffer + size * count - size;
+ }
+ for (i = 0; i < count; i++) {
+ address_space_rw(&address_space_io, port, attrs,
+ ptr, size, direction == HAX_EXIT_IO_OUT);
+ if (!df) {
+ ptr += size;
+ } else {
+ ptr -= size;
+ }
+ }
+
+ return 0;
+}
+
+static int hax_vcpu_interrupt(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+ struct hax_tunnel *ht = vcpu->tunnel;
+
+ /*
+ * Try to inject an interrupt if the guest can accept it
+ * Unlike KVM, HAX kernel check for the eflags, instead of qemu
+ */
+ if (ht->ready_for_interrupt_injection &&
+ (cpu->interrupt_request & CPU_INTERRUPT_HARD)) {
+ int irq;
+
+ irq = cpu_get_pic_interrupt(env);
+ if (irq >= 0) {
+ hax_inject_interrupt(env, irq);
+ cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ }
+ }
+
+ /* If we have an interrupt but the guest is not ready to receive an
+ * interrupt, request an interrupt window exit. This will
+ * cause a return to userspace as soon as the guest is ready to
+ * receive interrupts. */
+ if ((cpu->interrupt_request & CPU_INTERRUPT_HARD)) {
+ ht->request_interrupt_window = 1;
+ } else {
+ ht->request_interrupt_window = 0;
+ }
+ return 0;
+}
+
+void hax_raise_event(CPUState *cpu)
+{
+ struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+
+ if (!vcpu) {
+ return;
+ }
+ vcpu->tunnel->user_event_pending = 1;
+}
+
+/*
+ * Ask hax kernel module to run the CPU for us till:
+ * 1. Guest crash or shutdown
+ * 2. Need QEMU's emulation like guest execute MMIO instruction
+ * 3. Guest execute HLT
+ * 4. QEMU have Signal/event pending
+ * 5. An unknown VMX exit happens
+ */
+static int hax_vcpu_hax_exec(CPUArchState *env)
+{
+ int ret = 0;
+ CPUState *cpu = ENV_GET_CPU(env);
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+ struct hax_tunnel *ht = vcpu->tunnel;
+
+ if (!hax_enabled()) {
+ DPRINTF("Trying to vcpu execute at eip:" TARGET_FMT_lx "\n", env->eip);
+ return 0;
+ }
+
+ cpu->halted = 0;
+
+ if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
+ cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
+ apic_poll_irq(x86_cpu->apic_state);
+ }
+
+ if (cpu->interrupt_request & CPU_INTERRUPT_INIT) {
+ DPRINTF("\nhax_vcpu_hax_exec: handling INIT for %d\n",
+ cpu->cpu_index);
+ do_cpu_init(x86_cpu);
+ hax_vcpu_sync_state(env, 1);
+ }
+
+ if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) {
+ DPRINTF("hax_vcpu_hax_exec: handling SIPI for %d\n",
+ cpu->cpu_index);
+ hax_vcpu_sync_state(env, 0);
+ do_cpu_sipi(x86_cpu);
+ hax_vcpu_sync_state(env, 1);
+ }
+
+ do {
+ int hax_ret;
+
+ if (cpu->exit_request) {
+ ret = 1;
+ break;
+ }
+
+ hax_vcpu_interrupt(env);
+
+ qemu_mutex_unlock_iothread();
+ hax_ret = hax_vcpu_run(vcpu);
+ qemu_mutex_lock_iothread();
+ current_cpu = cpu;
+
+ /* Simply continue the vcpu_run if system call interrupted */
+ if (hax_ret == -EINTR || hax_ret == -EAGAIN) {
+ DPRINTF("io window interrupted\n");
+ continue;
+ }
+
+ if (hax_ret < 0) {
+ fprintf(stderr, "vcpu run failed for vcpu %x\n", vcpu->vcpu_id);
+ abort();
+ }
+ switch (ht->_exit_status) {
+ case HAX_EXIT_IO:
+ ret = hax_handle_io(env, ht->pio._df, ht->pio._port,
+ ht->pio._direction,
+ ht->pio._size, ht->pio._count, vcpu->iobuf);
+ break;
+ case HAX_EXIT_FAST_MMIO:
+ ret = hax_handle_fastmmio(env, (struct hax_fastmmio *) vcpu->iobuf);
+ break;
+ /* Guest state changed, currently only for shutdown */
+ case HAX_EXIT_STATECHANGE:
+ fprintf(stdout, "VCPU shutdown request\n");
+ qemu_system_shutdown_request();
+ hax_vcpu_sync_state(env, 0);
+ ret = 1;
+ break;
+ case HAX_EXIT_UNKNOWN_VMEXIT:
+ fprintf(stderr, "Unknown VMX exit %x from guest\n",
+ ht->_exit_reason);
+ qemu_system_reset_request();
+ hax_vcpu_sync_state(env, 0);
+ cpu_dump_state(cpu, stderr, fprintf, 0);
+ ret = -1;
+ break;
+ case HAX_EXIT_HLT:
+ if (!(cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
+ !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
+ /* hlt instruction with interrupt disabled is shutdown */
+ env->eflags |= IF_MASK;
+ cpu->halted = 1;
+ cpu->exception_index = EXCP_HLT;
+ ret = 1;
+ }
+ break;
+ /* these situations will continue to hax module */
+ case HAX_EXIT_INTERRUPT:
+ case HAX_EXIT_PAUSED:
+ break;
+ case HAX_EXIT_MMIO:
+ /* Should not happen on UG system */
+ fprintf(stderr, "HAX: unsupported MMIO emulation\n");
+ ret = -1;
+ break;
+ case HAX_EXIT_REAL:
+ /* Should not happen on UG system */
+ fprintf(stderr, "HAX: unimplemented real mode emulation\n");
+ ret = -1;
+ break;
+ default:
+ fprintf(stderr, "Unknown exit %x from HAX\n", ht->_exit_status);
+ qemu_system_reset_request();
+ hax_vcpu_sync_state(env, 0);
+ cpu_dump_state(cpu, stderr, fprintf, 0);
+ ret = 1;
+ break;
+ }
+ } while (!ret);
+
+ if (cpu->exit_request) {
+ cpu->exit_request = 0;
+ cpu->exception_index = EXCP_INTERRUPT;
+ }
+ return ret < 0;
+}
+
+static void do_hax_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
+{
+ CPUArchState *env = cpu->env_ptr;
+
+ hax_arch_get_registers(env);
+ cpu->hax_vcpu_dirty = true;
+}
+
+void hax_cpu_synchronize_state(CPUState *cpu)
+{
+ if (!cpu->hax_vcpu_dirty) {
+ run_on_cpu(cpu, do_hax_cpu_synchronize_state, RUN_ON_CPU_NULL);
+ }
+}
+
+static void do_hax_cpu_synchronize_post_reset(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ CPUArchState *env = cpu->env_ptr;
+
+ hax_vcpu_sync_state(env, 1);
+ cpu->hax_vcpu_dirty = false;
+}
+
+void hax_cpu_synchronize_post_reset(CPUState *cpu)
+{
+ run_on_cpu(cpu, do_hax_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
+}
+
+static void do_hax_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
+{
+ CPUArchState *env = cpu->env_ptr;
+
+ hax_vcpu_sync_state(env, 1);
+ cpu->hax_vcpu_dirty = false;
+}
+
+void hax_cpu_synchronize_post_init(CPUState *cpu)
+{
+ run_on_cpu(cpu, do_hax_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
+}
+
+int hax_smp_cpu_exec(CPUState *cpu)
+{
+ CPUArchState *env = (CPUArchState *) (cpu->env_ptr);
+ int fatal;
+ int ret;
+
+ while (1) {
+ if (cpu->exception_index >= EXCP_INTERRUPT) {
+ ret = cpu->exception_index;
+ cpu->exception_index = -1;
+ break;
+ }
+
+ fatal = hax_vcpu_hax_exec(env);
+
+ if (fatal) {
+ fprintf(stderr, "Unsupported HAX vcpu return\n");
+ abort();
+ }
+ }
+
+ return ret;
+}
+
+static void set_v8086_seg(struct segment_desc_t *lhs, const SegmentCache *rhs)
+{
+ memset(lhs, 0, sizeof(struct segment_desc_t));
+ lhs->selector = rhs->selector;
+ lhs->base = rhs->base;
+ lhs->limit = rhs->limit;
+ lhs->type = 3;
+ lhs->present = 1;
+ lhs->dpl = 3;
+ lhs->operand_size = 0;
+ lhs->desc = 1;
+ lhs->long_mode = 0;
+ lhs->granularity = 0;
+ lhs->available = 0;
+}
+
+static void get_seg(SegmentCache *lhs, const struct segment_desc_t *rhs)
+{
+ lhs->selector = rhs->selector;
+ lhs->base = rhs->base;
+ lhs->limit = rhs->limit;
+ lhs->flags = (rhs->type << DESC_TYPE_SHIFT)
+ | (rhs->present * DESC_P_MASK)
+ | (rhs->dpl << DESC_DPL_SHIFT)
+ | (rhs->operand_size << DESC_B_SHIFT)
+ | (rhs->desc * DESC_S_MASK)
+ | (rhs->long_mode << DESC_L_SHIFT)
+ | (rhs->granularity * DESC_G_MASK) | (rhs->available * DESC_AVL_MASK);
+}
+
+static void set_seg(struct segment_desc_t *lhs, const SegmentCache *rhs)
+{
+ unsigned flags = rhs->flags;
+
+ memset(lhs, 0, sizeof(struct segment_desc_t));
+ lhs->selector = rhs->selector;
+ lhs->base = rhs->base;
+ lhs->limit = rhs->limit;
+ lhs->type = (flags >> DESC_TYPE_SHIFT) & 15;
+ lhs->present = (flags & DESC_P_MASK) != 0;
+ lhs->dpl = rhs->selector & 3;
+ lhs->operand_size = (flags >> DESC_B_SHIFT) & 1;
+ lhs->desc = (flags & DESC_S_MASK) != 0;
+ lhs->long_mode = (flags >> DESC_L_SHIFT) & 1;
+ lhs->granularity = (flags & DESC_G_MASK) != 0;
+ lhs->available = (flags & DESC_AVL_MASK) != 0;
+}
+
+static void hax_getput_reg(uint64_t *hax_reg, target_ulong *qemu_reg, int set)
+{
+ target_ulong reg = *hax_reg;
+
+ if (set) {
+ *hax_reg = *qemu_reg;
+ } else {
+ *qemu_reg = reg;
+ }
+}
+
+/* The sregs has been synced with HAX kernel already before this call */
+static int hax_get_segments(CPUArchState *env, struct vcpu_state_t *sregs)
+{
+ get_seg(&env->segs[R_CS], &sregs->_cs);
+ get_seg(&env->segs[R_DS], &sregs->_ds);
+ get_seg(&env->segs[R_ES], &sregs->_es);
+ get_seg(&env->segs[R_FS], &sregs->_fs);
+ get_seg(&env->segs[R_GS], &sregs->_gs);
+ get_seg(&env->segs[R_SS], &sregs->_ss);
+
+ get_seg(&env->tr, &sregs->_tr);
+ get_seg(&env->ldt, &sregs->_ldt);
+ env->idt.limit = sregs->_idt.limit;
+ env->idt.base = sregs->_idt.base;
+ env->gdt.limit = sregs->_gdt.limit;
+ env->gdt.base = sregs->_gdt.base;
+ return 0;
+}
+
+static int hax_set_segments(CPUArchState *env, struct vcpu_state_t *sregs)
+{
+ if ((env->eflags & VM_MASK)) {
+ set_v8086_seg(&sregs->_cs, &env->segs[R_CS]);
+ set_v8086_seg(&sregs->_ds, &env->segs[R_DS]);
+ set_v8086_seg(&sregs->_es, &env->segs[R_ES]);
+ set_v8086_seg(&sregs->_fs, &env->segs[R_FS]);
+ set_v8086_seg(&sregs->_gs, &env->segs[R_GS]);
+ set_v8086_seg(&sregs->_ss, &env->segs[R_SS]);
+ } else {
+ set_seg(&sregs->_cs, &env->segs[R_CS]);
+ set_seg(&sregs->_ds, &env->segs[R_DS]);
+ set_seg(&sregs->_es, &env->segs[R_ES]);
+ set_seg(&sregs->_fs, &env->segs[R_FS]);
+ set_seg(&sregs->_gs, &env->segs[R_GS]);
+ set_seg(&sregs->_ss, &env->segs[R_SS]);
+
+ if (env->cr[0] & CR0_PE_MASK) {
+ /* force ss cpl to cs cpl */
+ sregs->_ss.selector = (sregs->_ss.selector & ~3) |
+ (sregs->_cs.selector & 3);
+ sregs->_ss.dpl = sregs->_ss.selector & 3;
+ }
+ }
+
+ set_seg(&sregs->_tr, &env->tr);
+ set_seg(&sregs->_ldt, &env->ldt);
+ sregs->_idt.limit = env->idt.limit;
+ sregs->_idt.base = env->idt.base;
+ sregs->_gdt.limit = env->gdt.limit;
+ sregs->_gdt.base = env->gdt.base;
+ return 0;
+}
+
+/*
+ * After get the state from the kernel module, some
+ * qemu emulator state need be updated also
+ */
+static int hax_setup_qemu_emulator(CPUArchState *env)
+{
+
+#define HFLAG_COPY_MASK (~( \
+ HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \
+ HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \
+ HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
+ HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK))
+
+ uint32_t hflags;
+
+ hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+ hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
+ hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
+ (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
+ hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
+ hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
+ (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
+
+ if (env->efer & MSR_EFER_LMA) {
+ hflags |= HF_LMA_MASK;
+ }
+
+ if ((hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) {
+ hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
+ } else {
+ hflags |= (env->segs[R_CS].flags & DESC_B_MASK) >>
+ (DESC_B_SHIFT - HF_CS32_SHIFT);
+ hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >>
+ (DESC_B_SHIFT - HF_SS32_SHIFT);
+ if (!(env->cr[0] & CR0_PE_MASK) ||
+ (env->eflags & VM_MASK) || !(hflags & HF_CS32_MASK)) {
+ hflags |= HF_ADDSEG_MASK;
+ } else {
+ hflags |= ((env->segs[R_DS].base |
+ env->segs[R_ES].base |
+ env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT;
+ }
+ }
+
+ hflags &= ~HF_SMM_MASK;
+
+ env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+ return 0;
+}
+
+static int hax_sync_vcpu_register(CPUArchState *env, int set)
+{
+ struct vcpu_state_t regs;
+ int ret;
+ memset(&regs, 0, sizeof(struct vcpu_state_t));
+
+ if (!set) {
+ ret = hax_sync_vcpu_state(env, &regs, 0);
+ if (ret < 0) {
+ return -1;
+ }
+ }
+
+ /* generic register */
+ hax_getput_reg(&regs._rax, &env->regs[R_EAX], set);
+ hax_getput_reg(&regs._rbx, &env->regs[R_EBX], set);
+ hax_getput_reg(&regs._rcx, &env->regs[R_ECX], set);
+ hax_getput_reg(&regs._rdx, &env->regs[R_EDX], set);
+ hax_getput_reg(&regs._rsi, &env->regs[R_ESI], set);
+ hax_getput_reg(&regs._rdi, &env->regs[R_EDI], set);
+ hax_getput_reg(&regs._rsp, &env->regs[R_ESP], set);
+ hax_getput_reg(&regs._rbp, &env->regs[R_EBP], set);
+#ifdef TARGET_X86_64
+ hax_getput_reg(&regs._r8, &env->regs[8], set);
+ hax_getput_reg(&regs._r9, &env->regs[9], set);
+ hax_getput_reg(&regs._r10, &env->regs[10], set);
+ hax_getput_reg(&regs._r11, &env->regs[11], set);
+ hax_getput_reg(&regs._r12, &env->regs[12], set);
+ hax_getput_reg(&regs._r13, &env->regs[13], set);
+ hax_getput_reg(&regs._r14, &env->regs[14], set);
+ hax_getput_reg(&regs._r15, &env->regs[15], set);
+#endif
+ hax_getput_reg(&regs._rflags, &env->eflags, set);
+ hax_getput_reg(&regs._rip, &env->eip, set);
+
+ if (set) {
+ regs._cr0 = env->cr[0];
+ regs._cr2 = env->cr[2];
+ regs._cr3 = env->cr[3];
+ regs._cr4 = env->cr[4];
+ hax_set_segments(env, &regs);
+ } else {
+ env->cr[0] = regs._cr0;
+ env->cr[2] = regs._cr2;
+ env->cr[3] = regs._cr3;
+ env->cr[4] = regs._cr4;
+ hax_get_segments(env, &regs);
+ }
+
+ if (set) {
+ ret = hax_sync_vcpu_state(env, &regs, 1);
+ if (ret < 0) {
+ return -1;
+ }
+ }
+ if (!set) {
+ hax_setup_qemu_emulator(env);
+ }
+ return 0;
+}
+
+static void hax_msr_entry_set(struct vmx_msr *item, uint32_t index,
+ uint64_t value)
+{
+ item->entry = index;
+ item->value = value;
+}
+
+static int hax_get_msrs(CPUArchState *env)
+{
+ struct hax_msr_data md;
+ struct vmx_msr *msrs = md.entries;
+ int ret, i, n;
+
+ n = 0;
+ msrs[n++].entry = MSR_IA32_SYSENTER_CS;
+ msrs[n++].entry = MSR_IA32_SYSENTER_ESP;
+ msrs[n++].entry = MSR_IA32_SYSENTER_EIP;
+ msrs[n++].entry = MSR_IA32_TSC;
+#ifdef TARGET_X86_64
+ msrs[n++].entry = MSR_EFER;
+ msrs[n++].entry = MSR_STAR;
+ msrs[n++].entry = MSR_LSTAR;
+ msrs[n++].entry = MSR_CSTAR;
+ msrs[n++].entry = MSR_FMASK;
+ msrs[n++].entry = MSR_KERNELGSBASE;
+#endif
+ md.nr_msr = n;
+ ret = hax_sync_msr(env, &md, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ for (i = 0; i < md.done; i++) {
+ switch (msrs[i].entry) {
+ case MSR_IA32_SYSENTER_CS:
+ env->sysenter_cs = msrs[i].value;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ env->sysenter_esp = msrs[i].value;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ env->sysenter_eip = msrs[i].value;
+ break;
+ case MSR_IA32_TSC:
+ env->tsc = msrs[i].value;
+ break;
+#ifdef TARGET_X86_64
+ case MSR_EFER:
+ env->efer = msrs[i].value;
+ break;
+ case MSR_STAR:
+ env->star = msrs[i].value;
+ break;
+ case MSR_LSTAR:
+ env->lstar = msrs[i].value;
+ break;
+ case MSR_CSTAR:
+ env->cstar = msrs[i].value;
+ break;
+ case MSR_FMASK:
+ env->fmask = msrs[i].value;
+ break;
+ case MSR_KERNELGSBASE:
+ env->kernelgsbase = msrs[i].value;
+ break;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static int hax_set_msrs(CPUArchState *env)
+{
+ struct hax_msr_data md;
+ struct vmx_msr *msrs;
+ msrs = md.entries;
+ int n = 0;
+
+ memset(&md, 0, sizeof(struct hax_msr_data));
+ hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
+ hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
+ hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
+ hax_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
+#ifdef TARGET_X86_64
+ hax_msr_entry_set(&msrs[n++], MSR_EFER, env->efer);
+ hax_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
+ hax_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar);
+ hax_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
+ hax_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask);
+ hax_msr_entry_set(&msrs[n++], MSR_KERNELGSBASE, env->kernelgsbase);
+#endif
+ md.nr_msr = n;
+ md.done = 0;
+
+ return hax_sync_msr(env, &md, 1);
+}
+
+static int hax_get_fpu(CPUArchState *env)
+{
+ struct fx_layout fpu;
+ int i, ret;
+
+ ret = hax_sync_fpu(env, &fpu, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ env->fpstt = (fpu.fsw >> 11) & 7;
+ env->fpus = fpu.fsw;
+ env->fpuc = fpu.fcw;
+ for (i = 0; i < 8; ++i) {
+ env->fptags[i] = !((fpu.ftw >> i) & 1);
+ }
+ memcpy(env->fpregs, fpu.st_mm, sizeof(env->fpregs));
+
+ for (i = 0; i < 8; i++) {
+ env->xmm_regs[i].ZMM_Q(0) = ldq_p(&fpu.mmx_1[i][0]);
+ env->xmm_regs[i].ZMM_Q(1) = ldq_p(&fpu.mmx_1[i][8]);
+ if (CPU_NB_REGS > 8) {
+ env->xmm_regs[i + 8].ZMM_Q(0) = ldq_p(&fpu.mmx_2[i][0]);
+ env->xmm_regs[i + 8].ZMM_Q(1) = ldq_p(&fpu.mmx_2[i][8]);
+ }
+ }
+ env->mxcsr = fpu.mxcsr;
+
+ return 0;
+}
+
+static int hax_set_fpu(CPUArchState *env)
+{
+ struct fx_layout fpu;
+ int i;
+
+ memset(&fpu, 0, sizeof(fpu));
+ fpu.fsw = env->fpus & ~(7 << 11);
+ fpu.fsw |= (env->fpstt & 7) << 11;
+ fpu.fcw = env->fpuc;
+
+ for (i = 0; i < 8; ++i) {
+ fpu.ftw |= (!env->fptags[i]) << i;
+ }
+
+ memcpy(fpu.st_mm, env->fpregs, sizeof(env->fpregs));
+ for (i = 0; i < 8; i++) {
+ stq_p(&fpu.mmx_1[i][0], env->xmm_regs[i].ZMM_Q(0));
+ stq_p(&fpu.mmx_1[i][8], env->xmm_regs[i].ZMM_Q(1));
+ if (CPU_NB_REGS > 8) {
+ stq_p(&fpu.mmx_2[i][0], env->xmm_regs[i + 8].ZMM_Q(0));
+ stq_p(&fpu.mmx_2[i][8], env->xmm_regs[i + 8].ZMM_Q(1));
+ }
+ }
+
+ fpu.mxcsr = env->mxcsr;
+
+ return hax_sync_fpu(env, &fpu, 1);
+}
+
+static int hax_arch_get_registers(CPUArchState *env)
+{
+ int ret;
+
+ ret = hax_sync_vcpu_register(env, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = hax_get_fpu(env);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = hax_get_msrs(env);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hax_arch_set_registers(CPUArchState *env)
+{
+ int ret;
+ ret = hax_sync_vcpu_register(env, 1);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to sync vcpu reg\n");
+ return ret;
+ }
+ ret = hax_set_fpu(env);
+ if (ret < 0) {
+ fprintf(stderr, "FPU failed\n");
+ return ret;
+ }
+ ret = hax_set_msrs(env);
+ if (ret < 0) {
+ fprintf(stderr, "MSR failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void hax_vcpu_sync_state(CPUArchState *env, int modified)
+{
+ if (hax_enabled()) {
+ if (modified) {
+ hax_arch_set_registers(env);
+ } else {
+ hax_arch_get_registers(env);
+ }
+ }
+}
+
+/*
+ * much simpler than kvm, at least in first stage because:
+ * We don't need consider the device pass-through, we don't need
+ * consider the framebuffer, and we may even remove the bios at all
+ */
+int hax_sync_vcpus(void)
+{
+ if (hax_enabled()) {
+ CPUState *cpu;
+
+ cpu = first_cpu;
+ if (!cpu) {
+ return 0;
+ }
+
+ for (; cpu != NULL; cpu = CPU_NEXT(cpu)) {
+ int ret;
+
+ ret = hax_arch_set_registers(cpu->env_ptr);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void hax_reset_vcpu_state(void *opaque)
+{
+ CPUState *cpu;
+ for (cpu = first_cpu; cpu != NULL; cpu = CPU_NEXT(cpu)) {
+ cpu->hax_vcpu->tunnel->user_event_pending = 0;
+ cpu->hax_vcpu->tunnel->ready_for_interrupt_injection = 0;
+ }
+}
+
+static void hax_accel_class_init(ObjectClass *oc, void *data)
+{
+ AccelClass *ac = ACCEL_CLASS(oc);
+ ac->name = "HAX";
+ ac->init_machine = hax_accel_init;
+ ac->allowed = &hax_allowed;
+}
+
+static const TypeInfo hax_accel_type = {
+ .name = ACCEL_CLASS_NAME("hax"),
+ .parent = TYPE_ACCEL,
+ .class_init = hax_accel_class_init,
+};
+
+static void hax_type_init(void)
+{
+ type_register_static(&hax_accel_type);
+}
+
+type_init(hax_type_init);
diff --git a/target/i386/hax-darwin.c b/target/i386/hax-darwin.c
new file mode 100644
index 0000000000..1c5bbd0a2d
--- /dev/null
+++ b/target/i386/hax-darwin.c
@@ -0,0 +1,316 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.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.
+ *
+ */
+
+/* HAX module interface - darwin version */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include "qemu/osdep.h"
+#include "target/i386/hax-i386.h"
+
+hax_fd hax_mod_open(void)
+{
+ int fd = open("/dev/HAX", O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "Failed to open the hax module\n");
+ }
+
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ return fd;
+}
+
+int hax_populate_ram(uint64_t va, uint32_t size)
+{
+ int ret;
+ struct hax_alloc_ram_info info;
+
+ if (!hax_global.vm || !hax_global.vm->fd) {
+ fprintf(stderr, "Allocate memory before vm create?\n");
+ return -EINVAL;
+ }
+
+ info.size = size;
+ info.va = va;
+ ret = ioctl(hax_global.vm->fd, HAX_VM_IOCTL_ALLOC_RAM, &info);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to allocate %x memory\n", size);
+ return ret;
+ }
+ return 0;
+}
+
+int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags)
+{
+ struct hax_set_ram_info info;
+ int ret;
+
+ info.pa_start = start_pa;
+ info.size = size;
+ info.va = host_va;
+ info.flags = (uint8_t) flags;
+
+ ret = ioctl(hax_global.vm->fd, HAX_VM_IOCTL_SET_RAM, &info);
+ if (ret < 0) {
+ return -errno;
+ }
+ return 0;
+}
+
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap)
+{
+ int ret;
+
+ ret = ioctl(hax->fd, HAX_IOCTL_CAPABILITY, cap);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to get HAX capability\n");
+ return -errno;
+ }
+
+ return 0;
+}
+
+int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
+{
+ int ret;
+
+ ret = ioctl(hax->fd, HAX_IOCTL_VERSION, version);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to get HAX version\n");
+ return -errno;
+ }
+
+ return 0;
+}
+
+static char *hax_vm_devfs_string(int vm_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID) {
+ fprintf(stderr, "Too big VM id\n");
+ return NULL;
+ }
+
+#define HAX_VM_DEVFS "/dev/hax_vm/vmxx"
+ name = g_strdup(HAX_VM_DEVFS);
+ if (!name) {
+ return NULL;
+ }
+
+ snprintf(name, sizeof HAX_VM_DEVFS, "/dev/hax_vm/vm%02d", vm_id);
+ return name;
+}
+
+static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID) {
+ fprintf(stderr, "Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
+ return NULL;
+ }
+
+#define HAX_VCPU_DEVFS "/dev/hax_vmxx/vcpuxx"
+ name = g_strdup(HAX_VCPU_DEVFS);
+ if (!name) {
+ return NULL;
+ }
+
+ snprintf(name, sizeof HAX_VCPU_DEVFS, "/dev/hax_vm%02d/vcpu%02d",
+ vm_id, vcpu_id);
+ return name;
+}
+
+int hax_host_create_vm(struct hax_state *hax, int *vmid)
+{
+ int ret;
+ int vm_id = 0;
+
+ if (hax_invalid_fd(hax->fd)) {
+ return -EINVAL;
+ }
+
+ if (hax->vm) {
+ return 0;
+ }
+
+ ret = ioctl(hax->fd, HAX_IOCTL_CREATE_VM, &vm_id);
+ *vmid = vm_id;
+ return ret;
+}
+
+hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id)
+{
+ hax_fd fd;
+ char *vm_name = NULL;
+
+ vm_name = hax_vm_devfs_string(vm_id);
+ if (!vm_name) {
+ return -1;
+ }
+
+ fd = open(vm_name, O_RDWR);
+ g_free(vm_name);
+
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ return fd;
+}
+
+int hax_notify_qemu_version(hax_fd vm_fd, struct hax_qemu_version *qversion)
+{
+ int ret;
+
+ if (hax_invalid_fd(vm_fd)) {
+ return -EINVAL;
+ }
+
+ ret = ioctl(vm_fd, HAX_VM_IOCTL_NOTIFY_QEMU_VERSION, qversion);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to notify qemu API version\n");
+ return ret;
+ }
+ return 0;
+}
+
+/* Simply assume the size should be bigger than the hax_tunnel,
+ * since the hax_tunnel can be extended later with compatibility considered
+ */
+int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid)
+{
+ int ret;
+
+ ret = ioctl(vm_fd, HAX_VM_IOCTL_VCPU_CREATE, &vcpuid);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to create vcpu %x\n", vcpuid);
+ }
+
+ return ret;
+}
+
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
+{
+ char *devfs_path = NULL;
+ hax_fd fd;
+
+ devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
+ if (!devfs_path) {
+ fprintf(stderr, "Failed to get the devfs\n");
+ return -EINVAL;
+ }
+
+ fd = open(devfs_path, O_RDWR);
+ g_free(devfs_path);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open the vcpu devfs\n");
+ }
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ return fd;
+}
+
+int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
+{
+ int ret;
+ struct hax_tunnel_info info;
+
+ ret = ioctl(vcpu->fd, HAX_VCPU_IOCTL_SETUP_TUNNEL, &info);
+ if (ret) {
+ fprintf(stderr, "Failed to setup the hax tunnel\n");
+ return ret;
+ }
+
+ if (!valid_hax_tunnel_size(info.size)) {
+ fprintf(stderr, "Invalid hax tunnel size %x\n", info.size);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ vcpu->tunnel = (struct hax_tunnel *) (intptr_t) (info.va);
+ vcpu->iobuf = (unsigned char *) (intptr_t) (info.io_va);
+ return 0;
+}
+
+int hax_vcpu_run(struct hax_vcpu_state *vcpu)
+{
+ int ret;
+
+ ret = ioctl(vcpu->fd, HAX_VCPU_IOCTL_RUN, NULL);
+ return ret;
+}
+
+int hax_sync_fpu(CPUArchState *env, struct fx_layout *fl, int set)
+{
+ int ret, fd;
+
+ fd = hax_vcpu_get_fd(env);
+ if (fd <= 0) {
+ return -1;
+ }
+
+ if (set) {
+ ret = ioctl(fd, HAX_VCPU_IOCTL_SET_FPU, fl);
+ } else {
+ ret = ioctl(fd, HAX_VCPU_IOCTL_GET_FPU, fl);
+ }
+ return ret;
+}
+
+int hax_sync_msr(CPUArchState *env, struct hax_msr_data *msrs, int set)
+{
+ int ret, fd;
+
+ fd = hax_vcpu_get_fd(env);
+ if (fd <= 0) {
+ return -1;
+ }
+ if (set) {
+ ret = ioctl(fd, HAX_VCPU_IOCTL_SET_MSRS, msrs);
+ } else {
+ ret = ioctl(fd, HAX_VCPU_IOCTL_GET_MSRS, msrs);
+ }
+ return ret;
+}
+
+int hax_sync_vcpu_state(CPUArchState *env, struct vcpu_state_t *state, int set)
+{
+ int ret, fd;
+
+ fd = hax_vcpu_get_fd(env);
+ if (fd <= 0) {
+ return -1;
+ }
+
+ if (set) {
+ ret = ioctl(fd, HAX_VCPU_SET_REGS, state);
+ } else {
+ ret = ioctl(fd, HAX_VCPU_GET_REGS, state);
+ }
+ return ret;
+}
+
+int hax_inject_interrupt(CPUArchState *env, int vector)
+{
+ int ret, fd;
+
+ fd = hax_vcpu_get_fd(env);
+ if (fd <= 0) {
+ return -1;
+ }
+
+ ret = ioctl(fd, HAX_VCPU_IOCTL_INTERRUPT, &vector);
+ return ret;
+}
diff --git a/target/i386/hax-darwin.h b/target/i386/hax-darwin.h
new file mode 100644
index 0000000000..0c0968b77d
--- /dev/null
+++ b/target/i386/hax-darwin.h
@@ -0,0 +1,63 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.com>
+ * Xin Xiaohui<xiaohui.xin@intel.com>
+ * Zhang Xiantao<xiantao.zhang@intel.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 TARGET_I386_HAX_DARWIN_H
+#define TARGET_I386_HAX_DARWIN_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+
+#define HAX_INVALID_FD (-1)
+static inline int hax_invalid_fd(hax_fd fd)
+{
+ return fd <= 0;
+}
+
+static inline void hax_mod_close(struct hax_state *hax)
+{
+ close(hax->fd);
+}
+
+static inline void hax_close_fd(hax_fd fd)
+{
+ close(fd);
+}
+
+/* HAX model level ioctl */
+#define HAX_IOCTL_VERSION _IOWR(0, 0x20, struct hax_module_version)
+#define HAX_IOCTL_CREATE_VM _IOWR(0, 0x21, uint32_t)
+#define HAX_IOCTL_DESTROY_VM _IOW(0, 0x22, uint32_t)
+#define HAX_IOCTL_CAPABILITY _IOR(0, 0x23, struct hax_capabilityinfo)
+
+#define HAX_VM_IOCTL_VCPU_CREATE _IOWR(0, 0x80, uint32_t)
+#define HAX_VM_IOCTL_ALLOC_RAM _IOWR(0, 0x81, struct hax_alloc_ram_info)
+#define HAX_VM_IOCTL_SET_RAM _IOWR(0, 0x82, struct hax_set_ram_info)
+#define HAX_VM_IOCTL_VCPU_DESTROY _IOW(0, 0x83, uint32_t)
+#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
+
+#define HAX_VCPU_IOCTL_RUN _IO(0, 0xc0)
+#define HAX_VCPU_IOCTL_SET_MSRS _IOWR(0, 0xc1, struct hax_msr_data)
+#define HAX_VCPU_IOCTL_GET_MSRS _IOWR(0, 0xc2, struct hax_msr_data)
+
+#define HAX_VCPU_IOCTL_SET_FPU _IOW(0, 0xc3, struct fx_layout)
+#define HAX_VCPU_IOCTL_GET_FPU _IOR(0, 0xc4, struct fx_layout)
+
+#define HAX_VCPU_IOCTL_SETUP_TUNNEL _IOWR(0, 0xc5, struct hax_tunnel_info)
+#define HAX_VCPU_IOCTL_INTERRUPT _IOWR(0, 0xc6, uint32_t)
+#define HAX_VCPU_SET_REGS _IOWR(0, 0xc7, struct vcpu_state_t)
+#define HAX_VCPU_GET_REGS _IOWR(0, 0xc8, struct vcpu_state_t)
+
+#endif /* TARGET_I386_HAX_DARWIN_H */
diff --git a/target/i386/hax-i386.h b/target/i386/hax-i386.h
new file mode 100644
index 0000000000..8ffe91fcb5
--- /dev/null
+++ b/target/i386/hax-i386.h
@@ -0,0 +1,94 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.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 _HAX_I386_H
+#define _HAX_I386_H
+
+#include "cpu.h"
+#include "sysemu/hax.h"
+
+#ifdef CONFIG_DARWIN
+typedef int hax_fd;
+#endif
+
+#ifdef CONFIG_WIN32
+typedef HANDLE hax_fd;
+#endif
+
+extern struct hax_state hax_global;
+struct hax_vcpu_state {
+ hax_fd fd;
+ int vcpu_id;
+ struct hax_tunnel *tunnel;
+ unsigned char *iobuf;
+};
+
+struct hax_state {
+ hax_fd fd; /* the global hax device interface */
+ uint32_t version;
+ struct hax_vm *vm;
+ uint64_t mem_quota;
+};
+
+#define HAX_MAX_VCPU 0x10
+#define MAX_VM_ID 0x40
+#define MAX_VCPU_ID 0x40
+
+struct hax_vm {
+ hax_fd fd;
+ int id;
+ struct hax_vcpu_state *vcpus[HAX_MAX_VCPU];
+};
+
+#ifdef NEED_CPU_H
+/* Functions exported to host specific mode */
+hax_fd hax_vcpu_get_fd(CPUArchState *env);
+int valid_hax_tunnel_size(uint16_t size);
+
+/* Host specific functions */
+int hax_mod_version(struct hax_state *hax, struct hax_module_version *version);
+int hax_inject_interrupt(CPUArchState *env, int vector);
+struct hax_vm *hax_vm_create(struct hax_state *hax);
+int hax_vcpu_run(struct hax_vcpu_state *vcpu);
+int hax_vcpu_create(int id);
+int hax_sync_vcpu_state(CPUArchState *env, struct vcpu_state_t *state,
+ int set);
+int hax_sync_msr(CPUArchState *env, struct hax_msr_data *msrs, int set);
+int hax_sync_fpu(CPUArchState *env, struct fx_layout *fl, int set);
+#endif
+
+int hax_vm_destroy(struct hax_vm *vm);
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap);
+int hax_notify_qemu_version(hax_fd vm_fd, struct hax_qemu_version *qversion);
+int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags);
+
+/* Common host function */
+int hax_host_create_vm(struct hax_state *hax, int *vm_id);
+hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id);
+int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid);
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid);
+int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu);
+hax_fd hax_mod_open(void);
+void hax_memory_init(void);
+
+
+#ifdef CONFIG_DARWIN
+#include "target/i386/hax-darwin.h"
+#endif
+
+#ifdef CONFIG_WIN32
+#include "target/i386/hax-windows.h"
+#endif
+
+#include "target/i386/hax-interface.h"
+
+#endif
diff --git a/target/i386/hax-interface.h b/target/i386/hax-interface.h
new file mode 100644
index 0000000000..d141308831
--- /dev/null
+++ b/target/i386/hax-interface.h
@@ -0,0 +1,361 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.com>
+ * Xin Xiaohui<xiaohui.xin@intel.com>
+ * Zhang Xiantao<xiantao.zhang@intel.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.
+ *
+ */
+
+/* Interface with HAX kernel module */
+
+#ifndef _HAX_INTERFACE_H
+#define _HAX_INTERFACE_H
+
+/* fx_layout has 3 formats table 3-56, 512bytes */
+struct fx_layout {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t res1;
+ uint16_t fop;
+ union {
+ struct {
+ uint32_t fip;
+ uint16_t fcs;
+ uint16_t res2;
+ };
+ uint64_t fpu_ip;
+ };
+ union {
+ struct {
+ uint32_t fdp;
+ uint16_t fds;
+ uint16_t res3;
+ };
+ uint64_t fpu_dp;
+ };
+ uint32_t mxcsr;
+ uint32_t mxcsr_mask;
+ uint8_t st_mm[8][16];
+ uint8_t mmx_1[8][16];
+ uint8_t mmx_2[8][16];
+ uint8_t pad[96];
+} __attribute__ ((aligned(8)));
+
+struct vmx_msr {
+ uint64_t entry;
+ uint64_t value;
+} __attribute__ ((__packed__));
+
+/*
+ * Fixed array is not good, but it makes Mac support a bit easier by avoiding
+ * memory map or copyin staff.
+ */
+#define HAX_MAX_MSR_ARRAY 0x20
+struct hax_msr_data {
+ uint16_t nr_msr;
+ uint16_t done;
+ uint16_t pad[2];
+ struct vmx_msr entries[HAX_MAX_MSR_ARRAY];
+} __attribute__ ((__packed__));
+
+union interruptibility_state_t {
+ uint32_t raw;
+ struct {
+ uint32_t sti_blocking:1;
+ uint32_t movss_blocking:1;
+ uint32_t smi_blocking:1;
+ uint32_t nmi_blocking:1;
+ uint32_t reserved:28;
+ };
+ uint64_t pad;
+};
+
+typedef union interruptibility_state_t interruptibility_state_t;
+
+/* Segment descriptor */
+struct segment_desc_t {
+ uint16_t selector;
+ uint16_t _dummy;
+ uint32_t limit;
+ uint64_t base;
+ union {
+ struct {
+ uint32_t type:4;
+ uint32_t desc:1;
+ uint32_t dpl:2;
+ uint32_t present:1;
+ uint32_t:4;
+ uint32_t available:1;
+ uint32_t long_mode:1;
+ uint32_t operand_size:1;
+ uint32_t granularity:1;
+ uint32_t null:1;
+ uint32_t:15;
+ };
+ uint32_t ar;
+ };
+ uint32_t ipad;
+};
+
+typedef struct segment_desc_t segment_desc_t;
+
+struct vcpu_state_t {
+ union {
+ uint64_t _regs[16];
+ struct {
+ union {
+ struct {
+ uint8_t _al, _ah;
+ };
+ uint16_t _ax;
+ uint32_t _eax;
+ uint64_t _rax;
+ };
+ union {
+ struct {
+ uint8_t _cl, _ch;
+ };
+ uint16_t _cx;
+ uint32_t _ecx;
+ uint64_t _rcx;
+ };
+ union {
+ struct {
+ uint8_t _dl, _dh;
+ };
+ uint16_t _dx;
+ uint32_t _edx;
+ uint64_t _rdx;
+ };
+ union {
+ struct {
+ uint8_t _bl, _bh;
+ };
+ uint16_t _bx;
+ uint32_t _ebx;
+ uint64_t _rbx;
+ };
+ union {
+ uint16_t _sp;
+ uint32_t _esp;
+ uint64_t _rsp;
+ };
+ union {
+ uint16_t _bp;
+ uint32_t _ebp;
+ uint64_t _rbp;
+ };
+ union {
+ uint16_t _si;
+ uint32_t _esi;
+ uint64_t _rsi;
+ };
+ union {
+ uint16_t _di;
+ uint32_t _edi;
+ uint64_t _rdi;
+ };
+
+ uint64_t _r8;
+ uint64_t _r9;
+ uint64_t _r10;
+ uint64_t _r11;
+ uint64_t _r12;
+ uint64_t _r13;
+ uint64_t _r14;
+ uint64_t _r15;
+ };
+ };
+
+ union {
+ uint32_t _eip;
+ uint64_t _rip;
+ };
+
+ union {
+ uint32_t _eflags;
+ uint64_t _rflags;
+ };
+
+ segment_desc_t _cs;
+ segment_desc_t _ss;
+ segment_desc_t _ds;
+ segment_desc_t _es;
+ segment_desc_t _fs;
+ segment_desc_t _gs;
+ segment_desc_t _ldt;
+ segment_desc_t _tr;
+
+ segment_desc_t _gdt;
+ segment_desc_t _idt;
+
+ uint64_t _cr0;
+ uint64_t _cr2;
+ uint64_t _cr3;
+ uint64_t _cr4;
+
+ uint64_t _dr0;
+ uint64_t _dr1;
+ uint64_t _dr2;
+ uint64_t _dr3;
+ uint64_t _dr6;
+ uint64_t _dr7;
+ uint64_t _pde;
+
+ uint32_t _efer;
+
+ uint32_t _sysenter_cs;
+ uint64_t _sysenter_eip;
+ uint64_t _sysenter_esp;
+
+ uint32_t _activity_state;
+ uint32_t pad;
+ interruptibility_state_t _interruptibility_state;
+};
+
+/* HAX exit status */
+enum exit_status {
+ /* IO port request */
+ HAX_EXIT_IO = 1,
+ /* MMIO instruction emulation */
+ HAX_EXIT_MMIO,
+ /* QEMU emulation mode request, currently means guest enter non-PG mode */
+ HAX_EXIT_REAL,
+ /*
+ * Interrupt window open, qemu can inject interrupt now
+ * Also used when signal pending since at that time qemu usually need
+ * check interrupt
+ */
+ HAX_EXIT_INTERRUPT,
+ /* Unknown vmexit, mostly trigger reboot */
+ HAX_EXIT_UNKNOWN_VMEXIT,
+ /* HALT from guest */
+ HAX_EXIT_HLT,
+ /* Reboot request, like because of tripple fault in guest */
+ HAX_EXIT_STATECHANGE,
+ /* the vcpu is now only paused when destroy, so simply return to hax */
+ HAX_EXIT_PAUSED,
+ HAX_EXIT_FAST_MMIO,
+};
+
+/*
+ * The interface definition:
+ * 1. vcpu_run execute will return 0 on success, otherwise mean failed
+ * 2. exit_status return the exit reason, as stated in enum exit_status
+ * 3. exit_reason is the vmx exit reason
+ */
+struct hax_tunnel {
+ uint32_t _exit_reason;
+ uint32_t _exit_flag;
+ uint32_t _exit_status;
+ uint32_t user_event_pending;
+ int ready_for_interrupt_injection;
+ int request_interrupt_window;
+ union {
+ struct {
+ /* 0: read, 1: write */
+#define HAX_EXIT_IO_IN 1
+#define HAX_EXIT_IO_OUT 0
+ uint8_t _direction;
+ uint8_t _df;
+ uint16_t _size;
+ uint16_t _port;
+ uint16_t _count;
+ uint8_t _flags;
+ uint8_t _pad0;
+ uint16_t _pad1;
+ uint32_t _pad2;
+ uint64_t _vaddr;
+ } pio;
+ struct {
+ uint64_t gla;
+ } mmio;
+ struct {
+ } state;
+ };
+} __attribute__ ((__packed__));
+
+struct hax_module_version {
+ uint32_t compat_version;
+ uint32_t cur_version;
+} __attribute__ ((__packed__));
+
+/* This interface is support only after API version 2 */
+struct hax_qemu_version {
+ /* Current API version in QEMU */
+ uint32_t cur_version;
+ /* The minimum API version supported by QEMU */
+ uint32_t min_version;
+} __attribute__ ((__packed__));
+
+/* The mac specfic interface to qemu, mostly is ioctl related */
+struct hax_tunnel_info {
+ uint64_t va;
+ uint64_t io_va;
+ uint16_t size;
+ uint16_t pad[3];
+} __attribute__ ((__packed__));
+
+struct hax_alloc_ram_info {
+ uint32_t size;
+ uint32_t pad;
+ uint64_t va;
+} __attribute__ ((__packed__));
+#define HAX_RAM_INFO_ROM 0x01 /* Read-Only */
+#define HAX_RAM_INFO_INVALID 0x80 /* Unmapped, usually used for MMIO */
+struct hax_set_ram_info {
+ uint64_t pa_start;
+ uint32_t size;
+ uint8_t flags;
+ uint8_t pad[3];
+ uint64_t va;
+} __attribute__ ((__packed__));
+
+#define HAX_CAP_STATUS_WORKING 0x1
+#define HAX_CAP_STATUS_NOTWORKING 0x0
+#define HAX_CAP_WORKSTATUS_MASK 0x1
+
+#define HAX_CAP_FAILREASON_VT 0x1
+#define HAX_CAP_FAILREASON_NX 0x2
+
+#define HAX_CAP_MEMQUOTA 0x2
+#define HAX_CAP_UG 0x4
+
+struct hax_capabilityinfo {
+ /* bit 0: 1 - working
+ * 0 - not working, possibly because NT/NX disabled
+ * bit 1: 1 - memory limitation working
+ * 0 - no memory limitation
+ */
+ uint16_t wstatus;
+ /* valid when not working
+ * bit 0: VT not enabeld
+ * bit 1: NX not enabled*/
+ uint16_t winfo;
+ uint32_t pad;
+ uint64_t mem_quota;
+} __attribute__ ((__packed__));
+
+struct hax_fastmmio {
+ uint64_t gpa;
+ union {
+ uint64_t value;
+ uint64_t gpa2; /* since HAX API v4 */
+ };
+ uint8_t size;
+ uint8_t direction;
+ uint16_t reg_index;
+ uint32_t pad0;
+ uint64_t _cr0;
+ uint64_t _cr2;
+ uint64_t _cr3;
+ uint64_t _cr4;
+} __attribute__ ((__packed__));
+#endif
diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c
new file mode 100644
index 0000000000..2884040021
--- /dev/null
+++ b/target/i386/hax-mem.c
@@ -0,0 +1,289 @@
+/*
+ * HAX memory mapping operations
+ *
+ * Copyright (c) 2015-16 Intel Corporation
+ * Copyright 2016 Google, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/address-spaces.h"
+#include "exec/exec-all.h"
+
+#include "target/i386/hax-i386.h"
+#include "qemu/queue.h"
+
+#define DEBUG_HAX_MEM 0
+
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_HAX_MEM) { \
+ fprintf(stdout, fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+/**
+ * HAXMapping: describes a pending guest physical memory mapping
+ *
+ * @start_pa: a guest physical address marking the start of the region; must be
+ * page-aligned
+ * @size: a guest physical address marking the end of the region; must be
+ * page-aligned
+ * @host_va: the host virtual address of the start of the mapping
+ * @flags: mapping parameters e.g. HAX_RAM_INFO_ROM or HAX_RAM_INFO_INVALID
+ * @entry: additional fields for linking #HAXMapping instances together
+ */
+typedef struct HAXMapping {
+ uint64_t start_pa;
+ uint32_t size;
+ uint64_t host_va;
+ int flags;
+ QTAILQ_ENTRY(HAXMapping) entry;
+} HAXMapping;
+
+/*
+ * A doubly-linked list (actually a tail queue) of the pending page mappings
+ * for the ongoing memory transaction.
+ *
+ * It is used to optimize the number of page mapping updates done through the
+ * kernel module. For example, it's effective when a driver is digging an MMIO
+ * hole inside an existing memory mapping. It will get a deletion of the whole
+ * region, then the addition of the 2 remaining RAM areas around the hole and
+ * finally the memory transaction commit. During the commit, it will effectively
+ * send to the kernel only the removal of the pages from the MMIO hole after
+ * having computed locally the result of the deletion and additions.
+ */
+static QTAILQ_HEAD(HAXMappingListHead, HAXMapping) mappings =
+ QTAILQ_HEAD_INITIALIZER(mappings);
+
+/**
+ * hax_mapping_dump_list: dumps @mappings to stdout (for debugging)
+ */
+static void hax_mapping_dump_list(void)
+{
+ HAXMapping *entry;
+
+ DPRINTF("%s updates:\n", __func__);
+ QTAILQ_FOREACH(entry, &mappings, entry) {
+ DPRINTF("\t%c 0x%016" PRIx64 "->0x%016" PRIx64 " VA 0x%016" PRIx64
+ "%s\n", entry->flags & HAX_RAM_INFO_INVALID ? '-' : '+',
+ entry->start_pa, entry->start_pa + entry->size, entry->host_va,
+ entry->flags & HAX_RAM_INFO_ROM ? " ROM" : "");
+ }
+}
+
+static void hax_insert_mapping_before(HAXMapping *next, uint64_t start_pa,
+ uint32_t size, uint64_t host_va,
+ uint8_t flags)
+{
+ HAXMapping *entry;
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->start_pa = start_pa;
+ entry->size = size;
+ entry->host_va = host_va;
+ entry->flags = flags;
+ if (!next) {
+ QTAILQ_INSERT_TAIL(&mappings, entry, entry);
+ } else {
+ QTAILQ_INSERT_BEFORE(next, entry, entry);
+ }
+}
+
+static bool hax_mapping_is_opposite(HAXMapping *entry, uint64_t host_va,
+ uint8_t flags)
+{
+ /* removed then added without change for the read-only flag */
+ bool nop_flags = (entry->flags ^ flags) == HAX_RAM_INFO_INVALID;
+
+ return (entry->host_va == host_va) && nop_flags;
+}
+
+static void hax_update_mapping(uint64_t start_pa, uint32_t size,
+ uint64_t host_va, uint8_t flags)
+{
+ uint64_t end_pa = start_pa + size;
+ uint32_t chunk_sz;
+ HAXMapping *entry, *next;
+
+ QTAILQ_FOREACH_SAFE(entry, &mappings, entry, next) {
+ if (start_pa >= entry->start_pa + entry->size) {
+ continue;
+ }
+ if (start_pa < entry->start_pa) {
+ chunk_sz = end_pa <= entry->start_pa ? size
+ : entry->start_pa - start_pa;
+ hax_insert_mapping_before(entry, start_pa, chunk_sz,
+ host_va, flags);
+ start_pa += chunk_sz;
+ host_va += chunk_sz;
+ size -= chunk_sz;
+ }
+ chunk_sz = MIN(size, entry->size);
+ if (chunk_sz) {
+ bool nop = hax_mapping_is_opposite(entry, host_va, flags);
+ bool partial = chunk_sz < entry->size;
+ if (partial) {
+ /* remove the beginning of the existing chunk */
+ entry->start_pa += chunk_sz;
+ entry->host_va += chunk_sz;
+ entry->size -= chunk_sz;
+ if (!nop) {
+ hax_insert_mapping_before(entry, start_pa, chunk_sz,
+ host_va, flags);
+ }
+ } else { /* affects the full mapping entry */
+ if (nop) { /* no change to this mapping, remove it */
+ QTAILQ_REMOVE(&mappings, entry, entry);
+ g_free(entry);
+ } else { /* update mapping properties */
+ entry->host_va = host_va;
+ entry->flags = flags;
+ }
+ }
+ start_pa += chunk_sz;
+ host_va += chunk_sz;
+ size -= chunk_sz;
+ }
+ if (!size) { /* we are done */
+ break;
+ }
+ }
+ if (size) { /* add the leftover */
+ hax_insert_mapping_before(NULL, start_pa, size, host_va, flags);
+ }
+}
+
+static void hax_process_section(MemoryRegionSection *section, uint8_t flags)
+{
+ MemoryRegion *mr = section->mr;
+ hwaddr start_pa = section->offset_within_address_space;
+ ram_addr_t size = int128_get64(section->size);
+ unsigned int delta;
+ uint64_t host_va;
+
+ /* We only care about RAM pages */
+ if (!memory_region_is_ram(mr)) {
+ return;
+ }
+
+ /* Adjust start_pa and size so that they are page-aligned. (Cf
+ * kvm_set_phys_mem() in kvm-all.c).
+ */
+ delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask);
+ delta &= ~qemu_real_host_page_mask;
+ if (delta > size) {
+ return;
+ }
+ start_pa += delta;
+ size -= delta;
+ size &= qemu_real_host_page_mask;
+ if (!size || (start_pa & ~qemu_real_host_page_mask)) {
+ return;
+ }
+
+ host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
+ + section->offset_within_region + delta;
+ if (memory_region_is_rom(section->mr)) {
+ flags |= HAX_RAM_INFO_ROM;
+ }
+
+ /* the kernel module interface uses 32-bit sizes (but we could split...) */
+ g_assert(size <= UINT32_MAX);
+
+ hax_update_mapping(start_pa, size, host_va, flags);
+}
+
+static void hax_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ memory_region_ref(section->mr);
+ hax_process_section(section, 0);
+}
+
+static void hax_region_del(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ hax_process_section(section, HAX_RAM_INFO_INVALID);
+ memory_region_unref(section->mr);
+}
+
+static void hax_transaction_begin(MemoryListener *listener)
+{
+ g_assert(QTAILQ_EMPTY(&mappings));
+}
+
+static void hax_transaction_commit(MemoryListener *listener)
+{
+ if (!QTAILQ_EMPTY(&mappings)) {
+ HAXMapping *entry, *next;
+
+ if (DEBUG_HAX_MEM) {
+ hax_mapping_dump_list();
+ }
+ QTAILQ_FOREACH_SAFE(entry, &mappings, entry, next) {
+ if (entry->flags & HAX_RAM_INFO_INVALID) {
+ /* for unmapping, put the values expected by the kernel */
+ entry->flags = HAX_RAM_INFO_INVALID;
+ entry->host_va = 0;
+ }
+ if (hax_set_ram(entry->start_pa, entry->size,
+ entry->host_va, entry->flags)) {
+ fprintf(stderr, "%s: Failed mapping @0x%016" PRIx64 "+0x%"
+ PRIx32 " flags %02x\n", __func__, entry->start_pa,
+ entry->size, entry->flags);
+ }
+ QTAILQ_REMOVE(&mappings, entry, entry);
+ g_free(entry);
+ }
+ }
+}
+
+/* currently we fake the dirty bitmap sync, always dirty */
+static void hax_log_sync(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ MemoryRegion *mr = section->mr;
+
+ if (!memory_region_is_ram(mr)) {
+ /* Skip MMIO regions */
+ return;
+ }
+
+ memory_region_set_dirty(mr, 0, int128_get64(section->size));
+}
+
+static MemoryListener hax_memory_listener = {
+ .begin = hax_transaction_begin,
+ .commit = hax_transaction_commit,
+ .region_add = hax_region_add,
+ .region_del = hax_region_del,
+ .log_sync = hax_log_sync,
+ .priority = 10,
+};
+
+static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
+{
+ /*
+ * In HAX, QEMU allocates the virtual address, and HAX kernel
+ * populates the memory with physical memory. Currently we have no
+ * paging, so user should make sure enough free memory in advance.
+ */
+ if (hax_populate_ram((uint64_t)(uintptr_t)host, size) < 0) {
+ fprintf(stderr, "HAX failed to populate RAM");
+ abort();
+ }
+}
+
+static struct RAMBlockNotifier hax_ram_notifier = {
+ .ram_block_added = hax_ram_block_added,
+};
+
+void hax_memory_init(void)
+{
+ ram_block_notifier_add(&hax_ram_notifier);
+ memory_listener_register(&hax_memory_listener, &address_space_memory);
+}
diff --git a/target/i386/hax-windows.c b/target/i386/hax-windows.c
new file mode 100644
index 0000000000..15a180b646
--- /dev/null
+++ b/target/i386/hax-windows.c
@@ -0,0 +1,479 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.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/osdep.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "hax-i386.h"
+
+/*
+ * return 0 when success, -1 when driver not loaded,
+ * other negative value for other failure
+ */
+static int hax_open_device(hax_fd *fd)
+{
+ uint32_t errNum = 0;
+ HANDLE hDevice;
+
+ if (!fd) {
+ return -2;
+ }
+
+ hDevice = CreateFile("\\\\.\\HAX",
+ GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Failed to open the HAX device!\n");
+ errNum = GetLastError();
+ if (errNum == ERROR_FILE_NOT_FOUND) {
+ return -1;
+ }
+ return -2;
+ }
+ *fd = hDevice;
+ return 0;
+}
+
+/* hax_fd hax_mod_open */
+ hax_fd hax_mod_open(void)
+{
+ int ret;
+ hax_fd fd = NULL;
+
+ ret = hax_open_device(&fd);
+ if (ret != 0) {
+ fprintf(stderr, "Open HAX device failed\n");
+ }
+
+ return fd;
+}
+
+int hax_populate_ram(uint64_t va, uint32_t size)
+{
+ int ret;
+ struct hax_alloc_ram_info info;
+ HANDLE hDeviceVM;
+ DWORD dSize = 0;
+
+ if (!hax_global.vm || !hax_global.vm->fd) {
+ fprintf(stderr, "Allocate memory before vm create?\n");
+ return -EINVAL;
+ }
+
+ info.size = size;
+ info.va = va;
+
+ hDeviceVM = hax_global.vm->fd;
+
+ ret = DeviceIoControl(hDeviceVM,
+ HAX_VM_IOCTL_ALLOC_RAM,
+ &info, sizeof(info), NULL, 0, &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to allocate %x memory\n", size);
+ return ret;
+ }
+
+ return 0;
+}
+
+int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags)
+{
+ struct hax_set_ram_info info;
+ HANDLE hDeviceVM = hax_global.vm->fd;
+ DWORD dSize = 0;
+ int ret;
+
+ info.pa_start = start_pa;
+ info.size = size;
+ info.va = host_va;
+ info.flags = (uint8_t) flags;
+
+ ret = DeviceIoControl(hDeviceVM, HAX_VM_IOCTL_SET_RAM,
+ &info, sizeof(info), NULL, 0, &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap)
+{
+ int ret;
+ HANDLE hDevice = hax->fd; /* handle to hax module */
+ DWORD dSize = 0;
+ DWORD err = 0;
+
+ if (hax_invalid_fd(hDevice)) {
+ fprintf(stderr, "Invalid fd for hax device!\n");
+ return -ENODEV;
+ }
+
+ ret = DeviceIoControl(hDevice, HAX_IOCTL_CAPABILITY, NULL, 0, cap,
+ sizeof(*cap), &dSize, (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ err = GetLastError();
+ if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) {
+ fprintf(stderr, "hax capability is too long to hold.\n");
+ }
+ fprintf(stderr, "Failed to get Hax capability:%luu\n", err);
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
+{
+ int ret;
+ HANDLE hDevice = hax->fd; /* handle to hax module */
+ DWORD dSize = 0;
+ DWORD err = 0;
+
+ if (hax_invalid_fd(hDevice)) {
+ fprintf(stderr, "Invalid fd for hax device!\n");
+ return -ENODEV;
+ }
+
+ ret = DeviceIoControl(hDevice,
+ HAX_IOCTL_VERSION,
+ NULL, 0,
+ version, sizeof(*version), &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ err = GetLastError();
+ if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) {
+ fprintf(stderr, "hax module verion is too long to hold.\n");
+ }
+ fprintf(stderr, "Failed to get Hax module version:%lu\n", err);
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+static char *hax_vm_devfs_string(int vm_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID) {
+ fprintf(stderr, "Too big VM id\n");
+ return NULL;
+ }
+
+#define HAX_VM_DEVFS "\\\\.\\hax_vmxx"
+ name = g_strdup(HAX_VM_DEVFS);
+ if (!name) {
+ return NULL;
+ }
+
+ snprintf(name, sizeof HAX_VM_DEVFS, "\\\\.\\hax_vm%02d", vm_id);
+ return name;
+}
+
+static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID) {
+ fprintf(stderr, "Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
+ return NULL;
+ }
+
+#define HAX_VCPU_DEVFS "\\\\.\\hax_vmxx_vcpuxx"
+ name = g_strdup(HAX_VCPU_DEVFS);
+ if (!name) {
+ return NULL;
+ }
+
+ snprintf(name, sizeof HAX_VCPU_DEVFS, "\\\\.\\hax_vm%02d_vcpu%02d",
+ vm_id, vcpu_id);
+ return name;
+}
+
+int hax_host_create_vm(struct hax_state *hax, int *vmid)
+{
+ int ret;
+ int vm_id = 0;
+ DWORD dSize = 0;
+
+ if (hax_invalid_fd(hax->fd)) {
+ return -EINVAL;
+ }
+
+ if (hax->vm) {
+ return 0;
+ }
+
+ ret = DeviceIoControl(hax->fd,
+ HAX_IOCTL_CREATE_VM,
+ NULL, 0, &vm_id, sizeof(vm_id), &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret) {
+ fprintf(stderr, "Failed to create VM. Error code: %lu\n",
+ GetLastError());
+ return -1;
+ }
+ *vmid = vm_id;
+ return 0;
+}
+
+hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id)
+{
+ char *vm_name = NULL;
+ hax_fd hDeviceVM;
+
+ vm_name = hax_vm_devfs_string(vm_id);
+ if (!vm_name) {
+ fprintf(stderr, "Failed to open VM. VM name is null\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ hDeviceVM = CreateFile(vm_name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hDeviceVM == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Open the vm device error:%s, ec:%lu\n",
+ vm_name, GetLastError());
+ }
+
+ g_free(vm_name);
+ return hDeviceVM;
+}
+
+int hax_notify_qemu_version(hax_fd vm_fd, struct hax_qemu_version *qversion)
+{
+ int ret;
+ DWORD dSize = 0;
+ if (hax_invalid_fd(vm_fd)) {
+ return -EINVAL;
+ }
+ ret = DeviceIoControl(vm_fd,
+ HAX_VM_IOCTL_NOTIFY_QEMU_VERSION,
+ qversion, sizeof(struct hax_qemu_version),
+ NULL, 0, &dSize, (LPOVERLAPPED) NULL);
+ if (!ret) {
+ fprintf(stderr, "Failed to notify qemu API version\n");
+ return -1;
+ }
+ return 0;
+}
+
+int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid)
+{
+ int ret;
+ DWORD dSize = 0;
+
+ ret = DeviceIoControl(vm_fd,
+ HAX_VM_IOCTL_VCPU_CREATE,
+ &vcpuid, sizeof(vcpuid), NULL, 0, &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret) {
+ fprintf(stderr, "Failed to create vcpu %x\n", vcpuid);
+ return -1;
+ }
+
+ return 0;
+}
+
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
+{
+ char *devfs_path = NULL;
+ hax_fd hDeviceVCPU;
+
+ devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
+ if (!devfs_path) {
+ fprintf(stderr, "Failed to get the devfs\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ hDeviceVCPU = CreateFile(devfs_path,
+ GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hDeviceVCPU == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Failed to open the vcpu devfs\n");
+ }
+ g_free(devfs_path);
+ return hDeviceVCPU;
+}
+
+int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
+{
+ hax_fd hDeviceVCPU = vcpu->fd;
+ int ret;
+ struct hax_tunnel_info info;
+ DWORD dSize = 0;
+
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_SETUP_TUNNEL,
+ NULL, 0, &info, sizeof(info), &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret) {
+ fprintf(stderr, "Failed to setup the hax tunnel\n");
+ return -1;
+ }
+
+ if (!valid_hax_tunnel_size(info.size)) {
+ fprintf(stderr, "Invalid hax tunnel size %x\n", info.size);
+ ret = -EINVAL;
+ return ret;
+ }
+ vcpu->tunnel = (struct hax_tunnel *) (intptr_t) (info.va);
+ vcpu->iobuf = (unsigned char *) (intptr_t) (info.io_va);
+ return 0;
+}
+
+int hax_vcpu_run(struct hax_vcpu_state *vcpu)
+{
+ int ret;
+ HANDLE hDeviceVCPU = vcpu->fd;
+ DWORD dSize = 0;
+
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_RUN,
+ NULL, 0, NULL, 0, &dSize, (LPOVERLAPPED) NULL);
+ if (!ret) {
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+int hax_sync_fpu(CPUArchState *env, struct fx_layout *fl, int set)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize = 0;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd)) {
+ return -1;
+ }
+
+ hDeviceVCPU = fd;
+
+ if (set) {
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_SET_FPU,
+ fl, sizeof(*fl), NULL, 0, &dSize,
+ (LPOVERLAPPED) NULL);
+ } else {
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_GET_FPU,
+ NULL, 0, fl, sizeof(*fl), &dSize,
+ (LPOVERLAPPED) NULL);
+ }
+ if (!ret) {
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+int hax_sync_msr(CPUArchState *env, struct hax_msr_data *msrs, int set)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize = 0;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd)) {
+ return -1;
+ }
+ hDeviceVCPU = fd;
+
+ if (set) {
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_SET_MSRS,
+ msrs, sizeof(*msrs),
+ msrs, sizeof(*msrs), &dSize, (LPOVERLAPPED) NULL);
+ } else {
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_GET_MSRS,
+ msrs, sizeof(*msrs),
+ msrs, sizeof(*msrs), &dSize, (LPOVERLAPPED) NULL);
+ }
+ if (!ret) {
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+int hax_sync_vcpu_state(CPUArchState *env, struct vcpu_state_t *state, int set)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd)) {
+ return -1;
+ }
+
+ hDeviceVCPU = fd;
+
+ if (set) {
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_SET_REGS,
+ state, sizeof(*state),
+ NULL, 0, &dSize, (LPOVERLAPPED) NULL);
+ } else {
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_GET_REGS,
+ NULL, 0,
+ state, sizeof(*state), &dSize,
+ (LPOVERLAPPED) NULL);
+ }
+ if (!ret) {
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+int hax_inject_interrupt(CPUArchState *env, int vector)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd)) {
+ return -1;
+ }
+
+ hDeviceVCPU = fd;
+
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_INTERRUPT,
+ &vector, sizeof(vector), NULL, 0, &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret) {
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
diff --git a/target/i386/hax-windows.h b/target/i386/hax-windows.h
new file mode 100644
index 0000000000..1d8f68de91
--- /dev/null
+++ b/target/i386/hax-windows.h
@@ -0,0 +1,89 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * Written by:
+ * Jiang Yunhong<yunhong.jiang@intel.com>
+ * Xin Xiaohui<xiaohui.xin@intel.com>
+ * Zhang Xiantao<xiantao.zhang@intel.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 TARGET_I386_HAX_WINDOWS_H
+#define TARGET_I386_HAX_WINDOWS_H
+
+#include <windows.h>
+#include <memory.h>
+#include <malloc.h>
+#include <winioctl.h>
+#include <string.h>
+#include <stdio.h>
+#include <windef.h>
+
+#define HAX_INVALID_FD INVALID_HANDLE_VALUE
+
+static inline void hax_mod_close(struct hax_state *hax)
+{
+ CloseHandle(hax->fd);
+}
+
+static inline void hax_close_fd(hax_fd fd)
+{
+ CloseHandle(fd);
+}
+
+static inline int hax_invalid_fd(hax_fd fd)
+{
+ return (fd == INVALID_HANDLE_VALUE);
+}
+
+#define HAX_DEVICE_TYPE 0x4000
+
+#define HAX_IOCTL_VERSION CTL_CODE(HAX_DEVICE_TYPE, 0x900, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_IOCTL_CREATE_VM CTL_CODE(HAX_DEVICE_TYPE, 0x901, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_IOCTL_CAPABILITY CTL_CODE(HAX_DEVICE_TYPE, 0x910, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VM_IOCTL_VCPU_CREATE CTL_CODE(HAX_DEVICE_TYPE, 0x902, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VM_IOCTL_ALLOC_RAM CTL_CODE(HAX_DEVICE_TYPE, 0x903, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VM_IOCTL_SET_RAM CTL_CODE(HAX_DEVICE_TYPE, 0x904, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VM_IOCTL_VCPU_DESTROY CTL_CODE(HAX_DEVICE_TYPE, 0x905, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VCPU_IOCTL_RUN CTL_CODE(HAX_DEVICE_TYPE, 0x906, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_SET_MSRS CTL_CODE(HAX_DEVICE_TYPE, 0x907, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_GET_MSRS CTL_CODE(HAX_DEVICE_TYPE, 0x908, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_SET_FPU CTL_CODE(HAX_DEVICE_TYPE, 0x909, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_GET_FPU CTL_CODE(HAX_DEVICE_TYPE, 0x90a, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VCPU_IOCTL_SETUP_TUNNEL CTL_CODE(HAX_DEVICE_TYPE, 0x90b, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_INTERRUPT CTL_CODE(HAX_DEVICE_TYPE, 0x90c, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_SET_REGS CTL_CODE(HAX_DEVICE_TYPE, 0x90d, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_GET_REGS CTL_CODE(HAX_DEVICE_TYPE, 0x90e, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION CTL_CODE(HAX_DEVICE_TYPE, 0x910, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+#endif /* TARGET_I386_HAX_WINDOWS_H */
diff --git a/target/i386/helper.c b/target/i386/helper.c
index c86272efab..e2af3404f2 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -24,6 +24,7 @@
#include "kvm_i386.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
#include "monitor/monitor.h"
#include "hw/i386/apic_internal.h"
#endif
diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c
index 39a230f119..8545574568 100644
--- a/target/i386/hyperv.c
+++ b/target/i386/hyperv.c
@@ -12,6 +12,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "hyperv.h"
#include "standard-headers/asm-x86/hyperv.h"
@@ -88,7 +89,7 @@ HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
goto err_sint_set_notifier;
}
- event_notifier_set_handler(&sint_route->sint_ack_notifier, false,
+ event_notifier_set_handler(&sint_route->sint_ack_notifier,
kvm_hv_sint_ack_handler);
gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vcpu_id, sint);
@@ -112,7 +113,7 @@ HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
err_irqfd:
kvm_irqchip_release_virq(kvm_state, gsi);
err_gsi:
- event_notifier_set_handler(&sint_route->sint_ack_notifier, false, NULL);
+ event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
event_notifier_cleanup(&sint_route->sint_ack_notifier);
err_sint_set_notifier:
event_notifier_cleanup(&sint_route->sint_set_notifier);
@@ -128,7 +129,7 @@ void kvm_hv_sint_route_destroy(HvSintRoute *sint_route)
&sint_route->sint_set_notifier,
sint_route->gsi);
kvm_irqchip_release_virq(kvm_state, sint_route->gsi);
- event_notifier_set_handler(&sint_route->sint_ack_notifier, false, NULL);
+ event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
event_notifier_cleanup(&sint_route->sint_ack_notifier);
event_notifier_cleanup(&sint_route->sint_set_notifier);
g_free(sint_route);
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 10a9cd8f7f..e6c4f754ab 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -23,6 +23,7 @@
#include "qemu-common.h"
#include "cpu.h"
#include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/kvm_int.h"
#include "kvm_i386.h"
#include "hyperv.h"
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index dcf5fbba0c..998c3412c3 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -55,6 +55,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
return 0;
}
+int kvm_arch_irqchip_create(MachineState *ms, KVMState *s)
+{
+ return 0;
+}
+
int kvm_arch_init_vcpu(CPUState *cs)
{
MIPSCPU *cpu = MIPS_CPU(cs);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 9c4834c4fc..ec92c64159 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -26,7 +26,7 @@
#include "cpu.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "sysemu/numa.h"
#include "kvm_ppc.h"
#include "sysemu/cpus.h"
@@ -145,6 +145,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
return 0;
}
+int kvm_arch_irqchip_create(MachineState *ms, KVMState *s)
+{
+ return 0;
+}
+
static int kvm_arch_sync_sregs(PowerPCCPU *cpu)
{
CPUPPCState *cenv = &cpu->env;
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index bd1d78bfbe..4b43283913 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -315,16 +315,4 @@ static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len)
#endif /* CONFIG_KVM */
-#ifndef KVM_INTERRUPT_SET
-#define KVM_INTERRUPT_SET -1
-#endif
-
-#ifndef KVM_INTERRUPT_UNSET
-#define KVM_INTERRUPT_UNSET -2
-#endif
-
-#ifndef KVM_INTERRUPT_SET_LEVEL
-#define KVM_INTERRUPT_SET_LEVEL -3
-#endif
-
#endif /* KVM_PPC_H */
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index fdb7a787bf..0efc8c63fa 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -23,7 +23,7 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
#include "exec/log.h"
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index e6a835c14c..94dfcd7afc 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -21,10 +21,10 @@
#include "qemu/osdep.h"
#include "disas/bfd.h"
#include "exec/gdbstub.h"
-#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "sysemu/arch_init.h"
#include "sysemu/cpus.h"
+#include "sysemu/hw_accel.h"
#include "cpu-models.h"
#include "mmu-hash32.h"
#include "mmu-hash64.h"
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index ea4dc22eeb..94ab74d58f 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -23,6 +23,7 @@
#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu/bitops.h"
+#include "sysemu/hw_accel.h"
int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index c47db9a884..3ac29f92b3 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -294,6 +294,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
return 0;
}
+int kvm_arch_irqchip_create(MachineState *ms, KVMState *s)
+{
+ return 0;
+}
+
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
{
return cpu->cpu_index;
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 96f59703a1..22ea256e94 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -537,6 +537,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
hw/core/bus.o \
hw/core/irq.o \
hw/core/fw-path-provider.o \
+ hw/core/reset.o \
$(test-qapi-obj-y)
tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
migration/vmstate.o migration/qemu-file.o \
diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c
index 37debc11f9..c5637cc406 100644
--- a/tests/device-introspect-test.c
+++ b/tests/device-introspect-test.c
@@ -20,18 +20,24 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qdict.h"
#include "libqtest.h"
const char common_args[] = "-nodefaults -machine none";
-static QList *device_type_list(bool abstract)
+static QList *qom_list_types(const char *implements, bool abstract)
{
QDict *resp;
QList *ret;
+ QDict *args = qdict_new();
+ qdict_put(args, "abstract", qbool_from_bool(abstract));
+ if (implements) {
+ qdict_put(args, "implements", qstring_from_str(implements));
+ }
resp = qmp("{'execute': 'qom-list-types',"
- " 'arguments': {'implements': 'device', 'abstract': %i}}",
- abstract);
+ " 'arguments': %p }", args);
g_assert(qdict_haskey(resp, "return"));
ret = qdict_get_qlist(resp, "return");
QINCREF(ret);
@@ -39,6 +45,11 @@ static QList *device_type_list(bool abstract)
return ret;
}
+static QList *device_type_list(bool abstract)
+{
+ return qom_list_types("device", abstract);
+}
+
static void test_one_device(const char *type)
{
QDict *resp;
@@ -110,6 +121,48 @@ static void test_device_intro_concrete(void)
qtest_end();
}
+static void test_abstract_interfaces(void)
+{
+ QList *all_types;
+ QList *obj_types;
+ QListEntry *ae;
+
+ qtest_start(common_args);
+ /* qom-list-types implements=interface would return any type
+ * that implements _any_ interface (not just interface types),
+ * so use a trick to find the interface type names:
+ * - list all object types
+ * - list all types, and look for items that are not
+ * on the first list
+ */
+ all_types = qom_list_types(NULL, false);
+ obj_types = qom_list_types("object", false);
+
+ QLIST_FOREACH_ENTRY(all_types, ae) {
+ QDict *at = qobject_to_qdict(qlist_entry_obj(ae));
+ const char *aname = qdict_get_str(at, "name");
+ QListEntry *oe;
+ const char *found = NULL;
+
+ QLIST_FOREACH_ENTRY(obj_types, oe) {
+ QDict *ot = qobject_to_qdict(qlist_entry_obj(oe));
+ const char *oname = qdict_get_str(ot, "name");
+ if (!strcmp(aname, oname)) {
+ found = oname;
+ break;
+ }
+ }
+
+ /* Using g_assert_cmpstr() will give more useful failure
+ * messages than g_assert(found) */
+ g_assert_cmpstr(aname, ==, found);
+ }
+
+ QDECREF(all_types);
+ QDECREF(obj_types);
+ qtest_end();
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -118,6 +171,7 @@ int main(int argc, char **argv)
qtest_add_func("device/introspect/none", test_device_intro_none);
qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
qtest_add_func("device/introspect/concrete", test_device_intro_concrete);
+ qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces);
return g_test_run();
}
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index aa88c3cf45..aaa9116fb7 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -156,12 +156,11 @@ struct TestIOChannelData {
};
-static void test_io_channel_complete(Object *src,
- Error *err,
+static void test_io_channel_complete(QIOTask *task,
gpointer opaque)
{
struct TestIOChannelData *data = opaque;
- data->err = err != NULL;
+ data->err = qio_task_propagate_error(task, NULL);
g_main_loop_quit(data->loop);
}
diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
index bd3ae2bf7a..8eaa208e1b 100644
--- a/tests/test-io-channel-tls.c
+++ b/tests/test-io-channel-tls.c
@@ -53,14 +53,13 @@ struct QIOChannelTLSHandshakeData {
bool failed;
};
-static void test_tls_handshake_done(Object *source,
- Error *err,
+static void test_tls_handshake_done(QIOTask *task,
gpointer opaque)
{
struct QIOChannelTLSHandshakeData *data = opaque;
data->finished = true;
- data->failed = err != NULL;
+ data->failed = qio_task_propagate_error(task, NULL);
}
diff --git a/tests/test-io-task.c b/tests/test-io-task.c
index e091c12e10..ff62272d5f 100644
--- a/tests/test-io-task.c
+++ b/tests/test-io-task.c
@@ -50,14 +50,13 @@ struct TestTaskData {
};
-static void task_callback(Object *source,
- Error *err,
+static void task_callback(QIOTask *task,
gpointer opaque)
{
struct TestTaskData *data = opaque;
- data->source = source;
- data->err = err;
+ data->source = qio_task_get_source(task);
+ qio_task_propagate_error(task, &data->err);
}
@@ -76,7 +75,6 @@ static void test_task_complete(void)
g_assert(obj == src);
object_unref(obj);
- object_unref(src);
g_assert(data.source == obj);
g_assert(data.err == NULL);
@@ -121,9 +119,9 @@ static void test_task_failure(void)
error_setg(&err, "Some error");
- qio_task_abort(task, err);
+ qio_task_set_error(task, err);
+ qio_task_complete(task);
- error_free(err);
object_unref(obj);
g_assert(data.source == obj);
@@ -142,31 +140,28 @@ struct TestThreadWorkerData {
GMainLoop *loop;
};
-static int test_task_thread_worker(QIOTask *task,
- Error **errp,
- gpointer opaque)
+static void test_task_thread_worker(QIOTask *task,
+ gpointer opaque)
{
struct TestThreadWorkerData *data = opaque;
data->worker = g_thread_self();
if (data->fail) {
- error_setg(errp, "Testing fail");
- return -1;
+ Error *err = NULL;
+ error_setg(&err, "Testing fail");
+ qio_task_set_error(task, err);
}
-
- return 0;
}
-static void test_task_thread_callback(Object *source,
- Error *err,
+static void test_task_thread_callback(QIOTask *task,
gpointer opaque)
{
struct TestThreadWorkerData *data = opaque;
- data->source = source;
- data->err = err;
+ data->source = qio_task_get_source(task);
+ qio_task_propagate_error(task, &data->err);
data->complete = g_thread_self();
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index c0c29a5119..ffaab57550 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -65,16 +65,17 @@ static void start_auth_vencrypt_subauth(VncState *vs)
}
}
-static void vnc_tls_handshake_done(Object *source,
- Error *err,
+static void vnc_tls_handshake_done(QIOTask *task,
gpointer user_data)
{
VncState *vs = user_data;
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
VNC_DEBUG("Handshake failed %s\n",
error_get_pretty(err));
vnc_client_error(vs);
+ error_free(err);
} else {
vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL);
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index bffb484a8d..f530cd5474 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -24,15 +24,16 @@
#include "io/channel-websock.h"
#include "qemu/bswap.h"
-static void vncws_tls_handshake_done(Object *source,
- Error *err,
+static void vncws_tls_handshake_done(QIOTask *task,
gpointer user_data)
{
VncState *vs = user_data;
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
vnc_client_error(vs);
+ error_free(err);
} else {
VNC_DEBUG("TLS handshake complete, starting websocket handshake\n");
vs->ioc_tag = qio_channel_add_watch(
@@ -83,15 +84,16 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
}
-static void vncws_handshake_done(Object *source,
- Error *err,
+static void vncws_handshake_done(QIOTask *task,
gpointer user_data)
{
VncState *vs = user_data;
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err));
vnc_client_error(vs);
+ error_free(err);
} else {
VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
vnc_start_protocol(vs);
diff --git a/user-exec-stub.c b/user-exec-stub.c
new file mode 100644
index 0000000000..dbcf1ade9c
--- /dev/null
+++ b/user-exec-stub.c
@@ -0,0 +1,34 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qom/cpu.h"
+#include "sysemu/replay.h"
+
+void cpu_resume(CPUState *cpu)
+{
+}
+
+void qemu_init_vcpu(CPUState *cpu)
+{
+}
+
+/* User mode emulation does not support record/replay yet. */
+
+bool replay_exception(void)
+{
+ return true;
+}
+
+bool replay_has_exception(void)
+{
+ return false;
+}
+
+bool replay_interrupt(void)
+{
+ return true;
+}
+
+bool replay_has_interrupt(void)
+{
+ return false;
+}
diff --git a/util/bitmap.c b/util/bitmap.c
index 43ed011720..c1a84ca5e3 100644
--- a/util/bitmap.c
+++ b/util/bitmap.c
@@ -164,6 +164,8 @@ void bitmap_set(unsigned long *map, long start, long nr)
int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+ assert(start >= 0 && nr >= 0);
+
while (nr - bits_to_set >= 0) {
*p |= mask_to_set;
nr -= bits_to_set;
@@ -184,6 +186,8 @@ void bitmap_set_atomic(unsigned long *map, long start, long nr)
int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+ assert(start >= 0 && nr >= 0);
+
/* First word */
if (nr - bits_to_set > 0) {
atomic_or(p, mask_to_set);
@@ -221,6 +225,8 @@ void bitmap_clear(unsigned long *map, long start, long nr)
int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+ assert(start >= 0 && nr >= 0);
+
while (nr - bits_to_clear >= 0) {
*p &= ~mask_to_clear;
nr -= bits_to_clear;
@@ -243,6 +249,8 @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
unsigned long dirty = 0;
unsigned long old_bits;
+ assert(start >= 0 && nr >= 0);
+
/* First word */
if (nr - bits_to_clear > 0) {
old_bits = atomic_fetch_and(p, ~mask_to_clear);
diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c
index f2aacfc8b3..7e40252ade 100644
--- a/util/event_notifier-posix.c
+++ b/util/event_notifier-posix.c
@@ -90,15 +90,6 @@ int event_notifier_get_fd(const EventNotifier *e)
return e->rfd;
}
-int event_notifier_set_handler(EventNotifier *e,
- bool is_external,
- EventNotifierHandler *handler)
-{
- aio_set_fd_handler(iohandler_get_aio_context(), e->rfd, is_external,
- (IOHandler *)handler, NULL, NULL, e);
- return 0;
-}
-
int event_notifier_set(EventNotifier *e)
{
static const uint64_t value = 1;
diff --git a/util/event_notifier-win32.c b/util/event_notifier-win32.c
index de87df02d6..519fb59123 100644
--- a/util/event_notifier-win32.c
+++ b/util/event_notifier-win32.c
@@ -32,18 +32,6 @@ HANDLE event_notifier_get_handle(EventNotifier *e)
return e->event;
}
-int event_notifier_set_handler(EventNotifier *e,
- bool is_external,
- EventNotifierHandler *handler)
-{
- if (handler) {
- return qemu_add_wait_object(e->event, (IOHandler *)handler, e);
- } else {
- qemu_del_wait_object(e->event, (IOHandler *)handler, e);
- return 0;
- }
-}
-
int event_notifier_set(EventNotifier *e)
{
SetEvent(e->event);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index fe1d07aaef..7c120c45ce 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -38,6 +38,10 @@
# define AI_V4MAPPED 0
#endif
+#ifndef AI_NUMERICSERV
+# define AI_NUMERICSERV 0
+#endif
+
static int inet_getport(struct addrinfo *e)
{
@@ -110,8 +114,8 @@ NetworkAddressFamily inet_netfamily(int family)
* outside scope of this method and not currently handled by
* callers at all.
*/
-static int inet_ai_family_from_address(InetSocketAddress *addr,
- Error **errp)
+int inet_ai_family_from_address(InetSocketAddress *addr,
+ Error **errp)
{
if (addr->has_ipv6 && addr->has_ipv4 &&
!addr->ipv6 && !addr->ipv4) {
@@ -141,6 +145,9 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_PASSIVE;
+ if (saddr->has_numeric && saddr->numeric) {
+ ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+ }
ai.ai_family = inet_ai_family_from_address(saddr, &err);
ai.ai_socktype = SOCK_STREAM;
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index 37cd8ba3fe..73e3a0edf5 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -458,12 +458,6 @@ void qemu_thread_create(QemuThread *thread, const char *name,
if (err) {
error_exit(err, __func__);
}
- if (mode == QEMU_THREAD_DETACHED) {
- err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (err) {
- error_exit(err, __func__);
- }
- }
/* Leave signal handling to the iothread. */
sigfillset(&set);
@@ -476,6 +470,12 @@ void qemu_thread_create(QemuThread *thread, const char *name,
qemu_thread_set_name(thread, name);
}
+ if (mode == QEMU_THREAD_DETACHED) {
+ err = pthread_detach(thread->thread);
+ if (err) {
+ error_exit(err, __func__);
+ }
+ }
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
pthread_attr_destroy(&attr);
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index 178e0168a1..29c3e4dd85 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -497,8 +497,8 @@ HANDLE qemu_thread_get_handle(QemuThread *thread)
EnterCriticalSection(&data->cs);
if (!data->exited) {
- handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
- thread->tid);
+ handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME |
+ THREAD_SET_CONTEXT, FALSE, thread->tid);
} else {
handle = NULL;
}
diff --git a/vl.c b/vl.c
index c643d3ff3a..a260f30974 100644
--- a/vl.c
+++ b/vl.c
@@ -65,6 +65,7 @@ int main(int argc, char **argv)
#include "hw/bt.h"
#include "sysemu/watchdog.h"
#include "hw/smbios/smbios.h"
+#include "hw/acpi/acpi.h"
#include "hw/xen/xen.h"
#include "hw/qdev.h"
#include "hw/loader.h"
@@ -92,6 +93,7 @@ int main(int argc, char **argv)
#include "sysemu/cpus.h"
#include "migration/colo.h"
#include "sysemu/kvm.h"
+#include "sysemu/hax.h"
#include "qapi/qmp/qjson.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
@@ -1630,16 +1632,6 @@ void vm_state_notify(int running, RunState state)
}
}
-/* reset/shutdown handler */
-
-typedef struct QEMUResetEntry {
- QTAILQ_ENTRY(QEMUResetEntry) entry;
- QEMUResetHandler *func;
- void *opaque;
-} QEMUResetEntry;
-
-static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
- QTAILQ_HEAD_INITIALIZER(reset_handlers);
static int reset_requested;
static int shutdown_requested, shutdown_signal = -1;
static pid_t shutdown_pid;
@@ -1729,38 +1721,6 @@ static int qemu_debug_requested(void)
return r;
}
-void qemu_register_reset(QEMUResetHandler *func, void *opaque)
-{
- QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry));
-
- re->func = func;
- re->opaque = opaque;
- QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
-}
-
-void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
-{
- QEMUResetEntry *re;
-
- QTAILQ_FOREACH(re, &reset_handlers, entry) {
- if (re->func == func && re->opaque == opaque) {
- QTAILQ_REMOVE(&reset_handlers, re, entry);
- g_free(re);
- return;
- }
- }
-}
-
-void qemu_devices_reset(void)
-{
- QEMUResetEntry *re, *nre;
-
- /* reset all devices */
- QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
- re->func(re->opaque);
- }
-}
-
void qemu_system_reset(bool report)
{
MachineClass *mc;
@@ -1954,7 +1914,7 @@ static void main_loop(void)
int64_t ti;
#endif
do {
- nonblocking = !kvm_enabled() && !xen_enabled() && last_io > 0;
+ nonblocking = tcg_enabled() && last_io > 0;
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
@@ -3699,7 +3659,7 @@ int main(int argc, char **argv, char **envp)
if (!opts) {
exit(1);
}
- do_acpitable_option(opts);
+ acpi_table_add(opts, &error_fatal);
break;
case QEMU_OPTION_smbios:
opts = qemu_opts_parse_noisily(qemu_find_opts("smbios"),
@@ -3707,7 +3667,7 @@ int main(int argc, char **argv, char **envp)
if (!opts) {
exit(1);
}
- do_smbios_option(opts);
+ smbios_entry_add(opts, &error_fatal);
break;
case QEMU_OPTION_fwcfg:
opts = qemu_opts_parse_noisily(qemu_find_opts("fw_cfg"),
@@ -3720,6 +3680,10 @@ int main(int argc, char **argv, char **envp)
olist = qemu_find_opts("machine");
qemu_opts_parse_noisily(olist, "accel=kvm", false);
break;
+ case QEMU_OPTION_enable_hax:
+ olist = qemu_find_opts("machine");
+ qemu_opts_parse_noisily(olist, "accel=hax", false);
+ break;
case QEMU_OPTION_M:
case QEMU_OPTION_machine:
olist = qemu_find_opts("machine");
@@ -4414,8 +4378,8 @@ int main(int argc, char **argv, char **envp)
cpu_ticks_init();
if (icount_opts) {
- if (kvm_enabled() || xen_enabled()) {
- error_report("-icount is not allowed with kvm or xen");
+ if (!tcg_enabled()) {
+ error_report("-icount is not allowed with hardware virtualization");
exit(1);
}
configure_icount(icount_opts, &error_abort);
@@ -4551,6 +4515,10 @@ int main(int argc, char **argv, char **envp)
numa_post_machine_init();
+ if (hax_enabled()) {
+ hax_sync_vcpus();
+ }
+
if (qemu_opts_foreach(qemu_find_opts("fw_cfg"),
parse_fw_cfg, fw_cfg_find(), NULL) != 0) {
exit(1);
diff --git a/xen-mapcache.c b/xen-mapcache.c
index 8f3a592013..31debdfb2c 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -163,6 +163,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
err = g_malloc0(nb_pfn * sizeof (int));
if (entry->vaddr_base != NULL) {
+ ram_block_notify_remove(entry->vaddr_base, entry->size);
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);
@@ -188,6 +189,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
entry->valid_mapping = (unsigned long *) g_malloc0(sizeof(unsigned long) *
BITS_TO_LONGS(size >> XC_PAGE_SHIFT));
+ ram_block_notify_add(entry->vaddr_base, entry->size);
bitmap_zero(entry->valid_mapping, nb_pfn);
for (i = 0; i < nb_pfn; i++) {
if (!err[i]) {
@@ -397,6 +399,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
}
pentry->next = entry->next;
+ ram_block_notify_remove(entry->vaddr_base, entry->size);
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);