static void whpx_vcpu_process_async_events(CPUState *cpu) { struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); X86CPU *x86_cpu = X86_CPU(cpu); struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && !(env->hflags & HF_SMM_MASK)) { do_cpu_init(x86_cpu); cpu->vcpu_dirty = true; vcpu->interruptable = true; } 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_HARD) && (env->eflags & IF_MASK)) || (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { cpu->halted = false; } if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) { if (!cpu->vcpu_dirty) { whpx_get_registers(cpu); } do_cpu_sipi(x86_cpu); } if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { cpu->interrupt_request &= ~CPU_INTERRUPT_TPR; if (!cpu->vcpu_dirty) { whpx_get_registers(cpu); } apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip, env->tpr_access_type); } return; }
/* * 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; }