void qemu_notify_event(void) { CPUOldState *env = cpu_single_env; if (env) { cpu_exit(env); /* * 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 }
static void apic_common_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info; static DeviceState *vapic; int instance_id = s->id; info = APIC_COMMON_GET_CLASS(s); info->realize(dev, errp); /* Note: We need at least 1M to map the VAPIC option ROM */ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK && !hax_enabled() && ram_size >= 1024 * 1024) { vapic = sysbus_create_simple("kvmvapic", -1, NULL); } s->vapic = vapic; if (apic_report_tpr_access && info->enable_tpr_reporting) { info->enable_tpr_reporting(s, true); } if (s->legacy_instance_id) { instance_id = -1; } vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common, s, -1, 0, NULL); }
void main_loop(void) { int r; #ifdef CONFIG_HAX if (hax_enabled()) hax_sync_vcpus(); #endif for (;;) { do { #ifdef CONFIG_PROFILER int64_t ti; #endif tcg_cpu_exec(); #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif main_loop_wait(qemu_calculate_timeout()); #ifdef CONFIG_PROFILER dev_time += profile_getclock() - ti; #endif qemu_log_rotation_poll(); } while (vm_can_run()); if (qemu_debug_requested()) vm_stop(EXCP_DEBUG); if (qemu_shutdown_requested()) { if (no_shutdown) { vm_stop(0); no_shutdown = 0; } else { if (savevm_on_exit != NULL) { /* Prior to saving VM to the snapshot file, save HW config * settings for that VM, so we can match them when VM gets * loaded from the snapshot. */ snaphost_save_config(savevm_on_exit); do_savevm(cur_mon, savevm_on_exit); } break; } } if (qemu_reset_requested()) { pause_all_vcpus(); qemu_system_reset(); resume_all_vcpus(); } if (qemu_powerdown_requested()) qemu_system_powerdown(); if ((r = qemu_vmstop_requested())) vm_stop(r); } pause_all_vcpus(); }
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); } } }
void qemu_init_vcpu(void *_env) { CPUOldState *env = _env; if (kvm_enabled()) kvm_init_vcpu(env); #ifdef CONFIG_HAX if (hax_enabled()) hax_init_vcpu(env); #endif return; }
void qemu_notify_event(void) { CPUState *env = cpu_single_env; if (env) { cpu_exit(env); #ifdef USE_KQEMU if (env->kqemu_enabled) kqemu_cpu_interrupt(env); #endif #ifdef CONFIG_HAX if (hax_enabled()) hax_raise_event(env); } else { #ifdef _WIN32 if(hax_enabled()) SetEvent(qemu_event_handle); #endif } #else }
/* * 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; }
/* * 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(); cpu_exec_start(cpu); hax_ret = hax_vcpu_run(vcpu); cpu_exec_end(cpu); qemu_mutex_lock_iothread(); /* 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(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 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(SHUTDOWN_CAUSE_GUEST_RESET); 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(SHUTDOWN_CAUSE_GUEST_RESET); 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; }