diff options
author | Jun Nakajima <jun.nakajima@intel.com> | 2011-12-17 19:13:25 -0800 |
---|---|---|
committer | Jiang, Yunhong <yunhong.jiang@intel.com> | 2012-01-17 06:15:06 +0800 |
commit | a381ef07088ce479610129e37bfef42538f397da (patch) | |
tree | 523581dd6c18ddd42bb3980483778a3dd5d6154d | |
parent | e7e8b324a626a4ba112c3ad47d54eb9cfd3025ba (diff) | |
download | external_qemu-a381ef07088ce479610129e37bfef42538f397da.zip external_qemu-a381ef07088ce479610129e37bfef42538f397da.tar.gz external_qemu-a381ef07088ce479610129e37bfef42538f397da.tar.bz2 |
Changes to existing files to add HAX support
HAX (Hardware-based Accelerated eXecution) employes hardware virtualization
technology to boost performance of the Android emulator on Mac OS X or Windows
hosts.
This changeset includes the changes required to the existing files. To pass
the compilation, hax.h is added, but CONFIG_HAX is disabled so that no
real changes added.
Change-Id: Ifa5777e8788e6698747c1ec4cd91315161c2ca0b
Signed-off-by: Zhang, Xiantao <xiantao.zhang@intel.com>
Signed-off-by: Xin, Xiaohui <xiaohui.xin@intel.com>
Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com>
Signed-off-by: Nakajima, Jun <jun.nakajima@intel.com>
-rw-r--r-- | cpu-defs.h | 3 | ||||
-rw-r--r-- | cpu-exec.c | 29 | ||||
-rw-r--r-- | cpus.c | 29 | ||||
-rw-r--r-- | exec.c | 26 | ||||
-rw-r--r-- | fpu/softfloat.h | 2 | ||||
-rw-r--r-- | hax.h | 38 | ||||
-rw-r--r-- | kvm.h | 7 | ||||
-rw-r--r-- | qemu-options.hx | 11 | ||||
-rw-r--r-- | target-i386/helper.c | 6 | ||||
-rw-r--r-- | target-i386/translate.c | 9 | ||||
-rw-r--r-- | vl-android.c | 27 |
11 files changed, 181 insertions, 6 deletions
@@ -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 @@ -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(;;) */ @@ -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); @@ -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; @@ -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 @@ -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++) { |