@@ -161,7 +161,7 @@ endif #CONFIG_BSD_USER
# System emulator target
ifdef CONFIG_SOFTMMU
-obj-y = vl.o monitor.o machine.o gdbstub.o
+obj-y = vl.o cpus.o monitor.o machine.o gdbstub.o
obj-y += qemu-timer.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
new file mode 100644
@@ -0,0 +1,757 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the
"Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+
+#include "monitor.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "dma.h"
+#include "kvm.h"
+
+#include "cpus.h"
+
+static CPUState *cur_cpu;
+static CPUState *next_cpu;
+
+/***********************************************************/
+void hw_error(const char *fmt, ...)
+{
+ va_list ap;
+ CPUState *env;
+
+ 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) {
+ fprintf(stderr, "CPU #%d:\n", env->cpu_index);
+#ifdef TARGET_I386
+ cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
+#else
+ cpu_dump_state(env, stderr, fprintf, 0);
+#endif
+ }
+ va_end(ap);
+ abort();
+}
+
+void cpu_synchronize_all_states(void)
+{
+ CPUState *cpu;
+
+ for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ cpu_synchronize_state(cpu);
+ }
+}
+
+void cpu_synchronize_all_post_reset(void)
+{
+ CPUState *cpu;
+
+ for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ cpu_synchronize_post_reset(cpu);
+ }
+}
+
+void cpu_synchronize_all_post_init(void)
+{
+ CPUState *cpu;
+
+ for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ cpu_synchronize_post_init(cpu);
+ }
+}
+
+static void do_vm_stop(int reason)
+{
+ if (vm_running) {
+ cpu_disable_ticks();
+ vm_running = 0;
+ pause_all_vcpus();
+ vm_state_notify(0, reason);
+ monitor_protocol_event(QEVENT_STOP, NULL);
+ }
+}
+
+static int cpu_can_run(CPUState *env)
+{
+ if (env->stop)
+ return 0;
+ if (env->stopped)
+ return 0;
+ if (!vm_running)
+ return 0;
+ return 1;
+}
+
+static int cpu_has_work(CPUState *env)
+{
+ if (env->stop)
+ return 1;
+ if (env->stopped)
+ return 0;
+ if (!env->halted)
+ return 1;
+ if (qemu_cpu_has_work(env))
+ return 1;
+ return 0;
+}
+
+static int tcg_has_work(void)
+{
+ CPUState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu)
+ if (cpu_has_work(env))
+ return 1;
+ return 0;
+}
+
+#ifndef _WIN32
+static int io_thread_fd = -1;
+
+static void qemu_event_increment(void)
+{
+ /* Write 8 bytes to be compatible with eventfd. */
+ static uint64_t val = 1;
+ ssize_t ret;
+
+ if (io_thread_fd == -1)
+ return;
+
+ do {
+ ret = write(io_thread_fd, &val, sizeof(val));
+ } while (ret < 0 && errno == EINTR);
+
+ /* EAGAIN is fine, a read must be pending. */
+ if (ret < 0 && errno != EAGAIN) {
+ fprintf(stderr, "qemu_event_increment: write() filed: %s\n",
+ strerror(errno));
+ exit (1);
+ }
+}
+
+static void qemu_event_read(void *opaque)
+{
+ int fd = (unsigned long)opaque;
+ ssize_t len;
+ char buffer[512];
+
+ /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
+ do {
+ len = read(fd, buffer, sizeof(buffer));
+ } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+}
+
+static int qemu_event_init(void)
+{
+ int err;
+ int fds[2];
+
+ err = qemu_eventfd(fds);
+ if (err == -1)
+ return -errno;
+
+ err = fcntl_setfl(fds[0], O_NONBLOCK);
+ if (err < 0)
+ goto fail;
+
+ err = fcntl_setfl(fds[1], O_NONBLOCK);
+ if (err < 0)
+ goto fail;
+
+ qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+ (void *)(unsigned long)fds[0]);
+
+ io_thread_fd = fds[1];
+ return 0;
+
+fail:
+ close(fds[0]);
+ close(fds[1]);
+ return err;
+}
+#else
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+ qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!qemu_event_handle) {
+ fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+ return -1;
+ }
+ qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+ return 0;
+}
+
+static void qemu_event_increment(void)
+{
+ if (!SetEvent(qemu_event_handle)) {
+ fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
+ GetLastError());
+ exit (1);
+ }
+}
+#endif
+
+#ifndef CONFIG_IOTHREAD
+int qemu_init_main_loop(void)
+{
+ return qemu_event_init();
+}
+
+void qemu_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+
+ env->nr_cores = smp_cores;
+ env->nr_threads = smp_threads;
+ if (kvm_enabled())
+ kvm_init_vcpu(env);
+ return;
+}
+
+int qemu_cpu_self(void *env)
+{
+ return 1;
+}
+
+void resume_all_vcpus(void)
+{
+}
+
+void pause_all_vcpus(void)
+{
+}
+
+void qemu_cpu_kick(void *env)
+{
+ return;
+}
+
+void qemu_notify_event(void)
+{
+ CPUState *env = cpu_single_env;
+
+ qemu_event_increment ();
+ if (env) {
+ cpu_exit(env);
+ }
+ if (next_cpu && env != next_cpu) {
+ cpu_exit(next_cpu);
+ }
+}
+
+void qemu_mutex_lock_iothread(void) {}
+void qemu_mutex_unlock_iothread(void) {}
+
+void vm_stop(int reason)
+{
+ do_vm_stop(reason);
+}
+
+#else /* CONFIG_IOTHREAD */
+
+#include "qemu-thread.h"
+
+QemuMutex qemu_global_mutex;
+static QemuMutex qemu_fair_mutex;
+
+static QemuThread io_thread;
+
+static QemuThread *tcg_cpu_thread;
+static QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+static QemuCond qemu_cpu_cond;
+/* system init */
+static QemuCond qemu_system_cond;
+static QemuCond qemu_pause_cond;
+
+static void tcg_block_io_signals(void);
+static void kvm_block_io_signals(CPUState *env);
+static void unblock_io_signals(void);
+
+int qemu_init_main_loop(void)
+{
+ int ret;
+
+ ret = qemu_event_init();
+ if (ret)
+ return ret;
+
+ qemu_cond_init(&qemu_pause_cond);
+ qemu_mutex_init(&qemu_fair_mutex);
+ qemu_mutex_init(&qemu_global_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ unblock_io_signals();
+ qemu_thread_self(&io_thread);
+
+ return 0;
+}
+
+static void qemu_wait_io_event_common(CPUState *env)
+{
+ if (env->stop) {
+ env->stop = 0;
+ env->stopped = 1;
+ qemu_cond_signal(&qemu_pause_cond);
+ }
+}
+
+static void qemu_wait_io_event(CPUState *env)
+{
+ while (!tcg_has_work())
+ qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+
+ qemu_mutex_unlock(&qemu_global_mutex);
+
+ /*
+ * Users of qemu_global_mutex can be starved, having no chance
+ * to acquire it since this path will get to it first.
+ * So use another lock to provide fairness.
+ */
+ qemu_mutex_lock(&qemu_fair_mutex);
+ qemu_mutex_unlock(&qemu_fair_mutex);
+
+ qemu_mutex_lock(&qemu_global_mutex);
+ qemu_wait_io_event_common(env);
+}
+
+static void qemu_kvm_eat_signal(CPUState *env, int timeout)
+{
+ struct timespec ts;
+ int r, e;
+ siginfo_t siginfo;
+ sigset_t waitset;
+
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+
+ sigemptyset(&waitset);
+ sigaddset(&waitset, SIG_IPI);
+
+ qemu_mutex_unlock(&qemu_global_mutex);
+ r = sigtimedwait(&waitset, &siginfo, &ts);
+ e = errno;
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ if (r == -1 && !(e == EAGAIN || e == EINTR)) {
+ fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+ exit(1);
+ }
+}
+
+static void qemu_kvm_wait_io_event(CPUState *env)
+{
+ while (!cpu_has_work(env))
+ qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+
+ qemu_kvm_eat_signal(env, 0);
+ qemu_wait_io_event_common(env);
+}
+
+static int qemu_cpu_exec(CPUState *env);
+
+static void *kvm_cpu_thread_fn(void *arg)
+{
+ CPUState *env = arg;
+
+ qemu_thread_self(env->thread);
+ if (kvm_enabled())
+ kvm_init_vcpu(env);
+
+ kvm_block_io_signals(env);
+
+ /* signal CPU creation */
+ qemu_mutex_lock(&qemu_global_mutex);
+ env->created = 1;
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ /* and wait for machine initialization */
+ while (!qemu_system_ready)
+ qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+ while (1) {
+ if (cpu_can_run(env))
+ qemu_cpu_exec(env);
+ qemu_kvm_wait_io_event(env);
+ }
+
+ return NULL;
+}
+
+static void *tcg_cpu_thread_fn(void *arg)
+{
+ CPUState *env = arg;
+
+ tcg_block_io_signals();
+ qemu_thread_self(env->thread);
+
+ /* signal CPU creation */
+ qemu_mutex_lock(&qemu_global_mutex);
+ for (env = first_cpu; env != NULL; env = env->next_cpu)
+ env->created = 1;
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ /* and wait for machine initialization */
+ while (!qemu_system_ready)
+ qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+ while (1) {
+ tcg_cpu_exec();
+ qemu_wait_io_event(cur_cpu);
+ }
+
+ return NULL;
+}
+
+void qemu_cpu_kick(void *_env)
+{
+ CPUState *env = _env;
+ qemu_cond_broadcast(env->halt_cond);
+ if (kvm_enabled())
+ qemu_thread_signal(env->thread, SIG_IPI);
+}
+
+int qemu_cpu_self(void *_env)
+{
+ CPUState *env = _env;
+ QemuThread this;
+
+ qemu_thread_self(&this);
+
+ return qemu_thread_equal(&this, env->thread);
+}
+
+static void cpu_signal(int sig)
+{
+ if (cpu_single_env)
+ cpu_exit(cpu_single_env);
+}
+
+static void tcg_block_io_signals(void)
+{
+ sigset_t set;
+ struct sigaction sigact;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGCHLD);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIG_IPI);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = cpu_signal;
+ sigaction(SIG_IPI, &sigact, NULL);
+}
+
+static void dummy_signal(int sig)
+{
+}
+
+static void kvm_block_io_signals(CPUState *env)
+{
+ int r;
+ sigset_t set;
+ struct sigaction sigact;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGCHLD);
+ sigaddset(&set, SIG_IPI);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ pthread_sigmask(SIG_BLOCK, NULL, &set);
+ sigdelset(&set, SIG_IPI);
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = dummy_signal;
+ sigaction(SIG_IPI, &sigact, NULL);
+
+ r = kvm_set_signal_mask(env, &set);
+ if (r) {
+ fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
+ exit(1);
+ }
+}
+
+static void unblock_io_signals(void)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIG_IPI);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+}
+
+static void qemu_signal_lock(unsigned int msecs)
+{
+ qemu_mutex_lock(&qemu_fair_mutex);
+
+ while (qemu_mutex_trylock(&qemu_global_mutex)) {
+ qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
+ if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
+ break;
+ }
+ qemu_mutex_unlock(&qemu_fair_mutex);
+}
+
+void qemu_mutex_lock_iothread(void)
+{
+ if (kvm_enabled()) {
+ qemu_mutex_lock(&qemu_fair_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+ qemu_mutex_unlock(&qemu_fair_mutex);
+ } else
+ qemu_signal_lock(100);
+}
+
+void qemu_mutex_unlock_iothread(void)
+{
+ qemu_mutex_unlock(&qemu_global_mutex);
+}
+
+static int all_vcpus_paused(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ if (!penv->stopped)
+ return 0;
+ penv = (CPUState *)penv->next_cpu;
+ }
+
+ return 1;
+}
+
+void pause_all_vcpus(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ penv->stop = 1;
+ qemu_thread_signal(penv->thread, SIG_IPI);
+ qemu_cpu_kick(penv);
+ penv = (CPUState *)penv->next_cpu;
+ }
+
+ while (!all_vcpus_paused()) {
+ qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
+ penv = first_cpu;
+ while (penv) {
+ qemu_thread_signal(penv->thread, SIG_IPI);
+ penv = (CPUState *)penv->next_cpu;
+ }
+ }
+}
+
+void resume_all_vcpus(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ penv->stop = 0;
+ penv->stopped = 0;
+ qemu_thread_signal(penv->thread, SIG_IPI);
+ qemu_cpu_kick(penv);
+ penv = (CPUState *)penv->next_cpu;
+ }
+}
+
+static void tcg_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+ /* share a single thread for all cpus with TCG */
+ if (!tcg_cpu_thread) {
+ env->thread = qemu_mallocz(sizeof(QemuThread));
+ env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
+ while (env->created == 0)
+ qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+ tcg_cpu_thread = env->thread;
+ tcg_halt_cond = env->halt_cond;
+ } else {
+ env->thread = tcg_cpu_thread;
+ env->halt_cond = tcg_halt_cond;
+ }
+}
+
+static void kvm_start_vcpu(CPUState *env)
+{
+ env->thread = qemu_mallocz(sizeof(QemuThread));
+ env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
+ while (env->created == 0)
+ qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+}
+
+void qemu_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+
+ env->nr_cores = smp_cores;
+ env->nr_threads = smp_threads;
+ if (kvm_enabled())
+ kvm_start_vcpu(env);
+ else
+ tcg_init_vcpu(env);
+}
+
+void qemu_notify_event(void)
+{
+ qemu_event_increment();
+}
+
+static void qemu_system_vmstop_request(int reason)
+{
+ vmstop_requested = reason;
+ qemu_notify_event();
+}
+
+void vm_stop(int reason)
+{
+ QemuThread me;
+ qemu_thread_self(&me);
+
+ if (!qemu_thread_equal(&me, &io_thread)) {
+ qemu_system_vmstop_request(reason);
+ /*
+ * FIXME: should not return to device code in case
+ * vm_stop() has been requested.
+ */
+ if (cpu_single_env) {
+ cpu_exit(cpu_single_env);
+ cpu_single_env->stop = 1;
+ }
+ return;
+ }
+ do_vm_stop(reason);
+}
+
+#endif
+
+static int qemu_cpu_exec(CPUState *env)
+{
+ int ret;
+#ifdef CONFIG_PROFILER
+ int64_t ti;
+#endif
+
+#ifdef CONFIG_PROFILER
+ ti = profile_getclock();
+#endif
+ if (use_icount) {
+ int64_t count;
+ 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_next_deadline());
+ qemu_icount += count;
+ decr = (count > 0xffff) ? 0xffff : count;
+ count -= decr;
+ env->icount_decr.u16.low = decr;
+ env->icount_extra = count;
+ }
+ ret = cpu_exec(env);
+#ifdef CONFIG_PROFILER
+ qemu_time += profile_getclock() - ti;
+#endif
+ if (use_icount) {
+ /* Fold pending instructions back into the
+ instruction counter, and clear the interrupt flag. */
+ qemu_icount -= (env->icount_decr.u16.low
+ + env->icount_extra);
+ env->icount_decr.u32 = 0;
+ env->icount_extra = 0;
+ }
+ return ret;
+}
+
+bool tcg_cpu_exec(void)
+{
+ int ret = 0;
+
+ if (next_cpu == NULL)
+ next_cpu = first_cpu;
+ for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
+ CPUState *env = cur_cpu = next_cpu;
+
+ qemu_clock_enable(vm_clock,
+ (cur_cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
+
+ if (qemu_alarm_pending())
+ break;
+ if (cpu_can_run(env))
+ ret = qemu_cpu_exec(env);
+ else if (env->stop)
+ break;
+
+ if (ret == EXCP_DEBUG) {
+ gdb_set_stop_cpu(env);
+ debug_requested = 1;
+ break;
+ }
+ }
+ return tcg_has_work();
+}
+
+void set_numa_modes(void)
+{
+ CPUState *env;
+ int i;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ for (i = 0; i < nb_numa_nodes; i++) {
+ if (node_cpumask[i] & (1 << env->cpu_index)) {
+ env->numa_node = i;
+ }
+ }
+ }
+}
new file mode 100644
@@ -0,0 +1,17 @@
+#ifndef QEMU_CPUS_H
+#define QEMU_CPUS_H
+
+/* cpu-common.c */
+int qemu_init_main_loop(void);
+void resume_all_vcpus(void);
+void pause_all_vcpus(void);
+
+/* vl.c */
+extern int smp_cores;
+extern int smp_threads;
+extern int debug_requested;
+void vm_state_notify(int running, int reason);
+bool tcg_cpu_exec(void);
+void set_numa_modes(void);
+
+#endif
@@ -160,6 +160,7 @@ int main(int argc, char **argv)
#include "slirp/libslirp.h"
#include "qemu-queue.h"
+#include "cpus.h"
//#define DEBUG_NET
//#define DEBUG_SLIRP
@@ -249,8 +250,6 @@ int nb_numa_nodes;
uint64_t node_mem[MAX_NODES];
uint64_t node_cpumask[MAX_NODES];
-static CPUState *cur_cpu;
-static CPUState *next_cpu;
static QEMUTimer *nographic_timer;
uint8_t qemu_uuid[16];
@@ -310,28 +309,6 @@ static int default_driver_check(QemuOpts *opts,
void *opaque)
target_phys_addr_t isa_mem_base = 0;
PicState2 *isa_pic;
-/***********************************************************/
-void hw_error(const char *fmt, ...)
-{
- va_list ap;
- CPUState *env;
-
- 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) {
- fprintf(stderr, "CPU #%d:\n", env->cpu_index);
-#ifdef TARGET_I386
- cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
-#else
- cpu_dump_state(env, stderr, fprintf, 0);
-#endif
- }
- va_end(ap);
- abort();
-}
-
static void set_proc_name(const char *s)
{
Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- Makefile.target | 2 +- cpus.c | 757 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ cpus.h | 17 ++ vl.c | 733 +----------------------------------------------------- 4 files changed, 778 insertions(+), 731 deletions(-) create mode 100644 cpus.c create mode 100644 cpus.h #if defined(__linux__) && defined(PR_SET_NAME) @@ -1958,33 +1935,6 @@ static void nographic_update(void *opaque) qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock)); } -void cpu_synchronize_all_states(void) -{ - CPUState *cpu; - - for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { - cpu_synchronize_state(cpu); - } -} - -void cpu_synchronize_all_post_reset(void) -{ - CPUState *cpu; - - for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { - cpu_synchronize_post_reset(cpu); - } -} - -void cpu_synchronize_all_post_init(void) -{ - CPUState *cpu; - - for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { - cpu_synchronize_post_init(cpu); - } -} - struct vm_change_state_entry { VMChangeStateHandler *cb; void *opaque; @@ -2012,7 +1962,7 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) qemu_free (e); } -static void vm_state_notify(int running, int reason) +void vm_state_notify(int running, int reason) { VMChangeStateEntry *e; @@ -2021,9 +1971,6 @@ static void vm_state_notify(int running, int reason) } } -static void resume_all_vcpus(void); -static void pause_all_vcpus(void); - void vm_start(void) { if (!vm_running) { @@ -2047,7 +1994,7 @@ static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers = static int reset_requested; static int shutdown_requested; static int powerdown_requested; -static int debug_requested; +int debug_requested; static int vmstop_requested; int qemu_shutdown_requested(void) @@ -2085,17 +2032,6 @@ static int qemu_vmstop_requested(void) return r; } -static void do_vm_stop(int reason) -{ - if (vm_running) { - cpu_disable_ticks(); - vm_running = 0; - pause_all_vcpus(); - vm_state_notify(0, reason); - monitor_protocol_event(QEVENT_STOP, NULL); - } -} - void qemu_register_reset(QEMUResetHandler *func, void *opaque) { QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry)); @@ -2152,589 +2088,6 @@ void qemu_system_powerdown_request(void) qemu_notify_event(); } -static int cpu_can_run(CPUState *env) -{ - if (env->stop) - return 0; - if (env->stopped) - return 0; - if (!vm_running) - return 0; - return 1; -} - -static int cpu_has_work(CPUState *env) -{ - if (env->stop) - return 1; - if (env->stopped) - return 0; - if (!env->halted) - return 1; - if (qemu_cpu_has_work(env)) - return 1; - return 0; -} - -static int tcg_has_work(void) -{ - CPUState *env; - - for (env = first_cpu; env != NULL; env = env->next_cpu) - if (cpu_has_work(env)) - return 1; - return 0; -} - -#ifndef _WIN32 -static int io_thread_fd = -1; - -static void qemu_event_increment(void) -{ - /* Write 8 bytes to be compatible with eventfd. */ - static uint64_t val = 1; - ssize_t ret; - - if (io_thread_fd == -1) - return; - - do { - ret = write(io_thread_fd, &val, sizeof(val)); - } while (ret < 0 && errno == EINTR); - - /* EAGAIN is fine, a read must be pending. */ - if (ret < 0 && errno != EAGAIN) { - fprintf(stderr, "qemu_event_increment: write() filed: %s\n", - strerror(errno)); - exit (1); - } -} - -static void qemu_event_read(void *opaque) -{ - int fd = (unsigned long)opaque; - ssize_t len; - char buffer[512]; - - /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */ - do { - len = read(fd, buffer, sizeof(buffer)); - } while ((len == -1 && errno == EINTR) || len == sizeof(buffer)); -} - -static int qemu_event_init(void) -{ - int err; - int fds[2]; - - err = qemu_eventfd(fds); - if (err == -1) - return -errno; - - err = fcntl_setfl(fds[0], O_NONBLOCK); - if (err < 0) - goto fail; - - err = fcntl_setfl(fds[1], O_NONBLOCK); - if (err < 0) - goto fail; - - qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, - (void *)(unsigned long)fds[0]); - - io_thread_fd = fds[1]; - return 0; - -fail: - close(fds[0]); - close(fds[1]); - return err; -} -#else -HANDLE qemu_event_handle; - -static void dummy_event_handler(void *opaque) -{ -} - -static int qemu_event_init(void) -{ - qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!qemu_event_handle) { - fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError()); - return -1; - } - qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL); - return 0; -} - -static void qemu_event_increment(void) -{ - if (!SetEvent(qemu_event_handle)) { - fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n", - GetLastError()); - exit (1); - } -} -#endif - -#ifndef CONFIG_IOTHREAD -static int qemu_init_main_loop(void) -{ - return qemu_event_init(); -} - -void qemu_init_vcpu(void *_env) -{ - CPUState *env = _env; - - env->nr_cores = smp_cores; - env->nr_threads = smp_threads; - if (kvm_enabled()) - kvm_init_vcpu(env); - return; -} - -int qemu_cpu_self(void *env) -{ - return 1; -} - -static void resume_all_vcpus(void) -{ -} - -static void pause_all_vcpus(void) -{ -} - -void qemu_cpu_kick(void *env) -{ - return; -} - -void qemu_notify_event(void) -{ - CPUState *env = cpu_single_env; - - qemu_event_increment (); - if (env) { - cpu_exit(env); - } - if (next_cpu && env != next_cpu) { - cpu_exit(next_cpu); - } -} - -void qemu_mutex_lock_iothread(void) {} -void qemu_mutex_unlock_iothread(void) {} - -void vm_stop(int reason) -{ - do_vm_stop(reason); -} - -#else /* CONFIG_IOTHREAD */ - -#include "qemu-thread.h" - -QemuMutex qemu_global_mutex; -static QemuMutex qemu_fair_mutex; - -static QemuThread io_thread; - -static QemuThread *tcg_cpu_thread; -static QemuCond *tcg_halt_cond; - -static int qemu_system_ready; -/* cpu creation */ -static QemuCond qemu_cpu_cond; -/* system init */ -static QemuCond qemu_system_cond; -static QemuCond qemu_pause_cond; - -static void tcg_block_io_signals(void); -static void kvm_block_io_signals(CPUState *env); -static void unblock_io_signals(void); - -static int qemu_init_main_loop(void) -{ - int ret; - - ret = qemu_event_init(); - if (ret) - return ret; - - qemu_cond_init(&qemu_pause_cond); - qemu_mutex_init(&qemu_fair_mutex); - qemu_mutex_init(&qemu_global_mutex); - qemu_mutex_lock(&qemu_global_mutex); - - unblock_io_signals(); - qemu_thread_self(&io_thread); - - return 0; -} - -static void qemu_wait_io_event_common(CPUState *env) -{ - if (env->stop) { - env->stop = 0; - env->stopped = 1; - qemu_cond_signal(&qemu_pause_cond); - } -} - -static void qemu_wait_io_event(CPUState *env) -{ - while (!tcg_has_work()) - qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); - - qemu_mutex_unlock(&qemu_global_mutex); - - /* - * Users of qemu_global_mutex can be starved, having no chance - * to acquire it since this path will get to it first. - * So use another lock to provide fairness. - */ - qemu_mutex_lock(&qemu_fair_mutex); - qemu_mutex_unlock(&qemu_fair_mutex); - - qemu_mutex_lock(&qemu_global_mutex); - qemu_wait_io_event_common(env); -} - -static void qemu_kvm_eat_signal(CPUState *env, int timeout) -{ - struct timespec ts; - int r, e; - siginfo_t siginfo; - sigset_t waitset; - - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - - sigemptyset(&waitset); - sigaddset(&waitset, SIG_IPI); - - qemu_mutex_unlock(&qemu_global_mutex); - r = sigtimedwait(&waitset, &siginfo, &ts); - e = errno; - qemu_mutex_lock(&qemu_global_mutex); - - if (r == -1 && !(e == EAGAIN || e == EINTR)) { - fprintf(stderr, "sigtimedwait: %s\n", strerror(e)); - exit(1); - } -} - -static void qemu_kvm_wait_io_event(CPUState *env) -{ - while (!cpu_has_work(env)) - qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); - - qemu_kvm_eat_signal(env, 0); - qemu_wait_io_event_common(env); -} - -static int qemu_cpu_exec(CPUState *env); - -static void *kvm_cpu_thread_fn(void *arg) -{ - CPUState *env = arg; - - qemu_thread_self(env->thread); - if (kvm_enabled()) - kvm_init_vcpu(env); - - kvm_block_io_signals(env); - - /* signal CPU creation */ - qemu_mutex_lock(&qemu_global_mutex); - env->created = 1; - qemu_cond_signal(&qemu_cpu_cond); - - /* and wait for machine initialization */ - while (!qemu_system_ready) - qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); - - while (1) { - if (cpu_can_run(env)) - qemu_cpu_exec(env); - qemu_kvm_wait_io_event(env); - } - - return NULL; -} - -static bool tcg_cpu_exec(void); - -static void *tcg_cpu_thread_fn(void *arg) -{ - CPUState *env = arg; - - tcg_block_io_signals(); - qemu_thread_self(env->thread); - - /* signal CPU creation */ - qemu_mutex_lock(&qemu_global_mutex); - for (env = first_cpu; env != NULL; env = env->next_cpu) - env->created = 1; - qemu_cond_signal(&qemu_cpu_cond); - - /* and wait for machine initialization */ - while (!qemu_system_ready) - qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); - - while (1) { - tcg_cpu_exec(); - qemu_wait_io_event(cur_cpu); - } - - return NULL; -} - -void qemu_cpu_kick(void *_env) -{ - CPUState *env = _env; - qemu_cond_broadcast(env->halt_cond); - if (kvm_enabled()) - qemu_thread_signal(env->thread, SIG_IPI); -} - -int qemu_cpu_self(void *_env) -{ - CPUState *env = _env; - QemuThread this; - - qemu_thread_self(&this); - - return qemu_thread_equal(&this, env->thread); -} - -static void cpu_signal(int sig) -{ - if (cpu_single_env) - cpu_exit(cpu_single_env); -} - -static void tcg_block_io_signals(void) -{ - sigset_t set; - struct sigaction sigact; - - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIGCHLD); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = cpu_signal; - sigaction(SIG_IPI, &sigact, NULL); -} - -static void dummy_signal(int sig) -{ -} - -static void kvm_block_io_signals(CPUState *env) -{ - int r; - sigset_t set; - struct sigaction sigact; - - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIGCHLD); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - pthread_sigmask(SIG_BLOCK, NULL, &set); - sigdelset(&set, SIG_IPI); - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = dummy_signal; - sigaction(SIG_IPI, &sigact, NULL); - - r = kvm_set_signal_mask(env, &set); - if (r) { - fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r)); - exit(1); - } -} - -static void unblock_io_signals(void) -{ - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); - - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_BLOCK, &set, NULL); -} - -static void qemu_signal_lock(unsigned int msecs) -{ - qemu_mutex_lock(&qemu_fair_mutex); - - while (qemu_mutex_trylock(&qemu_global_mutex)) { - qemu_thread_signal(tcg_cpu_thread, SIG_IPI); - if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs)) - break; - } - qemu_mutex_unlock(&qemu_fair_mutex); -} - -void qemu_mutex_lock_iothread(void) -{ - if (kvm_enabled()) { - qemu_mutex_lock(&qemu_fair_mutex); - qemu_mutex_lock(&qemu_global_mutex); - qemu_mutex_unlock(&qemu_fair_mutex); - } else - qemu_signal_lock(100); -} - -void qemu_mutex_unlock_iothread(void) -{ - qemu_mutex_unlock(&qemu_global_mutex); -} - -static int all_vcpus_paused(void) -{ - CPUState *penv = first_cpu; - - while (penv) { - if (!penv->stopped) - return 0; - penv = (CPUState *)penv->next_cpu; - } - - return 1; -} - -static void pause_all_vcpus(void) -{ - CPUState *penv = first_cpu; - - while (penv) { - penv->stop = 1; - qemu_thread_signal(penv->thread, SIG_IPI); - qemu_cpu_kick(penv); - penv = (CPUState *)penv->next_cpu; - } - - while (!all_vcpus_paused()) { - qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); - penv = first_cpu; - while (penv) { - qemu_thread_signal(penv->thread, SIG_IPI); - penv = (CPUState *)penv->next_cpu; - } - } -} - -static void resume_all_vcpus(void) -{ - CPUState *penv = first_cpu; - - while (penv) { - penv->stop = 0; - penv->stopped = 0; - qemu_thread_signal(penv->thread, SIG_IPI); - qemu_cpu_kick(penv); - penv = (CPUState *)penv->next_cpu; - } -} - -static void tcg_init_vcpu(void *_env) -{ - CPUState *env = _env; - /* share a single thread for all cpus with TCG */ - if (!tcg_cpu_thread) { - env->thread = qemu_mallocz(sizeof(QemuThread)); - env->halt_cond = qemu_mallocz(sizeof(QemuCond)); - qemu_cond_init(env->halt_cond); - qemu_thread_create(env->thread, tcg_cpu_thread_fn, env); - while (env->created == 0) - qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); - tcg_cpu_thread = env->thread; - tcg_halt_cond = env->halt_cond; - } else { - env->thread = tcg_cpu_thread; - env->halt_cond = tcg_halt_cond; - } -} - -static void kvm_start_vcpu(CPUState *env) -{ - env->thread = qemu_mallocz(sizeof(QemuThread)); - env->halt_cond = qemu_mallocz(sizeof(QemuCond)); - qemu_cond_init(env->halt_cond); - qemu_thread_create(env->thread, kvm_cpu_thread_fn, env); - while (env->created == 0) - qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); -} - -void qemu_init_vcpu(void *_env) -{ - CPUState *env = _env; - - env->nr_cores = smp_cores; - env->nr_threads = smp_threads; - if (kvm_enabled()) - kvm_start_vcpu(env); - else - tcg_init_vcpu(env); -} - -void qemu_notify_event(void) -{ - qemu_event_increment(); -} - -static void qemu_system_vmstop_request(int reason) -{ - vmstop_requested = reason; - qemu_notify_event(); -} - -void vm_stop(int reason) -{ - QemuThread me; - qemu_thread_self(&me); - - if (!qemu_thread_equal(&me, &io_thread)) { - qemu_system_vmstop_request(reason); - /* - * FIXME: should not return to device code in case - * vm_stop() has been requested. - */ - if (cpu_single_env) { - cpu_exit(cpu_single_env); - cpu_single_env->stop = 1; - } - return; - } - do_vm_stop(reason); -} - -#endif - - #ifdef _WIN32 static void host_main_loop_wait(int *timeout) { @@ -2861,86 +2214,6 @@ void main_loop_wait(int nonblocking) } -static int qemu_cpu_exec(CPUState *env) -{ - int ret; -#ifdef CONFIG_PROFILER - int64_t ti; -#endif - -#ifdef CONFIG_PROFILER - ti = profile_getclock(); -#endif - if (use_icount) { - int64_t count; - 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_next_deadline()); - qemu_icount += count; - decr = (count > 0xffff) ? 0xffff : count; - count -= decr; - env->icount_decr.u16.low = decr; - env->icount_extra = count; - } - ret = cpu_exec(env); -#ifdef CONFIG_PROFILER - qemu_time += profile_getclock() - ti; -#endif - if (use_icount) { - /* Fold pending instructions back into the - instruction counter, and clear the interrupt flag. */ - qemu_icount -= (env->icount_decr.u16.low - + env->icount_extra); - env->icount_decr.u32 = 0; - env->icount_extra = 0; - } - return ret; -} - -static bool tcg_cpu_exec(void) -{ - int ret = 0; - - if (next_cpu == NULL) - next_cpu = first_cpu; - for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) { - CPUState *env = cur_cpu = next_cpu; - - qemu_clock_enable(vm_clock, - (cur_cpu->singlestep_enabled & SSTEP_NOTIMER) == 0); - - if (qemu_alarm_pending()) - break; - if (cpu_can_run(env)) - ret = qemu_cpu_exec(env); - else if (env->stop) - break; - - if (ret == EXCP_DEBUG) { - gdb_set_stop_cpu(env); - debug_requested = 1; - break; - } - } - return tcg_has_work(); -} - -static void set_numa_modes(void) -{ - CPUState *env; - int i; - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - for (i = 0; i < nb_numa_nodes; i++) { - if (node_cpumask[i] & (1 << env->cpu_index)) { - env->numa_node = i; - } - } - } -} - static int vm_can_run(void) { if (powerdown_requested)