--- /dev/null
+/*
+ * HAX common code for both windows and darwin
+ * some code from KVM side
+ */
+
+#include "target-i386/hax-i386.h"
+
+#define HAX_EMUL_ONE 0x1
+#define HAX_EMUL_REAL 0x2
+#define HAX_EMUL_HLT 0x4
+#define HAX_EMUL_EXITLOOP 0x5
+
+#define HAX_EMULATE_STATE_MMIO 0x1
+#define HAX_EMULATE_STATE_REAL 0x2
+#define HAX_EMULATE_STATE_NONE 0x3
+#define HAX_EMULATE_STATE_INITIAL 0x4
+
+struct hax_state hax_global;
+
+int hax_support = -1;
+
+/* Called after hax_init */
+int hax_enabled(void)
+{
+ return (!hax_disabled && hax_support);
+}
+
+/* Currently non-PG modes are emulated by QEMU */
+int hax_vcpu_emulation_mode(CPUState *env)
+{
+ return !(env->cr[0] & CR0_PG_MASK);
+}
+
+static int hax_prepare_emulation(CPUState *env)
+{
+ /* Flush all emulation states */
+ tlb_flush(env, 1);
+ tb_flush(env);
+ /* Sync the vcpu state from hax kernel module */
+ hax_vcpu_sync_state(env, 0);
+ return 0;
+}
+
+/*
+ * Check whether to break the translation block loop
+ * break tbloop after one MMIO emulation, or after finish emulation mode
+ */
+static int hax_stop_tbloop(CPUState *env)
+{
+ switch (env->hax_vcpu->emulation_state)
+ {
+ case HAX_EMULATE_STATE_MMIO:
+ return 1;
+ break;
+ case HAX_EMULATE_STATE_INITIAL:
+ case HAX_EMULATE_STATE_REAL:
+ if (!hax_vcpu_emulation_mode(env))
+ return 1;
+ break;
+ default:
+ dprint("Invalid emulation state in hax_sto_tbloop state %x\n",
+ env->hax_vcpu->emulation_state);
+ break;
+ }
+
+ return 0;
+}
+
+int hax_stop_emulation(CPUState *env)
+{
+ if (hax_stop_tbloop(env))
+ {
+ env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_NONE;
+ /*
+ * QEMU emulation changes vcpu state,
+ * Sync the vcpu state to HAX kernel module
+ */
+ hax_vcpu_sync_state(env, 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+int hax_stop_translate(CPUState *env)
+{
+ struct hax_vcpu_state *vstate;
+
+ vstate = env->hax_vcpu;
+ assert(vstate->emulation_state);
+ if (vstate->emulation_state == HAX_EMULATE_STATE_MMIO )
+ return 1;
+
+ return 0;
+}
+
+int valid_hax_tunnel_size(uint16_t size)
+{
+ return size >= sizeof(struct hax_tunnel);
+}
+
+hax_fd hax_vcpu_get_fd(CPUState *env)
+{
+ struct hax_vcpu_state *vcpu = env->hax_vcpu;
+ if (!vcpu)
+ return HAX_INVALID_FD;
+ return vcpu->fd;
+}
+
+/* Current version */
+uint32_t hax_cur_version = 0x1;
+/* Least HAX kernel version */
+uint32_t hax_lest_version = 0x1;
+
+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)
+ dprint("VTX feature is not enabled. which will cause HAX driver not working.\n");
+ else if (cap->winfo & HAX_CAP_FAILREASON_NX)
+ dprint("NX feature is not enabled, which will cause HAX driver not working.\n");
+ return -ENXIO;
+ }
+
+ if (cap->wstatus & HAX_CAP_MEMQUOTA)
+ {
+ if (cap->mem_quota < hax->mem_quota)
+ {
+ dprint("The memory needed by this VM 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_lest_version > version.cur_version) ||
+ (hax_cur_version < 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)
+ {
+ dprint("vcpu %x created failed, vm is null\n", id);
+ return -1;
+ }
+
+ if (hax_global.vm->vcpus[id])
+ {
+ dprint("vcpu %x allocated already\n", id);
+ return 0;
+ }
+
+ vcpu = g_malloc(sizeof(struct hax_vcpu_state));
+ if (!vcpu)
+ {
+ dprint("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)
+ {
+ dprint("Failed to create vcpu %x\n", id);
+ goto error;
+ }
+
+ vcpu->fd = hax_host_open_vcpu(hax_global.vm->id, id);
+ if (hax_invalid_fd(vcpu->fd))
+ {
+ dprint("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)
+ {
+ dprint("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 *env)
+{
+ struct hax_vcpu_state *vcpu = env->hax_vcpu;
+
+ if (!hax_global.vm)
+ {
+ dprint("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 *env)
+{
+ int ret;
+
+ ret = hax_vcpu_create(env->cpu_index);
+ if (ret < 0)
+ {
+ dprint("Failed to create HAX vcpu\n");
+ exit(-1);
+ }
+
+ env->hax_vcpu = hax_global.vm->vcpus[env->cpu_index];
+ env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_INITIAL;
+ env->hax_vcpu_dirty = 1;
+ qemu_register_reset(hax_reset_vcpu_state, env);
+
+ return ret;
+}
+
+struct hax_vm *hax_vm_create(struct hax_state *hax)
+{
+ struct hax_vm *vm;
+ int vm_id = 0, ret;
+ char *vm_name = NULL;
+
+ 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) {
+ dprint("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))
+ {
+ dprint("Open the vm devcie error:%s\n", vm_name);
+ goto error;
+ }
+
+ hax->vm = vm;
+ dprint("End of VM create, id %d\n", vm->id);
+ 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])
+ {
+ dprint("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_client_set_memory(struct CPUPhysMemoryClient *client,
+ target_phys_addr_t start_addr,
+ ram_addr_t size, ram_addr_t phys_offset,
+ bool log_dirty)
+{
+ hax_set_phys_mem(start_addr, size, phys_offset);
+}
+
+/* currently we fake the dirty bitmap sync, always dirty */
+
+static int hax_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
+ target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr)
+{
+ ram_addr_t size = end_addr - start_addr;
+ ram_addr_t ram_addr;
+ unsigned long page_number, addr, c;
+ unsigned int len = ((size /TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) /
+ HOST_LONG_BITS;
+ unsigned long bitmap[len];
+ unsigned long map;
+ int i, j;
+
+
+ for (i = 0; i < len; i++) {
+ map = bitmap[i] = 1;
+ c = leul_to_cpu(bitmap[i]);
+ do {
+ j = ffsl(c) - 1;
+ c &= ~(1ul << j);
+ page_number = i * HOST_LONG_BITS + j;
+ addr = page_number * TARGET_PAGE_SIZE;
+ ram_addr = cpu_get_physical_page_desc(addr);
+ cpu_physical_memory_set_dirty(ram_addr);
+ } while (c != 0);
+ }
+
+ return 0;
+}
+
+static int hax_client_migration_log(struct CPUPhysMemoryClient *client,
+ int enable)
+{
+ return 0;
+}
+
+static int hax_log_start(CPUPhysMemoryClient *client,
+ target_phys_addr_t phys_addr, ram_addr_t size)
+{
+ return 0;
+}
+
+static int hax_log_stop(CPUPhysMemoryClient *client,
+ target_phys_addr_t phys_addr, ram_addr_t size)
+{
+ return 0;
+}
+
+static CPUPhysMemoryClient hax_cpu_phys_memory_client = {
+ .set_memory = hax_client_set_memory,
+ .sync_dirty_bitmap = hax_client_sync_dirty_bitmap,
+ .migration_log = hax_client_migration_log,
+ .log_start = hax_log_start,
+ .log_stop = hax_log_stop,
+};
+
+static void hax_handle_interrupt(CPUState *env, int mask)
+{
+ env->interrupt_request |= mask;
+
+ if (!qemu_cpu_is_self(env)) {
+ qemu_cpu_kick(env);
+ }
+}
+
+int hax_pre_init(ram_addr_t ram_size)
+{
+ struct hax_state *hax = NULL;
+
+ dprint("hax_disabled %d\n", hax_disabled);
+ if (hax_disabled)
+ return 0;
+ hax = &hax_global;
+ memset(hax, 0, sizeof(struct hax_state));
+ hax->mem_quota = ram_size;
+ dprint("ram_size %lx\n", ram_size);
+ return 0;
+}
+
+int hax_init(void)
+{
+ struct hax_state *hax = NULL;
+ int ret;
+
+ hax_support = 0;
+
+ hax = &hax_global;
+
+
+ hax->fd = hax_mod_open();
+ if (hax_invalid_fd(hax->fd))
+ {
+ hax->fd = 0;
+ ret = -ENODEV;
+ goto error;
+ }
+
+ if (hax_get_capability(hax))
+ {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!hax_version_support(hax))
+ {
+ dprint("Incompat Hax version. Qemu current version %x ", hax_cur_version );
+ dprint("requires least HAX version %x\n", hax_lest_version);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ hax->vm = hax_vm_create(hax);
+ if (!hax->vm)
+ {
+ dprint("Failed to create HAX VM\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ cpu_register_phys_memory_client(&hax_cpu_phys_memory_client);
+
+ hax_support = 1;
+
+ return 0;
+error:
+ if (hax->vm)
+ hax_vm_destroy(hax->vm);
+ if (hax->fd)
+ hax_mod_close(hax);
+
+ return ret;
+}
+
+int hax_handle_io(CPUState *env, uint32_t df, uint16_t port, int direction,
+ int size, int count, void *buffer)
+{
+ uint8_t *ptr;
+ int i;
+
+ if (!df)
+ ptr = (uint8_t *)buffer;
+ else
+ ptr = buffer + size * count - size;
+ for (i = 0; i < count; i++)
+ {
+ if (direction == HAX_EXIT_IO_IN) {
+ switch (size) {
+ case 1:
+ stb_p(ptr, cpu_inb(port));
+ break;
+ case 2:
+ stw_p(ptr, cpu_inw(port));
+ break;
+ case 4:
+ stl_p(ptr, cpu_inl(port));
+ break;
+ }
+ } else {
+ switch (size) {
+ case 1:
+ cpu_outb(port, ldub_p(ptr));
+ break;
+ case 2:
+ cpu_outw(port, lduw_p(ptr));
+ break;
+ case 4:
+ cpu_outl(port, ldl_p(ptr));
+ break;
+ }
+ }
+ if (!df)
+ ptr += size;
+ else
+ ptr -= size;
+ }
+
+ return 0;
+}
+
+static int hax_vcpu_interrupt(CPUState *env)
+{
+ struct hax_vcpu_state *vcpu = env->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 &&
+ (env->interrupt_request & CPU_INTERRUPT_HARD))
+ {
+ int irq;
+
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ irq = cpu_get_pic_interrupt(env);
+ if (irq >= 0) {
+ hax_inject_interrupt(env, irq);
+ }
+ }
+
+ /* 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 ((env->interrupt_request & CPU_INTERRUPT_HARD))
+ ht->request_interrupt_window = 1;
+ else
+ ht->request_interrupt_window = 0;
+ return 0;
+}
+
+void hax_raise_event(CPUState *env)
+{
+ struct hax_vcpu_state *vcpu = env->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 or guest
+ * enter emulation mode (non-PG mode)
+ * 3. Guest execute HLT
+ * 4. Qemu have Signal/event pending
+ * 5. An unknown VMX exit happens
+ */
+extern void qemu_system_reset_request(void);
+static int hax_vcpu_hax_exec(CPUState *env)
+{
+ int ret = 0;
+ struct hax_vcpu_state *vcpu = env->hax_vcpu;
+ struct hax_tunnel *ht = vcpu->tunnel;
+
+ if (hax_vcpu_emulation_mode(env))
+ {
+ dprint("Trying to vcpu execute at eip:%lx\n", env->eip);
+ return HAX_EMUL_EXITLOOP;
+ }
+
+
+ hax_cpu_synchronize_state(env);
+
+ do {
+ int hax_ret;
+
+
+ if (env->exit_request) {
+ ret = HAX_EMUL_EXITLOOP ;
+ break;
+ }
+
+ if (env->hax_vcpu_dirty) {
+ hax_vcpu_sync_state(env, 1);
+ env->hax_vcpu_dirty = 0;
+ }
+
+ hax_vcpu_interrupt(env);
+
+ hax_ret = hax_vcpu_run(vcpu);
+
+ /* Simply continue the vcpu_run if system call interrupted */
+ if (hax_ret == -EINTR || hax_ret == -EAGAIN) {
+ dprint("io window interrupted\n");
+ continue;
+ }
+
+ if (hax_ret < 0)
+ {
+ dprint("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_MMIO:
+ ret = HAX_EMUL_ONE;
+ break;
+ case HAX_EXIT_REAL:
+ ret = HAX_EMUL_REAL;
+ break;
+ /* Guest state changed, currently only for shutdown */
+ case HAX_EXIT_STATECHANGE:
+ dprint("VCPU shutdown request\n");
+ qemu_system_reset_request();
+ hax_prepare_emulation(env);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ ret = HAX_EMUL_EXITLOOP;
+ break;
+ case HAX_EXIT_UNKNOWN_VMEXIT:
+ dprint("Unknown VMX exit %x from guest\n", ht->_exit_reason);
+ qemu_system_reset_request();
+ hax_prepare_emulation(env);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ ret = HAX_EMUL_EXITLOOP;
+ break;
+ case HAX_EXIT_HLT:
+ if (!(env->interrupt_request & CPU_INTERRUPT_HARD) &&
+ !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
+ /* hlt instruction with interrupt disabled is shutdown */
+ env->eflags |= IF_MASK;
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+ ret = HAX_EMUL_HLT;
+ }
+ break;
+ /* these situation will continue to hax module */
+ case HAX_EXIT_INTERRUPT:
+ case HAX_EXIT_PAUSED:
+ break;
+ default:
+ dprint("Unknow exit %x from hax\n", ht->_exit_status);
+ qemu_system_reset_request();
+ hax_prepare_emulation(env);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ ret = HAX_EMUL_EXITLOOP;
+ break;
+ }
+ }while (!ret);
+
+ if (env->exit_request) {
+ env->exit_request = 0;
+ env->exception_index = EXCP_INTERRUPT;
+ }
+ return ret;
+}
+
+static void do_hax_cpu_synchronize_state(void *_env)
+{
+ CPUState *env = _env;
+ if (!env->hax_vcpu_dirty) {
+ hax_vcpu_sync_state(env, 0);
+ env->hax_vcpu_dirty = 1;
+ }
+}
+
+void hax_cpu_synchronize_state(CPUState *env)
+{
+ if (!env->hax_vcpu_dirty) {
+ run_on_cpu(env, do_hax_cpu_synchronize_state, env);
+ }
+}
+
+void hax_cpu_synchronize_post_reset(CPUState *env)
+{
+ hax_vcpu_sync_state(env, 1);
+ env->hax_vcpu_dirty = 0;
+}
+
+void hax_cpu_synchronize_post_init(CPUState *env)
+{
+ hax_vcpu_sync_state(env, 1);
+ env->hax_vcpu_dirty = 0;
+}
+
+/*
+ * return 1 when need emulate, 0 when need exit loop
+ */
+int hax_vcpu_exec(CPUState *env)
+{
+ int next = 0, ret = 0;
+ struct hax_vcpu_state *vcpu;
+
+ if (env->hax_vcpu->emulation_state != HAX_EMULATE_STATE_NONE)
+ return 1;
+
+ vcpu = env->hax_vcpu;
+ next = hax_vcpu_hax_exec(env);
+ switch (next)
+ {
+ case HAX_EMUL_ONE:
+ ret = 1;
+ env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_MMIO;
+ hax_prepare_emulation(env);
+ break;
+ case HAX_EMUL_REAL:
+ ret = 1;
+ env->hax_vcpu->emulation_state =
+ HAX_EMULATE_STATE_REAL;
+ hax_prepare_emulation(env);
+ break;
+ case HAX_EMUL_HLT:
+ case HAX_EMUL_EXITLOOP:
+ break;
+ default:
+ dprint("Unknown hax vcpu exec return %x\n", next);
+ abort();
+ }
+
+ return ret;
+}
+
+#define HAX_RAM_INFO_ROM 0x1
+
+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(CPUState *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(CPUState *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(CPUState *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;
+ }
+ }
+ env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+ return 0;
+}
+
+static int hax_sync_vcpu_register(CPUState *env, int set)
+{
+ struct vcpu_state_t regs;
+ int ret;
+ memset(®s, 0, sizeof(struct vcpu_state_t));
+
+ if (!set)
+ {
+ ret = hax_sync_vcpu_state(env, ®s, 0);
+ if (ret < 0)
+ return -1;
+ }
+
+ /*generic register */
+ hax_getput_reg(®s._rax, &env->regs[R_EAX], set);
+ hax_getput_reg(®s._rbx, &env->regs[R_EBX], set);
+ hax_getput_reg(®s._rcx, &env->regs[R_ECX], set);
+ hax_getput_reg(®s._rdx, &env->regs[R_EDX], set);
+ hax_getput_reg(®s._rsi, &env->regs[R_ESI], set);
+ hax_getput_reg(®s._rdi, &env->regs[R_EDI], set);
+ hax_getput_reg(®s._rsp, &env->regs[R_ESP], set);
+ hax_getput_reg(®s._rbp, &env->regs[R_EBP], set);
+
+ hax_getput_reg(®s._rflags, &env->eflags, set);
+ hax_getput_reg(®s._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, ®s);
+ }
+ 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, ®s);
+ }
+
+ if (set)
+ {
+ ret = hax_sync_vcpu_state(env, ®s, 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(CPUState *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;
+ 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;
+ }
+ }
+
+ return 0;
+}
+
+static int hax_set_msrs(CPUState *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);
+ md.nr_msr = n;
+ md.done = 0;
+
+ return hax_sync_msr(env, &md, 1);
+
+}
+
+static int hax_get_fpu(CPUState *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));
+
+ memcpy(env->xmm_regs, fpu.mmx_1, sizeof(fpu.mmx_1));
+ memcpy((XMMReg *)(env->xmm_regs) + 8, fpu.mmx_2, sizeof(fpu.mmx_2));
+ env->mxcsr = fpu.mxcsr;
+
+ return 0;
+}
+
+static int hax_set_fpu(CPUState *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));
+ memcpy(fpu.mmx_1, env->xmm_regs, sizeof (fpu.mmx_1));
+ memcpy(fpu.mmx_2, (XMMReg *)(env->xmm_regs) + 8, sizeof (fpu.mmx_2));
+
+ fpu.mxcsr = env->mxcsr;
+
+ return hax_sync_fpu(env, &fpu, 1);
+}
+
+int hax_arch_get_registers(CPUState *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(CPUState *env)
+{
+ int ret;
+ ret = hax_sync_vcpu_register(env, 1);
+
+ if (ret < 0)
+ {
+ dprint("Failed to sync vcpu reg\n");
+ return ret;
+ }
+ ret = hax_set_fpu(env);
+ if (ret < 0)
+ {
+ dprint("FPU failed\n");
+ return ret;
+ }
+ ret = hax_set_msrs(env);
+ if (ret < 0)
+ {
+ dprint("MSR failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void hax_vcpu_sync_state(CPUState *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 *env;
+
+ env = first_cpu;
+ if (!env)
+ return 0;
+
+ for (; env != NULL; env = env->next_cpu) {
+ int ret;
+
+ ret = hax_arch_set_registers(env);
+ if (ret < 0)
+ {
+ dprint("Failed to sync HAX vcpu context\n");
+ exit(1);
+ }
+ }
+ }
+
+ return 0;
+}
+void hax_reset_vcpu_state(void *opaque)
+{
+ CPUState *env = opaque;
+ for (env = first_cpu; env != NULL; env = env->next_cpu)
+ {
+ dprint("*********ReSet hax_vcpu->emulation_state \n");
+ env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_INITIAL;
+ env->hax_vcpu->tunnel->user_event_pending = 0;
+ env->hax_vcpu->tunnel->ready_for_interrupt_injection = 0;
+
+ }
+
+}
+
+
--- /dev/null
+#include "target-i386/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)
+ {
+ dprint("Failed to open the HAX device!\n");
+ errNum = GetLastError();
+ if (errNum == ERROR_FILE_NOT_FOUND)
+ return -1;
+ return -2;
+ }
+ *fd = hDevice;
+ dprint("device fd:%d\n", *fd);
+ return 0;
+}
+
+/* This need changes after more investigation on driver loading*/
+hax_fd hax_mod_open(void)
+{
+ int ret;
+ hax_fd fd;
+
+ ret = hax_open_device(&fd);
+ if (ret != 0)
+ dprint("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)
+ {
+ dprint("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) {
+ dprint("Failed to allocate %x memory\n", size);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/*
+ * 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_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t phys_offset)
+{
+ struct hax_set_ram_info info, *pinfo = &info;
+ ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+ HANDLE hDeviceVM;
+ DWORD dSize = 0;
+ int ret = 0;
+
+ /* We only care for the RAM and ROM */
+ if (flags >= IO_MEM_UNASSIGNED)
+ return 0;
+
+ if ( (start_addr & ~TARGET_PAGE_MASK) || (size & ~TARGET_PAGE_MASK))
+ {
+ dprint(
+ "set_phys_mem %x %lx requires page aligned addr and size\n",
+ start_addr, size);
+ return -1;
+ }
+
+ info.pa_start = start_addr;
+ info.size = size;
+ info.va = (uint64_t)qemu_get_ram_ptr(phys_offset);
+ info.flags = (flags & IO_MEM_ROM) ? 1 : 0;
+
+ hDeviceVM = hax_global.vm->fd;
+
+ ret = DeviceIoControl(hDeviceVM,
+ HAX_VM_IOCTL_SET_RAM,
+ pinfo, sizeof(*pinfo),
+ 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)) {
+ dprint("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)
+ dprint("hax capability is too long to hold.\n");
+ dprint("Failed to get Hax capability:%d\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)) {
+ dprint("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)
+ dprint("hax module verion is too long to hold.\n");
+ dprint("Failed to get Hax module version:%d\n", err);
+ return -EFAULT;
+ } else
+ return 0;
+}
+
+static char *hax_vm_devfs_string(int vm_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID)
+ {
+ dprint("Too big VM id\n");
+ return NULL;
+ }
+
+ name = g_strdup("\\\\.\\hax_vmxx");
+ if (!name)
+ return NULL;
+ sprintf(name, "\\\\.\\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)
+ {
+ dprint("Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
+ return NULL;
+ }
+ name = g_strdup("\\\\.\\hax_vmxx_vcpuxx");
+ if (!name)
+ return NULL;
+ sprintf(name, "\\\\.\\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) {
+ dprint("error code:%d", 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) {
+ dprint("Incorrect name\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)
+ dprint("Open the vm devcie error:%s, ec:%d\n", vm_name, GetLastError());
+
+ g_free(vm_name);
+ return hDeviceVM;
+}
+
+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)
+ {
+ dprint("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)
+ {
+ dprint("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)
+ dprint("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)
+ {
+ dprint("Failed to setup the hax tunnel\n");
+ return -1;
+ }
+
+ if (!valid_hax_tunnel_size(info.size))
+ {
+ dprint("Invalid hax tunnel size %x\n", info.size);
+ ret = -EINVAL;
+ return ret;
+ }
+ vcpu->tunnel = (struct hax_tunnel *)(info.va);
+ vcpu->iobuf = (unsigned char *)(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(CPUState *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(CPUState *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(CPUState *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(CPUState *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;
+}