#include "qapi-event.h"
#include "hw/nmi.h"
#include "sysemu/replay.h"
-
-#ifndef _WIN32
-#include "qemu/compatfd.h"
-#endif
+#include "hw/boards.h"
#ifdef CONFIG_LINUX
static bool default_mttcg_enabled(void)
{
- QemuOpts *icount_opts = qemu_find_opts_singleton("icount");
- const char *rr = qemu_opt_get(icount_opts, "rr");
-
- if (rr || TCG_OVERSIZED_GUEST) {
+ if (use_icount || TCG_OVERSIZED_GUEST) {
return false;
} else {
#ifdef TARGET_SUPPORTS_MTTCG
if (strcmp(t, "multi") == 0) {
if (TCG_OVERSIZED_GUEST) {
error_setg(errp, "No MTTCG when guest word size > hosts");
+ } else if (use_icount) {
+ error_setg(errp, "No MTTCG when icount is enabled");
} else {
+#ifndef TARGET_SUPPORTS_MTTCG
+ error_report("Guest not yet converted to MTTCG - "
+ "you may get unexpected results");
+#endif
if (!check_tcg_memory_orders_compatible()) {
error_report("Guest expects a stronger memory ordering "
"than the host provides");
- error_printf("This may cause strange/hard to debug errors");
+ error_printf("This may cause strange/hard to debug errors\n");
}
mttcg_enabled = true;
}
}
}
+/* The current number of executed instructions is based on what we
+ * originally budgeted minus the current state of the decrementing
+ * icount counters in extra/u16.low.
+ */
+static int64_t cpu_get_icount_executed(CPUState *cpu)
+{
+ return cpu->icount_budget - (cpu->icount_decr.u16.low + cpu->icount_extra);
+}
+
+/*
+ * Update the global shared timer_state.qemu_icount to take into
+ * account executed instructions. This is done by the TCG vCPU
+ * thread so the main-loop can see time has moved forward.
+ */
+void cpu_update_icount(CPUState *cpu)
+{
+ int64_t executed = cpu_get_icount_executed(cpu);
+ cpu->icount_budget -= executed;
+
+#ifdef CONFIG_ATOMIC64
+ atomic_set__nocheck(&timers_state.qemu_icount,
+ atomic_read__nocheck(&timers_state.qemu_icount) +
+ executed);
+#else /* FIXME: we need 64bit atomics to do this safely */
+ timers_state.qemu_icount += executed;
+#endif
+}
+
int64_t cpu_get_icount_raw(void)
{
- int64_t icount;
CPUState *cpu = current_cpu;
- icount = timers_state.qemu_icount;
- if (cpu) {
+ if (cpu && cpu->running) {
if (!cpu->can_do_io) {
fprintf(stderr, "Bad icount read\n");
exit(1);
}
- icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
+ /* Take into account what has run */
+ cpu_update_icount(cpu);
}
- return icount;
+#ifdef CONFIG_ATOMIC64
+ return atomic_read__nocheck(&timers_state.qemu_icount);
+#else /* FIXME: we need 64bit atomics to do this safely */
+ return timers_state.qemu_icount;
+#endif
}
/* Return the virtual CPU time, based on the instruction counter. */
if (deadline < 0) {
static bool notified;
if (!icount_sleep && !notified) {
- error_report("WARNING: icount sleep disabled and no active timers");
+ warn_report("icount sleep disabled and no active timers");
notified = true;
}
return;
sleeptime_ns = (long)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS);
qemu_mutex_unlock_iothread();
- atomic_set(&cpu->throttle_thread_scheduled, 0);
g_usleep(sleeptime_ns / 1000); /* Convert ns to us for usleep call */
qemu_mutex_lock_iothread();
+ atomic_set(&cpu->throttle_thread_scheduled, 0);
}
static void cpu_throttle_timer_tick(void *opaque)
} while (cpu != atomic_mb_read(&tcg_current_rr_cpu));
}
+static void do_nothing(CPUState *cpu, run_on_cpu_data unused)
+{
+}
+
+void qemu_timer_notify_cb(void *opaque, QEMUClockType type)
+{
+ if (!use_icount || type != QEMU_CLOCK_VIRTUAL) {
+ qemu_notify_event();
+ return;
+ }
+
+ if (!qemu_in_vcpu_thread() && first_cpu) {
+ /* qemu_cpu_kick is not enough to kick a halted CPU out of
+ * qemu_tcg_wait_io_event. async_run_on_cpu, instead,
+ * causes cpu_thread_is_idle to return false. This way,
+ * handle_icount_deadline can run.
+ */
+ async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL);
+ }
+}
+
static void kick_tcg_thread(void *opaque)
{
timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
}
}
+void cpu_synchronize_all_pre_loadvm(void)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ cpu_synchronize_pre_loadvm(cpu);
+ }
+}
+
static int do_vm_stop(RunState state)
{
int ret = 0;
abort();
}
-static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
- void *ctx)
+static void sigbus_handler(int n, siginfo_t *siginfo, void *ctx)
{
- if (kvm_on_sigbus(siginfo->ssi_code,
- (void *)(intptr_t)siginfo->ssi_addr)) {
+ if (siginfo->si_code != BUS_MCEERR_AO && siginfo->si_code != BUS_MCEERR_AR) {
sigbus_reraise();
}
+
+ if (current_cpu) {
+ /* Called asynchronously in VCPU thread. */
+ if (kvm_on_sigbus_vcpu(current_cpu, siginfo->si_code, siginfo->si_addr)) {
+ sigbus_reraise();
+ }
+ } else {
+ /* Called synchronously (via signalfd) in main thread. */
+ if (kvm_on_sigbus(siginfo->si_code, siginfo->si_addr)) {
+ sigbus_reraise();
+ }
+ }
}
static void qemu_init_sigbus(void)
memset(&action, 0, sizeof(action));
action.sa_flags = SA_SIGINFO;
- action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+ action.sa_sigaction = sigbus_handler;
sigaction(SIGBUS, &action, NULL);
prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
}
-
-static void qemu_kvm_eat_signals(CPUState *cpu)
-{
- struct timespec ts = { 0, 0 };
- siginfo_t siginfo;
- sigset_t waitset;
- sigset_t chkset;
- int r;
-
- sigemptyset(&waitset);
- sigaddset(&waitset, SIG_IPI);
- sigaddset(&waitset, SIGBUS);
-
- do {
- r = sigtimedwait(&waitset, &siginfo, &ts);
- if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
- perror("sigtimedwait");
- exit(1);
- }
-
- switch (r) {
- case SIGBUS:
- if (kvm_on_sigbus_vcpu(cpu, siginfo.si_code, siginfo.si_addr)) {
- sigbus_reraise();
- }
- break;
- default:
- break;
- }
-
- r = sigpending(&chkset);
- if (r == -1) {
- perror("sigpending");
- exit(1);
- }
- } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
-}
-
#else /* !CONFIG_LINUX */
-
static void qemu_init_sigbus(void)
{
}
-
-static void qemu_kvm_eat_signals(CPUState *cpu)
-{
-}
#endif /* !CONFIG_LINUX */
-#ifndef _WIN32
-static void dummy_signal(int sig)
-{
-}
-
-static void qemu_kvm_init_cpu_signals(CPUState *cpu)
-{
- int r;
- sigset_t set;
- struct sigaction sigact;
-
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_handler = dummy_signal;
- sigaction(SIG_IPI, &sigact, NULL);
-
- pthread_sigmask(SIG_BLOCK, NULL, &set);
- sigdelset(&set, SIG_IPI);
- sigdelset(&set, SIGBUS);
- r = kvm_set_signal_mask(cpu, &set);
- if (r) {
- fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
- exit(1);
- }
-}
-
-#else /* _WIN32 */
-static void qemu_kvm_init_cpu_signals(CPUState *cpu)
-{
- abort();
-}
-#endif /* _WIN32 */
-
static QemuMutex qemu_global_mutex;
static QemuThread io_thread;
qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
}
- qemu_kvm_eat_signals(cpu);
qemu_wait_io_event_common(cpu);
}
exit(1);
}
- qemu_kvm_init_cpu_signals(cpu);
+ kvm_init_cpu_signals(cpu);
/* signal CPU creation */
cpu->created = true;
static void handle_icount_deadline(void)
{
+ assert(qemu_in_vcpu_thread());
if (use_icount) {
int64_t deadline =
qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
if (deadline == 0) {
+ /* Wake up other AioContexts. */
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
+ qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
}
}
}
+static void prepare_icount_for_run(CPUState *cpu)
+{
+ if (use_icount) {
+ int insns_left;
+
+ /* These should always be cleared by process_icount_data after
+ * each vCPU execution. However u16.high can be raised
+ * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
+ */
+ g_assert(cpu->icount_decr.u16.low == 0);
+ g_assert(cpu->icount_extra == 0);
+
+ cpu->icount_budget = tcg_get_icount_limit();
+ insns_left = MIN(0xffff, cpu->icount_budget);
+ cpu->icount_decr.u16.low = insns_left;
+ cpu->icount_extra = cpu->icount_budget - insns_left;
+ }
+}
+
+static void process_icount_data(CPUState *cpu)
+{
+ if (use_icount) {
+ /* Account for executed instructions */
+ cpu_update_icount(cpu);
+
+ /* Reset the counters */
+ cpu->icount_decr.u16.low = 0;
+ cpu->icount_extra = 0;
+ cpu->icount_budget = 0;
+
+ replay_account_executed_instructions();
+ }
+}
+
+
static int tcg_cpu_exec(CPUState *cpu)
{
int ret;
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
- if (use_icount) {
- int64_t count;
- int decr;
- timers_state.qemu_icount -= (cpu->icount_decr.u16.low
- + cpu->icount_extra);
- cpu->icount_decr.u16.low = 0;
- cpu->icount_extra = 0;
- count = tcg_get_icount_limit();
- timers_state.qemu_icount += count;
- decr = (count > 0xffff) ? 0xffff : count;
- count -= decr;
- cpu->icount_decr.u16.low = decr;
- cpu->icount_extra = count;
- }
qemu_mutex_unlock_iothread();
cpu_exec_start(cpu);
ret = cpu_exec(cpu);
#ifdef CONFIG_PROFILER
tcg_time += profile_getclock() - ti;
#endif
- if (use_icount) {
- /* Fold pending instructions back into the
- instruction counter, and clear the interrupt flag. */
- timers_state.qemu_icount -= (cpu->icount_decr.u16.low
- + cpu->icount_extra);
- cpu->icount_decr.u32 = 0;
- cpu->icount_extra = 0;
- replay_account_executed_instructions();
- }
return ret;
}
/* Account partial waits to QEMU_CLOCK_VIRTUAL. */
qemu_account_warp_timer();
+ /* Run the timers here. This is much more efficient than
+ * waking up the I/O thread and waiting for completion.
+ */
+ handle_icount_deadline();
+
if (!cpu) {
cpu = first_cpu;
}
if (cpu_can_run(cpu)) {
int r;
+
+ prepare_icount_for_run(cpu);
+
r = tcg_cpu_exec(cpu);
+
+ process_icount_data(cpu);
+
if (r == EXCP_DEBUG) {
cpu_handle_guest_debug(cpu);
break;
atomic_mb_set(&cpu->exit_request, 0);
}
- handle_icount_deadline();
-
qemu_tcg_wait_io_event(cpu ? cpu : QTAILQ_FIRST(&cpus));
deal_with_unplugged_cpus();
}
{
CPUState *cpu = arg;
int r;
+
+ qemu_mutex_lock_iothread();
qemu_thread_get_self(cpu->thread);
- qemu_mutex_lock(&qemu_global_mutex);
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
{
CPUState *cpu = arg;
+ g_assert(!use_icount);
+
rcu_register_thread();
qemu_mutex_lock_iothread();
/* Ignore everything else? */
break;
}
+ } else if (cpu->unplug) {
+ qemu_tcg_destroy_vcpu(cpu);
+ cpu->created = false;
+ qemu_cond_signal(&qemu_cpu_cond);
+ qemu_mutex_unlock_iothread();
+ return NULL;
}
- handle_icount_deadline();
-
atomic_mb_set(&cpu->exit_request, 0);
qemu_tcg_wait_io_event(cpu);
}
CpuInfoList *qmp_query_cpus(Error **errp)
{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
CpuInfoList *head = NULL, *cur_item = NULL;
CPUState *cpu;
#else
info->value->arch = CPU_INFO_ARCH_OTHER;
#endif
+ info->value->has_props = !!mc->cpu_index_to_instance_props;
+ if (info->value->has_props) {
+ CpuInstanceProperties *props;
+ props = g_malloc0(sizeof(*props));
+ *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
+ info->value->props = props;
+ }
/* XXX: waiting for the qapi to support GSList */
if (!cur_item) {