X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/75312e745ad1b672cbabdc3022f6e7c8eff69b00..cfe25e2bcada943984e27ee63918fd75dc4563ac:/cpus.c diff --git a/cpus.c b/cpus.c index 97e9ab4c07..e566297bd3 100644 --- a/cpus.c +++ b/cpus.c @@ -60,20 +60,23 @@ #endif /* CONFIG_LINUX */ -static CPUArchState *next_cpu; +static CPUState *next_cpu; -static bool cpu_thread_is_idle(CPUArchState *env) +bool cpu_is_stopped(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); + return cpu->stopped || !runstate_is_running(); +} +static bool cpu_thread_is_idle(CPUState *cpu) +{ if (cpu->stop || cpu->queued_work_first) { return false; } - if (cpu->stopped || !runstate_is_running()) { + if (cpu_is_stopped(cpu)) { return true; } if (!cpu->halted || qemu_cpu_has_work(cpu) || - kvm_async_interrupts_enabled()) { + kvm_halt_in_kernel()) { return false; } return true; @@ -81,10 +84,10 @@ static bool cpu_thread_is_idle(CPUArchState *env) static bool all_cpu_threads_idle(void) { - CPUArchState *env; + CPUState *cpu; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (!cpu_thread_is_idle(env)) { + CPU_FOREACH(cpu) { + if (!cpu_thread_is_idle(cpu)) { return false; } } @@ -114,16 +117,17 @@ typedef struct TimersState { int64_t dummy; } TimersState; -TimersState timers_state; +static TimersState timers_state; /* Return the virtual CPU time, based on the instruction counter. */ int64_t cpu_get_icount(void) { int64_t icount; - CPUArchState *env = cpu_single_env; + CPUState *cpu = current_cpu; icount = qemu_icount; - if (env) { + if (cpu) { + CPUArchState *env = cpu->env_ptr; if (!can_do_io(env)) { fprintf(stderr, "Bad clock read\n"); } @@ -203,7 +207,7 @@ static void icount_adjust(void) return; } cur_time = cpu_get_clock(); - cur_icount = qemu_get_clock_ns(vm_clock); + cur_icount = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); delta = cur_icount - cur_time; /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ if (delta > 0 @@ -224,15 +228,16 @@ static void icount_adjust(void) static void icount_adjust_rt(void *opaque) { - qemu_mod_timer(icount_rt_timer, - qemu_get_clock_ms(rt_clock) + 1000); + timer_mod(icount_rt_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); icount_adjust(); } static void icount_adjust_vm(void *opaque) { - qemu_mod_timer(icount_vm_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); + timer_mod(icount_vm_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + get_ticks_per_sec() / 10); icount_adjust(); } @@ -248,22 +253,22 @@ static void icount_warp_rt(void *opaque) } if (runstate_is_running()) { - int64_t clock = qemu_get_clock_ns(rt_clock); + int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); int64_t warp_delta = clock - vm_clock_warp_start; if (use_icount == 1) { qemu_icount_bias += warp_delta; } else { /* - * In adaptive mode, do not let the vm_clock run too + * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too * far ahead of real time. */ int64_t cur_time = cpu_get_clock(); - int64_t cur_icount = qemu_get_clock_ns(vm_clock); + int64_t cur_icount = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t delta = cur_time - cur_icount; qemu_icount_bias += MIN(warp_delta, delta); } - if (qemu_clock_expired(vm_clock)) { - qemu_notify_event(); + if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } } vm_clock_warp_start = -1; @@ -271,19 +276,19 @@ static void icount_warp_rt(void *opaque) void qtest_clock_warp(int64_t dest) { - int64_t clock = qemu_get_clock_ns(vm_clock); + int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); assert(qtest_enabled()); while (clock < dest) { - int64_t deadline = qemu_clock_deadline(vm_clock); + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); int64_t warp = MIN(dest - clock, deadline); qemu_icount_bias += warp; - qemu_run_timers(vm_clock); - clock = qemu_get_clock_ns(vm_clock); + qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); + clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } - qemu_notify_event(); + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } -void qemu_clock_warp(QEMUClock *clock) +void qemu_clock_warp(QEMUClockType type) { int64_t deadline; @@ -292,20 +297,20 @@ void qemu_clock_warp(QEMUClock *clock) * applicable to other clocks. But a clock argument removes the * need for if statements all over the place. */ - if (clock != vm_clock || !use_icount) { + if (type != QEMU_CLOCK_VIRTUAL || !use_icount) { return; } /* - * If the CPUs have been sleeping, advance the vm_clock timer now. This - * ensures that the deadline for the timer is computed correctly below. + * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. + * This ensures that the deadline for the timer is computed correctly below. * This also makes sure that the insn counter is synchronized before the * CPU starts running, in case the CPU is woken by an event other than - * the earliest vm_clock timer. + * the earliest QEMU_CLOCK_VIRTUAL timer. */ icount_warp_rt(NULL); - if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) { - qemu_del_timer(icount_warp_timer); + if (!all_cpu_threads_idle() || !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL)) { + timer_del(icount_warp_timer); return; } @@ -314,28 +319,40 @@ void qemu_clock_warp(QEMUClock *clock) return; } - vm_clock_warp_start = qemu_get_clock_ns(rt_clock); - deadline = qemu_clock_deadline(vm_clock); + vm_clock_warp_start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + /* We want to use the earliest deadline from ALL vm_clocks */ + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + + /* Maintain prior (possibly buggy) behaviour where if no deadline + * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than + * INT32_MAX nanoseconds ahead, we still use INT32_MAX + * nanoseconds. + */ + if ((deadline < 0) || (deadline > INT32_MAX)) { + deadline = INT32_MAX; + } + if (deadline > 0) { /* - * Ensure the vm_clock proceeds even when the virtual CPU goes to + * Ensure QEMU_CLOCK_VIRTUAL proceeds even when the virtual CPU goes to * sleep. Otherwise, the CPU might be waiting for a future timer * interrupt to wake it up, but the interrupt never comes because * the vCPU isn't running any insns and thus doesn't advance the - * vm_clock. + * QEMU_CLOCK_VIRTUAL. * * An extreme solution for this problem would be to never let VCPUs - * sleep in icount mode if there is a pending vm_clock timer; rather - * time could just advance to the next vm_clock event. Instead, we - * do stop VCPUs and only advance vm_clock after some "real" time, - * (related to the time left until the next event) has passed. This - * rt_clock timer will do this. This avoids that the warps are too - * visible externally---for example, you will not be sending network - * packets continuously instead of every 100ms. + * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL + * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL + * event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL + * after some e"real" time, (related to the time left until the next + * event) has passed. The QEMU_CLOCK_REALTIME timer will do this. + * This avoids that the warps are visible externally; for example, + * you will not be sending network packets continuously instead of + * every 100ms. */ - qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline); - } else { - qemu_notify_event(); + timer_mod(icount_warp_timer, vm_clock_warp_start + deadline); + } else if (deadline == 0) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } } @@ -359,7 +376,8 @@ void configure_icount(const char *option) return; } - icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL); + icount_warp_timer = timer_new_ns(QEMU_CLOCK_REALTIME, + icount_warp_rt, NULL); if (strcmp(option, "auto") != 0) { icount_time_shift = strtol(option, NULL, 0); use_icount = 1; @@ -377,29 +395,30 @@ void configure_icount(const char *option) the virtual time trigger catches emulated time passing too fast. Realtime triggers occur even when idle, so use them less frequently than VM triggers. */ - icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL); - qemu_mod_timer(icount_rt_timer, - qemu_get_clock_ms(rt_clock) + 1000); - icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL); - qemu_mod_timer(icount_vm_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); + icount_rt_timer = timer_new_ms(QEMU_CLOCK_REALTIME, + icount_adjust_rt, NULL); + timer_mod(icount_rt_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); + icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + icount_adjust_vm, NULL); + timer_mod(icount_vm_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + get_ticks_per_sec() / 10); } /***********************************************************/ void hw_error(const char *fmt, ...) { va_list ap; - CPUArchState *env; CPUState *cpu; va_start(ap, fmt); fprintf(stderr, "qemu: hardware error: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); + CPU_FOREACH(cpu) { fprintf(stderr, "CPU #%d:\n", cpu->cpu_index); - cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU); + cpu_dump_state(cpu, stderr, fprintf, CPU_DUMP_FPU); } va_end(ap); abort(); @@ -407,47 +426,47 @@ void hw_error(const char *fmt, ...) void cpu_synchronize_all_states(void) { - CPUArchState *cpu; + CPUState *cpu; - for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { cpu_synchronize_state(cpu); } } void cpu_synchronize_all_post_reset(void) { - CPUArchState *cpu; + CPUState *cpu; - for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { cpu_synchronize_post_reset(cpu); } } void cpu_synchronize_all_post_init(void) { - CPUArchState *cpu; + CPUState *cpu; - for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { cpu_synchronize_post_init(cpu); } } -bool cpu_is_stopped(CPUState *cpu) +static int do_vm_stop(RunState state) { - return !runstate_is_running() || cpu->stopped; -} + int ret = 0; -static void do_vm_stop(RunState state) -{ if (runstate_is_running()) { cpu_disable_ticks(); pause_all_vcpus(); runstate_set(state); vm_state_notify(0, state); - bdrv_drain_all(); - bdrv_flush_all(); monitor_protocol_event(QEVENT_STOP, NULL); } + + bdrv_drain_all(); + ret = bdrv_flush_all(); + + return ret; } static bool cpu_can_run(CPUState *cpu) @@ -455,25 +474,23 @@ static bool cpu_can_run(CPUState *cpu) if (cpu->stop) { return false; } - if (cpu->stopped || !runstate_is_running()) { + if (cpu_is_stopped(cpu)) { return false; } return true; } -static void cpu_handle_guest_debug(CPUArchState *env) +static void cpu_handle_guest_debug(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); - - gdb_set_stop_cpu(env); + gdb_set_stop_cpu(cpu); qemu_system_debug_request(); cpu->stopped = true; } static void cpu_signal(int sig) { - if (cpu_single_env) { - cpu_exit(cpu_single_env); + if (current_cpu) { + cpu_exit(current_cpu); } exit_request = 1; } @@ -570,7 +587,7 @@ static void dummy_signal(int sig) { } -static void qemu_kvm_init_cpu_signals(CPUArchState *env) +static void qemu_kvm_init_cpu_signals(CPUState *cpu) { int r; sigset_t set; @@ -583,7 +600,7 @@ static void qemu_kvm_init_cpu_signals(CPUArchState *env) pthread_sigmask(SIG_BLOCK, NULL, &set); sigdelset(&set, SIG_IPI); sigdelset(&set, SIGBUS); - r = kvm_set_signal_mask(env, &set); + r = kvm_set_signal_mask(cpu, &set); if (r) { fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); exit(1); @@ -605,7 +622,7 @@ static void qemu_tcg_init_cpu_signals(void) } #else /* _WIN32 */ -static void qemu_kvm_init_cpu_signals(CPUArchState *env) +static void qemu_kvm_init_cpu_signals(CPUState *cpu) { abort(); } @@ -653,6 +670,7 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) wi.func = func; wi.data = data; + wi.free = false; if (cpu->queued_work_first == NULL) { cpu->queued_work_first = &wi; } else { @@ -664,13 +682,38 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) qemu_cpu_kick(cpu); while (!wi.done) { - CPUArchState *self_env = cpu_single_env; + CPUState *self_cpu = current_cpu; qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex); - cpu_single_env = self_env; + current_cpu = self_cpu; } } +void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) +{ + struct qemu_work_item *wi; + + if (qemu_cpu_is_self(cpu)) { + func(data); + return; + } + + wi = g_malloc0(sizeof(struct qemu_work_item)); + wi->func = func; + wi->data = data; + wi->free = true; + if (cpu->queued_work_first == NULL) { + cpu->queued_work_first = wi; + } else { + cpu->queued_work_last->next = wi; + } + cpu->queued_work_last = wi; + wi->next = NULL; + wi->done = false; + + qemu_cpu_kick(cpu); +} + static void flush_queued_work(CPUState *cpu) { struct qemu_work_item *wi; @@ -683,6 +726,9 @@ static void flush_queued_work(CPUState *cpu) cpu->queued_work_first = wi->next; wi->func(wi->data); wi->done = true; + if (wi->free) { + g_free(wi); + } } cpu->queued_work_last = NULL; qemu_cond_broadcast(&qemu_work_cond); @@ -701,12 +747,12 @@ static void qemu_wait_io_event_common(CPUState *cpu) static void qemu_tcg_wait_io_event(void) { - CPUArchState *env; + CPUState *cpu; while (all_cpu_threads_idle()) { /* Start accounting real time to the virtual clock if the CPUs are idle. */ - qemu_clock_warp(vm_clock); + qemu_clock_warp(QEMU_CLOCK_VIRTUAL); qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex); } @@ -714,16 +760,14 @@ static void qemu_tcg_wait_io_event(void) qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex); } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - qemu_wait_io_event_common(ENV_GET_CPU(env)); + CPU_FOREACH(cpu) { + qemu_wait_io_event_common(cpu); } } -static void qemu_kvm_wait_io_event(CPUArchState *env) +static void qemu_kvm_wait_io_event(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); - - while (cpu_thread_is_idle(env)) { + while (cpu_thread_is_idle(cpu)) { qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex); } @@ -733,14 +777,13 @@ static void qemu_kvm_wait_io_event(CPUArchState *env) static void *qemu_kvm_cpu_thread_fn(void *arg) { - CPUArchState *env = arg; - CPUState *cpu = ENV_GET_CPU(env); + CPUState *cpu = arg; int r; qemu_mutex_lock(&qemu_global_mutex); qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu_single_env = env; + current_cpu = cpu; r = kvm_init_vcpu(cpu); if (r < 0) { @@ -748,7 +791,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) exit(1); } - qemu_kvm_init_cpu_signals(env); + qemu_kvm_init_cpu_signals(cpu); /* signal CPU creation */ cpu->created = true; @@ -756,12 +799,12 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) while (1) { if (cpu_can_run(cpu)) { - r = kvm_cpu_exec(env); + r = kvm_cpu_exec(cpu); if (r == EXCP_DEBUG) { - cpu_handle_guest_debug(env); + cpu_handle_guest_debug(cpu); } } - qemu_kvm_wait_io_event(env); + qemu_kvm_wait_io_event(cpu); } return NULL; @@ -773,8 +816,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) fprintf(stderr, "qtest is not supported under Windows\n"); exit(1); #else - CPUArchState *env = arg; - CPUState *cpu = ENV_GET_CPU(env); + CPUState *cpu = arg; sigset_t waitset; int r; @@ -789,9 +831,9 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) cpu->created = true; qemu_cond_signal(&qemu_cpu_cond); - cpu_single_env = env; + current_cpu = cpu; while (1) { - cpu_single_env = NULL; + current_cpu = NULL; qemu_mutex_unlock_iothread(); do { int sig; @@ -802,7 +844,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) exit(1); } qemu_mutex_lock_iothread(); - cpu_single_env = env; + current_cpu = cpu; qemu_wait_io_event_common(cpu); } @@ -815,34 +857,36 @@ static void tcg_exec_all(void); static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *cpu = arg; - CPUArchState *env; qemu_tcg_init_cpu_signals(); qemu_thread_get_self(cpu->thread); - /* signal CPU creation */ qemu_mutex_lock(&qemu_global_mutex); - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); + CPU_FOREACH(cpu) { cpu->thread_id = qemu_get_thread_id(); cpu->created = true; } qemu_cond_signal(&qemu_cpu_cond); /* wait for initial kick-off after machine start */ - while (ENV_GET_CPU(first_cpu)->stopped) { + while (QTAILQ_FIRST(&cpus)->stopped) { qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex); /* process any pending work */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - qemu_wait_io_event_common(ENV_GET_CPU(env)); + CPU_FOREACH(cpu) { + qemu_wait_io_event_common(cpu); } } while (1) { tcg_exec_all(); - if (use_icount && qemu_clock_deadline(vm_clock) <= 0) { - qemu_notify_event(); + + if (use_icount) { + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + + if (deadline == 0) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } } qemu_tcg_wait_io_event(); } @@ -865,7 +909,7 @@ static void qemu_cpu_kick_thread(CPUState *cpu) CONTEXT tcgContext; if (SuspendThread(cpu->hThread) == (DWORD)-1) { - fprintf(stderr, "qemu:%s: GetLastError:%d\n", __func__, + fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__, GetLastError()); exit(1); } @@ -881,7 +925,7 @@ static void qemu_cpu_kick_thread(CPUState *cpu) cpu_signal(0); if (ResumeThread(cpu->hThread) == (DWORD)-1) { - fprintf(stderr, "qemu:%s: GetLastError:%d\n", __func__, + fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__, GetLastError()); exit(1); } @@ -901,12 +945,11 @@ void qemu_cpu_kick(CPUState *cpu) void qemu_cpu_kick_self(void) { #ifndef _WIN32 - assert(cpu_single_env); - CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env); + assert(current_cpu); - if (!cpu_single_cpu->thread_kicked) { - qemu_cpu_kick_thread(cpu_single_cpu); - cpu_single_cpu->thread_kicked = true; + if (!current_cpu->thread_kicked) { + qemu_cpu_kick_thread(current_cpu); + current_cpu->thread_kicked = true; } #else abort(); @@ -920,7 +963,7 @@ bool qemu_cpu_is_self(CPUState *cpu) static bool qemu_in_vcpu_thread(void) { - return cpu_single_env && qemu_cpu_is_self(ENV_GET_CPU(cpu_single_env)); + return current_cpu && qemu_cpu_is_self(current_cpu); } void qemu_mutex_lock_iothread(void) @@ -930,7 +973,7 @@ void qemu_mutex_lock_iothread(void) } else { iothread_requesting_mutex = true; if (qemu_mutex_trylock(&qemu_global_mutex)) { - qemu_cpu_kick_thread(ENV_GET_CPU(first_cpu)); + qemu_cpu_kick_thread(first_cpu); qemu_mutex_lock(&qemu_global_mutex); } iothread_requesting_mutex = false; @@ -945,14 +988,12 @@ void qemu_mutex_unlock_iothread(void) static int all_vcpus_paused(void) { - CPUArchState *penv = first_cpu; + CPUState *cpu; - while (penv) { - CPUState *pcpu = ENV_GET_CPU(penv); - if (!pcpu->stopped) { + CPU_FOREACH(cpu) { + if (!cpu->stopped) { return 0; } - penv = penv->next_cpu; } return 1; @@ -960,24 +1001,20 @@ static int all_vcpus_paused(void) void pause_all_vcpus(void) { - CPUArchState *penv = first_cpu; + CPUState *cpu; - qemu_clock_enable(vm_clock, false); - while (penv) { - CPUState *pcpu = ENV_GET_CPU(penv); - pcpu->stop = true; - qemu_cpu_kick(pcpu); - penv = penv->next_cpu; + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false); + CPU_FOREACH(cpu) { + cpu->stop = true; + qemu_cpu_kick(cpu); } if (qemu_in_vcpu_thread()) { cpu_stop_current(); if (!kvm_enabled()) { - while (penv) { - CPUState *pcpu = ENV_GET_CPU(penv); - pcpu->stop = 0; - pcpu->stopped = true; - penv = penv->next_cpu; + CPU_FOREACH(cpu) { + cpu->stop = false; + cpu->stopped = true; } return; } @@ -985,25 +1022,26 @@ void pause_all_vcpus(void) while (!all_vcpus_paused()) { qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex); - penv = first_cpu; - while (penv) { - qemu_cpu_kick(ENV_GET_CPU(penv)); - penv = penv->next_cpu; + CPU_FOREACH(cpu) { + qemu_cpu_kick(cpu); } } } +void cpu_resume(CPUState *cpu) +{ + cpu->stop = false; + cpu->stopped = false; + qemu_cpu_kick(cpu); +} + void resume_all_vcpus(void) { - CPUArchState *penv = first_cpu; + CPUState *cpu; - qemu_clock_enable(vm_clock, true); - while (penv) { - CPUState *pcpu = ENV_GET_CPU(penv); - pcpu->stop = false; - pcpu->stopped = false; - qemu_cpu_kick(pcpu); - penv = penv->next_cpu; + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + CPU_FOREACH(cpu) { + cpu_resume(cpu); } } @@ -1030,63 +1068,55 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) } } -static void qemu_kvm_start_vcpu(CPUArchState *env) +static void qemu_kvm_start_vcpu(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); - cpu->thread = g_malloc0(sizeof(QemuThread)); cpu->halt_cond = g_malloc0(sizeof(QemuCond)); qemu_cond_init(cpu->halt_cond); - qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, env, + qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, cpu, QEMU_THREAD_JOINABLE); while (!cpu->created) { qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); } } -static void qemu_dummy_start_vcpu(CPUArchState *env) +static void qemu_dummy_start_vcpu(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); - cpu->thread = g_malloc0(sizeof(QemuThread)); cpu->halt_cond = g_malloc0(sizeof(QemuCond)); qemu_cond_init(cpu->halt_cond); - qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, env, + qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, cpu, QEMU_THREAD_JOINABLE); while (!cpu->created) { qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); } } -void qemu_init_vcpu(void *_env) +void qemu_init_vcpu(CPUState *cpu) { - CPUArchState *env = _env; - CPUState *cpu = ENV_GET_CPU(env); - cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; if (kvm_enabled()) { - qemu_kvm_start_vcpu(env); + qemu_kvm_start_vcpu(cpu); } else if (tcg_enabled()) { qemu_tcg_init_vcpu(cpu); } else { - qemu_dummy_start_vcpu(env); + qemu_dummy_start_vcpu(cpu); } } void cpu_stop_current(void) { - if (cpu_single_env) { - CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env); - cpu_single_cpu->stop = false; - cpu_single_cpu->stopped = true; - cpu_exit(cpu_single_env); + if (current_cpu) { + current_cpu->stop = false; + current_cpu->stopped = true; + cpu_exit(current_cpu); qemu_cond_signal(&qemu_pause_cond); } } -void vm_stop(RunState state) +int vm_stop(RunState state) { if (qemu_in_vcpu_thread()) { qemu_system_vmstop_request(state); @@ -1095,19 +1125,23 @@ void vm_stop(RunState state) * vm_stop() has been requested. */ cpu_stop_current(); - return; + return 0; } - do_vm_stop(state); + + return do_vm_stop(state); } /* does a state transition even if the VM is already stopped, current state is forgotten forever */ -void vm_stop_force_state(RunState state) +int vm_stop_force_state(RunState state) { if (runstate_is_running()) { - vm_stop(state); + return vm_stop(state); } else { runstate_set(state); + /* Make sure to return an error if the flush in a previous vm_stop() + * failed. */ + return bdrv_flush_all(); } } @@ -1123,11 +1157,23 @@ static int tcg_cpu_exec(CPUArchState *env) #endif if (use_icount) { int64_t count; + int64_t deadline; int decr; qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 0; env->icount_extra = 0; - count = qemu_icount_round(qemu_clock_deadline(vm_clock)); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + + /* Maintain prior (possibly buggy) behaviour where if no deadline + * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than + * INT32_MAX nanoseconds ahead, we still use INT32_MAX + * nanoseconds. + */ + if ((deadline < 0) || (deadline > INT32_MAX)) { + deadline = INT32_MAX; + } + + count = qemu_icount_round(deadline); qemu_icount += count; decr = (count > 0xffff) ? 0xffff : count; count -= decr; @@ -1153,23 +1199,23 @@ static void tcg_exec_all(void) { int r; - /* Account partial waits to the vm_clock. */ - qemu_clock_warp(vm_clock); + /* Account partial waits to QEMU_CLOCK_VIRTUAL. */ + qemu_clock_warp(QEMU_CLOCK_VIRTUAL); if (next_cpu == NULL) { next_cpu = first_cpu; } - for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) { - CPUArchState *env = next_cpu; - CPUState *cpu = ENV_GET_CPU(env); + for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) { + CPUState *cpu = next_cpu; + CPUArchState *env = cpu->env_ptr; - qemu_clock_enable(vm_clock, - (env->singlestep_enabled & SSTEP_NOTIMER) == 0); + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, + (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0); if (cpu_can_run(cpu)) { r = tcg_cpu_exec(env); if (r == EXCP_DEBUG) { - cpu_handle_guest_debug(env); + cpu_handle_guest_debug(cpu); break; } } else if (cpu->stop || cpu->stopped) { @@ -1181,12 +1227,10 @@ static void tcg_exec_all(void) void set_numa_modes(void) { - CPUArchState *env; CPUState *cpu; int i; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); + CPU_FOREACH(cpu) { for (i = 0; i < nb_numa_nodes; i++) { if (test_bit(cpu->cpu_index, node_cpumask[i])) { cpu->numa_node = i; @@ -1206,18 +1250,30 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) CpuInfoList *qmp_query_cpus(Error **errp) { CpuInfoList *head = NULL, *cur_item = NULL; - CPUArchState *env; + CPUState *cpu; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - CPUState *cpu = ENV_GET_CPU(env); + CPU_FOREACH(cpu) { CpuInfoList *info; +#if defined(TARGET_I386) + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; +#elif defined(TARGET_PPC) + PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu); + CPUPPCState *env = &ppc_cpu->env; +#elif defined(TARGET_SPARC) + SPARCCPU *sparc_cpu = SPARC_CPU(cpu); + CPUSPARCState *env = &sparc_cpu->env; +#elif defined(TARGET_MIPS) + MIPSCPU *mips_cpu = MIPS_CPU(cpu); + CPUMIPSState *env = &mips_cpu->env; +#endif - cpu_synchronize_state(env); + cpu_synchronize_state(cpu); info = g_malloc0(sizeof(*info)); info->value = g_malloc0(sizeof(*info->value)); info->value->CPU = cpu->cpu_index; - info->value->current = (env == first_cpu); + info->value->current = (cpu == first_cpu); info->value->halted = cpu->halted; info->value->thread_id = cpu->thread_id; #if defined(TARGET_I386) @@ -1253,7 +1309,6 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, { FILE *f; uint32_t l; - CPUArchState *env; CPUState *cpu; uint8_t buf[1024]; @@ -1267,11 +1322,10 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, "a CPU number"); return; } - env = cpu->env_ptr; f = fopen(filename, "wb"); if (!f) { - error_set(errp, QERR_OPEN_FILE_FAILED, filename); + error_setg_file_open(errp, errno, filename); return; } @@ -1279,7 +1333,7 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, l = sizeof(buf); if (l > size) l = size; - cpu_memory_rw_debug(env, addr, buf, l, 0); + cpu_memory_rw_debug(cpu, addr, buf, l, 0); if (fwrite(buf, 1, l, f) != l) { error_set(errp, QERR_IO_ERROR); goto exit; @@ -1301,7 +1355,7 @@ void qmp_pmemsave(int64_t addr, int64_t size, const char *filename, f = fopen(filename, "wb"); if (!f) { - error_set(errp, QERR_OPEN_FILE_FAILED, filename); + error_setg_file_open(errp, errno, filename); return; } @@ -1325,15 +1379,32 @@ exit: void qmp_inject_nmi(Error **errp) { #if defined(TARGET_I386) - CPUArchState *env; + CPUState *cs; + + CPU_FOREACH(cs) { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; - for (env = first_cpu; env != NULL; env = env->next_cpu) { if (!env->apic_state) { - cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_NMI); + cpu_interrupt(cs, CPU_INTERRUPT_NMI); } else { apic_deliver_nmi(env->apic_state); } } +#elif defined(TARGET_S390X) + CPUState *cs; + S390CPU *cpu; + + CPU_FOREACH(cs) { + cpu = S390_CPU(cs); + if (cpu->env.cpu_num == monitor_get_cpu_index()) { + if (s390_cpu_restart(S390_CPU(cs)) == -1) { + error_set(errp, QERR_UNSUPPORTED); + return; + } + break; + } + } #else error_set(errp, QERR_UNSUPPORTED); #endif