Plumb the HAXM-based hardware acceleration support

Use the Intel HAX is kernel-based hardware acceleration module for
Windows (similar to KVM on Linux).

Based on the "target/i386: Add Intel HAX to android emulator" patch
from David Chou <david.j.chou@intel.com>

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
Message-Id: <7b9cae28a0c379ab459c7a8545c9a39762bd394f.1484045952.git.vpalatin@chromium.org>
[Drop hax_populate_ram stub. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Vincent Palatin 2017-01-10 11:59:57 +01:00 committed by Paolo Bonzini
parent 47c1c8c12f
commit b0cb0a66d6
11 changed files with 141 additions and 12 deletions

View File

@ -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

18
configure vendored
View File

@ -228,6 +228,7 @@ vhost_net="no"
vhost_scsi="no"
vhost_vsock="no"
kvm="no"
hax="no"
rdma=""
gprof="no"
debug_tcg="no"
@ -561,6 +562,7 @@ CYGWIN*)
;;
MINGW32*)
mingw32="yes"
hax="yes"
audio_possible_drivers="dsound sdl"
if check_include dsound.h; then
audio_drv_list="dsound"
@ -610,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"
@ -919,6 +922,10 @@ for opt do
;;
--enable-kvm) kvm="yes"
;;
--disable-hax) hax="no"
;;
--enable-hax) hax="yes"
;;
--disable-tcg-interpreter) tcg_interpreter="no"
;;
--enable-tcg-interpreter) tcg_interpreter="yes"
@ -1367,6 +1374,7 @@ disabled with --disable-FEATURE, default is enabled if available:
fdt fdt device tree
bluez bluez stack connectivity
kvm KVM acceleration support
hax HAX acceleration support
rdma RDMA-based migration support
vde support for vde network
netmap support for netmap network
@ -5056,6 +5064,7 @@ echo "Linux AIO support $linux_aio"
echo "ATTR/XATTR support $attr"
echo "Install blobs $blobs"
echo "KVM support $kvm"
echo "HAX support $hax"
echo "RDMA support $rdma"
echo "TCG interpreter $tcg_interpreter"
echo "fdt support $fdt"
@ -6039,6 +6048,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

78
cpus.c
View File

@ -35,6 +35,7 @@
#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"
@ -1221,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
@ -1236,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
}
@ -1259,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);
}
}
@ -1419,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];
@ -1469,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 {

View File

@ -23,11 +23,6 @@ int hax_sync_vcpus(void)
return 0;
}
int hax_populate_ram(uint64_t va, uint32_t size)
{
return -ENOSYS;
}
int hax_init_vcpu(CPUState *cpu)
{
return -ENOSYS;

View File

@ -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;

View File

@ -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);

View File

@ -20,6 +20,9 @@ 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)
@ -27,6 +30,9 @@ 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)
@ -34,6 +40,9 @@ 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 */

View File

@ -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,

View File

@ -5,3 +5,7 @@ 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

View File

@ -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;
}

15
vl.c
View File

@ -93,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"
@ -1913,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
@ -3679,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");
@ -4373,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);
@ -4510,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);