aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpu-defs.h3
-rw-r--r--cpu-exec.c29
-rw-r--r--cpus.c29
-rw-r--r--exec.c26
-rw-r--r--fpu/softfloat.h2
-rw-r--r--hax.h38
-rw-r--r--kvm.h7
-rw-r--r--qemu-options.hx11
-rw-r--r--target-i386/helper.c6
-rw-r--r--target-i386/translate.c9
-rw-r--r--vl-android.c27
11 files changed, 181 insertions, 6 deletions
diff --git a/cpu-defs.h b/cpu-defs.h
index f9294c3..000e86e 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -210,6 +210,7 @@ typedef struct CPUWatchpoint {
struct KVMState *kvm_state; \
struct kvm_run *kvm_run; \
int kvm_fd; \
- int kvm_vcpu_dirty;
+ int kvm_vcpu_dirty; \
+ struct hax_vcpu_state *hax_vcpu;
#endif
diff --git a/cpu-exec.c b/cpu-exec.c
index 92fae21..c6572f1 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -21,6 +21,7 @@
#include "disas.h"
#include "tcg.h"
#include "kvm.h"
+#include "hax.h"
#include "qemu-barrier.h"
#if !defined(CONFIG_SOFTMMU)
@@ -223,6 +224,23 @@ static void cpu_handle_debug_exception(CPUState *env)
volatile sig_atomic_t exit_request;
+/*
+ * Qemu emulation can happen because of MMIO or emulation mode,
+ * i.e. non-PG mode. For MMIO cases, the pending interrupt should not
+ * be emulated in qemu because MMIO is emulated for only one
+ * instruction now and then back to the HAX kernel module.
+ */
+int need_handle_intr_request(CPUState *env)
+{
+#ifdef CONFIG_HAX
+ if (!hax_enabled() || hax_vcpu_emulation_mode(env))
+ return env->interrupt_request;
+ return 0;
+#else
+ return env->interrupt_request;
+#endif
+}
+
int cpu_exec(CPUState *env1)
{
volatile host_reg_t saved_env_reg;
@@ -355,6 +373,11 @@ int cpu_exec(CPUState *env1)
}
}
+#ifdef CONFIG_HAX
+ if (hax_enabled() && !hax_vcpu_exec(env))
+ longjmp(env->jmp_env, 1);
+#endif
+
if (kvm_enabled()) {
kvm_cpu_exec(env);
longjmp(env->jmp_env, 1);
@@ -363,7 +386,7 @@ int cpu_exec(CPUState *env1)
next_tb = 0; /* force lookup of first TB */
for(;;) {
interrupt_request = env->interrupt_request;
- if (unlikely(interrupt_request)) {
+ if (unlikely(need_handle_intr_request(env))) {
if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
/* Mask out external interrupts for this step. */
interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
@@ -669,6 +692,10 @@ int cpu_exec(CPUState *env1)
}
}
env->current_tb = NULL;
+#ifdef CONFIG_HAX
+ if (hax_enabled() && hax_stop_emulation(env))
+ cpu_loop_exit();
+#endif
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
} /* for(;;) */
diff --git a/cpus.c b/cpus.c
index 470eb32..585a6b3 100644
--- a/cpus.c
+++ b/cpus.c
@@ -28,6 +28,7 @@
#include "gdbstub.h"
#include "dma.h"
#include "kvm.h"
+#include "hax.h"
#include "cpus.h"
@@ -191,6 +192,10 @@ void qemu_init_vcpu(void *_env)
if (kvm_enabled())
kvm_init_vcpu(env);
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_init_vcpu(env);
+#endif
return;
}
@@ -222,7 +227,27 @@ void qemu_notify_event(void)
if (env->kqemu_enabled)
kqemu_cpu_interrupt(env);
#endif
+ /*
+ * This is mainly for the Windows host, where the timer may be in
+ * a different thread with vcpu. Thus the timer function needs to
+ * notify the vcpu thread of more than simply cpu_exit. If env is
+ * not NULL, it means that the vcpu is in execute state, we need
+ * only to set the flags. If the guest is in execute state, the
+ * HAX kernel module will exit to qemu. If env is NULL, vcpu is
+ * in main_loop_wait, and we need a event to notify it.
+ */
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_raise_event(env);
+ } else {
+#ifdef _WIN32
+ if(hax_enabled())
+ SetEvent(qemu_event_handle);
+#endif
}
+#else
+ }
+#endif
}
void qemu_mutex_lock_iothread(void)
@@ -361,7 +386,7 @@ void qemu_cpu_kick(void *_env)
{
CPUState *env = _env;
qemu_cond_broadcast(env->halt_cond);
- if (kvm_enabled())
+ if (kvm_enabled() || hax_enabled())
qemu_thread_signal(env->thread, SIGUSR1);
}
@@ -425,7 +450,7 @@ static void qemu_signal_lock(unsigned int msecs)
void qemu_mutex_lock_iothread(void)
{
- if (kvm_enabled()) {
+ if (kvm_enabled() || hax_enabled()) {
qemu_mutex_lock(&qemu_fair_mutex);
qemu_mutex_lock(&qemu_global_mutex);
qemu_mutex_unlock(&qemu_fair_mutex);
diff --git a/exec.c b/exec.c
index f650a9e..b8a473f 100644
--- a/exec.c
+++ b/exec.c
@@ -39,6 +39,7 @@
#include "hw/hw.h"
#include "osdep.h"
#include "kvm.h"
+#include "hax.h"
#include "qemu-timer.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
@@ -2379,6 +2380,10 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
if (kvm_enabled())
kvm_set_phys_mem(start_addr, size, phys_offset);
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_set_phys_mem(start_addr, size, phys_offset);
+#endif
if (phys_offset == IO_MEM_UNASSIGNED) {
region_offset = start_addr;
@@ -2561,6 +2566,27 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#else
new_block->host = qemu_vmalloc(size);
+
+#ifdef CONFIG_HAX
+ /*
+ * In HAX, qemu allocates the virtual address, and HAX kernel
+ * module populates the region with physical memory. Currently
+ * we don’t populate guest memory on demand, thus we should
+ * make sure that sufficient amount of memory is available in
+ * advance.
+ */
+ if (hax_enabled())
+ {
+ int ret;
+ ret = hax_populate_ram((uint64_t)new_block->host, size);
+ if (ret < 0)
+ {
+ fprintf(stderr, "Hax failed to populate ram\n");
+ exit(-1);
+ }
+ }
+#endif
+
#endif
#ifdef MADV_MERGEABLE
madvise(new_block->host, size, MADV_MERGEABLE);
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 58c9b7b..070fb56 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -57,7 +57,7 @@ typedef uint8_t flag;
typedef uint8_t uint8;
typedef int8_t int8;
#ifndef _AIX
-typedef int uint16;
+typedef int16_t uint16;
typedef int int16;
#endif
typedef unsigned int uint32;
diff --git a/hax.h b/hax.h
new file mode 100644
index 0000000..9af61ce
--- /dev/null
+++ b/hax.h
@@ -0,0 +1,38 @@
+/* header to be included in non-HAX-specific code */
+#ifndef _HAX_H
+#define _HAX_H
+
+#include "config.h"
+#include "qemu-common.h"
+#include "cpu.h"
+
+extern int hax_disabled;
+struct hax_vcpu_state;
+
+#ifdef CONFIG_HAX
+int hax_enabled(void);
+int hax_init(int smp_cpus);
+int hax_init_vcpu(CPUState *env);
+/* Execute vcpu in non-root mode */
+int hax_vcpu_exec(CPUState *env);
+/* Sync vcpu state with HAX driver */
+int hax_sync_vcpus(void);
+void hax_vcpu_sync_state(CPUState *env, int modified);
+int hax_populate_ram(uint64_t va, uint32_t size);
+int hax_set_phys_mem(target_phys_addr_t start_addr,
+ ram_addr_t size, ram_addr_t phys_offset);
+/* Check if QEMU need emulate guest execution */
+int hax_vcpu_emulation_mode(CPUState *env);
+int hax_stop_emulation(CPUState *env);
+int hax_stop_translate(CPUState *env);
+int hax_arch_get_registers(CPUState *env);
+void hax_raise_event(CPUState *env);
+void hax_reset_vcpu_state(void *opaque);
+
+#include "target-i386/hax-interface.h"
+
+#else
+#define hax_enabled() (0)
+#endif
+
+#endif
diff --git a/kvm.h b/kvm.h
index d390dae..2ef89c7 100644
--- a/kvm.h
+++ b/kvm.h
@@ -136,7 +136,9 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
int reg);
/* generic hooks - to be moved/refactored once there are more users */
-
+#ifdef CONFIG_HAX
+void hax_vcpu_sync_state(CPUState *env, int modified);
+#endif
static inline void cpu_synchronize_state(CPUState *env, int modified)
{
if (kvm_enabled()) {
@@ -145,6 +147,9 @@ static inline void cpu_synchronize_state(CPUState *env, int modified)
else
kvm_arch_get_registers(env);
}
+#ifdef CONFIG_HAX
+ hax_vcpu_sync_state(env, modified);
+#endif
}
#endif
diff --git a/qemu-options.hx b/qemu-options.hx
index 880025e..b2ecf1b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1359,6 +1359,17 @@ Enable KVM full virtualization support. This option is only available
if KVM support is enabled when compiling.
ETEXI
+DEF("disable-hax", 0, QEMU_OPTION_disable_hax, \
+ "-disable-hax Disable HAX full virtualization support\n")
+STEXI
+@item -disable-hax
+Disable HAX (Hardware-based Acceleration eXecution) support. When HAX
+support is detected, the emulator will enable it by default. This
+option will disable the default action. HAX is supported only on Mac OS X
+and Windows platforms (if VT is present), and it does not conflict
+with KVM.
+ETEXI
+
#ifdef CONFIG_XEN
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
"-xen-domid id specify xen guest domain id\n")
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 6d0f18c..7e2ac4e 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -28,6 +28,7 @@
#include "exec-all.h"
#include "qemu-common.h"
#include "kvm.h"
+#include "hax.h"
//#define DEBUG_MMU
@@ -662,6 +663,11 @@ void cpu_dump_state(CPUState *env, FILE *f,
if (kvm_enabled())
kvm_arch_get_registers(env);
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_arch_get_registers(env);
+#endif
+
eflags = env->eflags;
#ifdef TARGET_X86_64
if (env->hflags & HF_CS64_MASK) {
diff --git a/target-i386/translate.c b/target-i386/translate.c
index f4e295f..e05cdac 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -32,6 +32,7 @@
#include "helper.h"
#define GEN_HELPER 1
#include "helper.h"
+#include "hax.h"
#define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02
@@ -7714,6 +7715,14 @@ static inline void gen_intermediate_code_internal(CPUState *env,
pc_ptr = disas_insn(dc, pc_ptr);
num_insns++;
+#ifdef CONFIG_HAX
+ if (hax_enabled() && hax_stop_translate(env))
+ {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
+#endif
/* stop translation if indicated */
if (dc->is_jmp)
break;
diff --git a/vl-android.c b/vl-android.c
index 8f439ac..8071052 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -198,6 +198,7 @@ int qemu_main(int argc, char **argv, char **envp);
#include "audio/audio.h"
#include "migration.h"
#include "kvm.h"
+#include "hax.h"
#ifdef CONFIG_KVM
#include "kvm-android.h"
#endif
@@ -298,6 +299,7 @@ int smp_cpus = 1;
const char *vnc_display;
int acpi_enabled = 1;
int no_hpet = 0;
+int hax_disabled = 0;
int no_virtio_balloon = 0;
int fd_bootchk = 1;
int no_reboot = 0;
@@ -1989,6 +1991,11 @@ static void main_loop(void)
qemu_cond_broadcast(&qemu_system_cond);
#endif
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_sync_vcpus();
+#endif
+
for (;;) {
do {
#ifdef CONFIG_PROFILER
@@ -3357,7 +3364,11 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_nand:
nand_add_dev(optarg);
break;
+
#endif
+ case QEMU_OPTION_disable_hax:
+ hax_disabled = 1;
+ break;
case QEMU_OPTION_android_ports:
android_op_ports = (char*)optarg;
break;
@@ -4127,6 +4138,17 @@ int main(int argc, char **argv, char **envp)
}
}
+#ifdef CONFIG_HAX
+ if (!hax_disabled)
+ {
+ int ret;
+
+ ret = hax_init(smp_cpus);
+ fprintf(stderr, "HAX is %s and emulator runs in %s mode\n",
+ !ret ? "working" :"not working", !ret ? "fast virt" : "emulation");
+ }
+#endif
+
if (monitor_device) {
monitor_hd = qemu_chr_open("monitor", monitor_device, NULL);
if (!monitor_hd) {
@@ -4259,6 +4281,11 @@ int main(int argc, char **argv, char **envp)
}
}
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_sync_vcpus();
+#endif
+
/* init USB devices */
if (usb_enabled) {
for(i = 0; i < usb_devices_index; i++) {