[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration support |
Date: |
Tue, 8 Nov 2016 21:37:18 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 |
> diff --git a/cpu-exec.c b/cpu-exec.c
> index 4188fed..4bd238b 100644
> --- a/cpu-exec.c
> +++ b/cpu-exec.c
All this should not be needed anymore with unrestricted guest support.
> diff --git a/cpus.c b/cpus.c
> index fc78502..6e0f572 100644
> --- a/cpus.c
> +++ b/cpus.c
> @@ -35,6 +35,7 @@
> #include "sysemu/dma.h"
> #include "sysemu/hw_accel.h"
> #include "sysemu/kvm.h"
> +#include "sysemu/hax.h"
> #include "qmp-commands.h"
> #include "exec/exec-all.h"
>
> @@ -1221,6 +1222,52 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
> return NULL;
> }
>
> +static void *qemu_hax_cpu_thread_fn(void *arg)
> +{
> + CPUState *cpu = arg;
> + int r;
> + qemu_thread_get_self(cpu->thread);
> + qemu_mutex_lock(&qemu_global_mutex);
> +
> + cpu->thread_id = qemu_get_thread_id();
> + cpu->created = true;
> + cpu->halted = 0;
> + current_cpu = cpu;
> +
> + hax_init_vcpu(cpu);
> + qemu_cond_signal(&qemu_cpu_cond);
> +
> + while (1) {
> + if (cpu_can_run(cpu)) {
> + r = hax_smp_cpu_exec(cpu);
> + if (r == EXCP_DEBUG) {
> + cpu_handle_guest_debug(cpu);
> + }
> + }
> +
> + while (cpu_thread_is_idle(cpu)) {
> + qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
> + }
> +
> + qemu_wait_io_event_common(cpu);
> + }
> + return NULL;
> +}
> +
> +
> +static void qemu_cpu_kick_no_halt(void)
> +{
> + CPUState *cpu;
> + /* Ensure whatever caused the exit has reached the CPU threads before
> + * writing exit_request.
> + */
> + atomic_mb_set(&exit_request, 1);
> + cpu = atomic_mb_read(&tcg_current_cpu);
> + if (cpu) {
> + cpu_exit(cpu);
> + }
> +}
> +
> static void qemu_cpu_kick_thread(CPUState *cpu)
> {
> #ifndef _WIN32
> @@ -1235,28 +1282,52 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
> fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
> exit(1);
> }
> -#else /* _WIN32 */
> - abort();
> -#endif
> -}
>
> -static void qemu_cpu_kick_no_halt(void)
> -{
> - CPUState *cpu;
> - /* Ensure whatever caused the exit has reached the CPU threads before
> - * writing exit_request.
> +#ifdef CONFIG_DARWIN
> + /* The cpu thread cannot catch it reliably when shutdown the guest on
> Mac.
> + * We can double check it and resend it
> */
> - atomic_mb_set(&exit_request, 1);
> - cpu = atomic_mb_read(&tcg_current_cpu);
> - if (cpu) {
> - cpu_exit(cpu);
> + if (!exit_request)
> + qemu_cpu_kick_no_halt();
This must be a conflict resolved wrong. exit_request is never read by
the HAX code.
> + if (hax_enabled() && hax_ug_platform())
> + cpu->exit_request = 1;
> +#endif
> +#else /* _WIN32 */
> + if (!qemu_cpu_is_self(cpu)) {
> + CONTEXT tcgContext;
> +
> + if (SuspendThread(cpu->hThread) == (DWORD)-1) {
> + fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
> + GetLastError());
> + exit(1);
> + }
> +
> + /* On multi-core systems, we are not sure that the thread is actually
> + * suspended until we can get the context.
> + */
> + tcgContext.ContextFlags = CONTEXT_CONTROL;
> + while (GetThreadContext(cpu->hThread, &tcgContext) != 0) {
> + continue;
> + }
> +
> + qemu_cpu_kick_no_halt();
> + if (hax_enabled() && hax_ug_platform())
> + cpu->exit_request = 1;
> +
> + if (ResumeThread(cpu->hThread) == (DWORD)-1) {
> + fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
> + GetLastError());
> + exit(1);
> + }
This is weird too. The SuspendThread/ResumeThread dance comes from an
old version of QEMU. It is not needed anymore and, again,
qemu_cpu_kick_no_halt would only be useful if hax_ug_platform() is false.
Here, Linux/KVM uses a signal and pthread_kill. It's probably good for
HAX on Darwin too, but not on Windows. It's possible that
SuspendThread/ResumeThread just does the right thing (sort of by
chance), in which case you can just keep it (removing
qemu_cpu_kick_no_halt). However, there is a hax_raise_event in patch 2
that is unused. If you can figure out how to use it it would be better.
> @@ -1617,6 +1618,21 @@ static void ram_block_add(RAMBlock *new_block, Error
> **errp)
> } else {
> new_block->host = phys_mem_alloc(new_block->max_length,
> &new_block->mr->align);
> + /*
> + * In Hax, the qemu allocate the virtual address, and HAX kernel
> + * populate the memory with physical memory. Currently we have no
> + * paging, so user should make sure enough free memory in advance
> + */
> + if (hax_enabled()) {
> + int ret;
> + ret = hax_populate_ram((uint64_t)(uintptr_t)new_block->host,
> + new_block->max_length);
> + if (ret < 0) {
> + error_setg(errp, "Hax failed to populate ram");
> + return;
> + }
> + }
Please try removing this block and instead starting QEMU with
-mem-prealloc. If it works, remove hax_populate_ram and just set
mem_prealloc to 1 in hax_accel_init.
> if (!new_block->host) {
> error_setg_errno(errp, errno,
> "cannot set up guest memory '%s'",
> diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
> index d78c885..dd4cdc8 100644
> --- a/hw/intc/apic_common.c
> +++ b/hw/intc/apic_common.c
> @@ -316,9 +316,10 @@ static void apic_common_realize(DeviceState *dev, Error
> **errp)
>
> /* Note: We need at least 1M to map the VAPIC option ROM */
> if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
> - ram_size >= 1024 * 1024) {
> + kvm_enabled() && ram_size >= 1024 * 1024) {
This should rather be !hax_enabled(), despite the historical name
mentions KVM.
> 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);
> diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
> index fb79f31..25b6003 100644
> --- a/target-i386/seg_helper.c
> +++ b/target-i386/seg_helper.c
> @@ -25,6 +25,7 @@
> #include "exec/exec-all.h"
> #include "exec/cpu_ldst.h"
> #include "exec/log.h"
> +#include "sysemu/hax.h"
>
> //#define DEBUG_PCALL
>
> @@ -1336,6 +1337,10 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int
> interrupt_request)
> !(env->hflags & HF_SMM_MASK)) {
> cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0);
> cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
> +#ifdef CONFIG_HAX
> + if (hax_enabled())
> + cs->hax_vcpu->resync = 1;
> +#endif
Not needed for UG mode.
> do_smm_enter(cpu);
> ret = true;
> } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index 324103c..e027896 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
Same.
> @@ -4060,6 +4066,7 @@ int main(int argc, char **argv, char **envp)
> machine_class = select_machine();
>
> set_memory_options(&ram_slots, &maxram_size, machine_class);
> + hax_pre_init(ram_size);
It should be possible to merge this with hax_accel_init.
> os_daemonize();
>
> @@ -4418,8 +4425,8 @@ int main(int argc, char **argv, char **envp)
>
> cpu_ticks_init();
> if (icount_opts) {
> - if (kvm_enabled() || xen_enabled()) {
> - error_report("-icount is not allowed with kvm or xen");
> + if (kvm_enabled() || xen_enabled() || hax_enabled()) {
> + error_report("-icount is not allowed with kvm or xen or hax");
Let's say it's only allowed with TCG. :) Again, thanks to UG mode if
hax_enabled() you'll have !tcg_enabled().
Paolo
> exit(1);
> }
> configure_icount(icount_opts, &error_abort);
> @@ -4555,6 +4562,10 @@ int main(int argc, char **argv, char **envp)
>
> numa_post_machine_init();
>
> + if (hax_enabled()) {
> + hax_sync_vcpus();
> + }
> +
> if (qemu_opts_foreach(qemu_find_opts("fw_cfg"),
> parse_fw_cfg, fw_cfg_find(), NULL) != 0) {
> exit(1);
>
[Qemu-devel] [PATCH 1/3] kvm: move cpu synchronization code, Vincent Palatin, 2016/11/08
Re: [Qemu-devel] [PATCH 0/3] [RFC] Add HAX support, Paolo Bonzini, 2016/11/08