Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream-repla…
Browse files Browse the repository at this point in the history
…y' into staging

So here it is, let's see what happens.

# gpg: Signature made Fri 06 Nov 2015 09:30:34 GMT using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"

* remotes/bonzini/tags/for-upstream-replay:
  replay: recording of the user input
  replay: command line options
  replay: replay blockers for devices
  replay: initialization and deinitialization
  replay: ptimer
  bottom halves: introduce bh call function
  replay: checkpoints
  icount: improve counting for record/replay
  replay: shutdown event
  replay: recording and replaying clock ticks
  replay: asynchronous events infrastructure
  replay: interrupts and exceptions
  cpu: replay instructions sequence
  cpu-exec: allow temporary disabling icount
  replay: introduce icount event
  replay: introduce mutex to protect the replay log
  replay: internal functions for replay log
  replay: global variables and function stubs

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Nov 6, 2015
2 parents 3aa88b3 + ee31299 commit 9319738
Show file tree
Hide file tree
Showing 30 changed files with 1,803 additions and 58 deletions.
2 changes: 2 additions & 0 deletions Makefile.objs
Expand Up @@ -54,6 +54,8 @@ common-obj-y += audio/
common-obj-y += hw/
common-obj-y += accel.o

common-obj-y += replay/

common-obj-y += ui/
common-obj-y += bt-host.o bt-vhci.o
bt-host.o-cflags := $(BLUEZ_CFLAGS)
Expand Down
7 changes: 6 additions & 1 deletion async.c
Expand Up @@ -59,6 +59,11 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
return bh;
}

void aio_bh_call(QEMUBH *bh)
{
bh->cb(bh->opaque);
}

/* Multiple occurrences of aio_bh_poll cannot be called concurrently */
int aio_bh_poll(AioContext *ctx)
{
Expand All @@ -84,7 +89,7 @@ int aio_bh_poll(AioContext *ctx)
ret = 1;
}
bh->idle = 0;
bh->cb(bh->opaque);
aio_bh_call(bh);
}
}

Expand Down
55 changes: 42 additions & 13 deletions cpu-exec.c
Expand Up @@ -30,6 +30,7 @@
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
#include "hw/i386/apic.h"
#endif
#include "sysemu/replay.h"

/* -icount align implementation. */

Expand Down Expand Up @@ -184,7 +185,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
/* Execute the code without caching the generated code. An interpreter
could be used if available. */
static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
TranslationBlock *orig_tb)
TranslationBlock *orig_tb, bool ignore_icount)
{
TranslationBlock *tb;

Expand All @@ -194,7 +195,8 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
max_cycles = CF_COUNT_MASK;

tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
max_cycles | CF_NOCACHE);
max_cycles | CF_NOCACHE
| (ignore_icount ? CF_IGNORE_ICOUNT : 0));
tb->orig_tb = tcg_ctx.tb_ctx.tb_invalidated_flag ? NULL : orig_tb;
cpu->current_tb = tb;
/* execute the generated code */
Expand Down Expand Up @@ -345,21 +347,25 @@ int cpu_exec(CPUState *cpu)
uintptr_t next_tb;
SyncClocks sc;

/* replay_interrupt may need current_cpu */
current_cpu = cpu;

if (cpu->halted) {
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
if ((cpu->interrupt_request & CPU_INTERRUPT_POLL)
&& replay_interrupt()) {
apic_poll_irq(x86_cpu->apic_state);
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
}
#endif
if (!cpu_has_work(cpu)) {
current_cpu = NULL;
return EXCP_HALTED;
}

cpu->halted = 0;
}

current_cpu = cpu;
atomic_mb_set(&tcg_current_cpu, cpu);
rcu_read_lock();

Expand Down Expand Up @@ -401,10 +407,22 @@ int cpu_exec(CPUState *cpu)
cpu->exception_index = -1;
break;
#else
cc->do_interrupt(cpu);
cpu->exception_index = -1;
if (replay_exception()) {
cc->do_interrupt(cpu);
cpu->exception_index = -1;
} else if (!replay_has_interrupt()) {
/* give a chance to iothread in replay mode */
ret = EXCP_INTERRUPT;
break;
}
#endif
}
} else if (replay_has_exception()
&& cpu->icount_decr.u16.low + cpu->icount_extra == 0) {
/* try to cause an exception pending in the log */
cpu_exec_nocache(cpu, 1, tb_find_fast(cpu), true);
ret = -1;
break;
}

next_tb = 0; /* force lookup of first TB */
Expand All @@ -420,30 +438,40 @@ int cpu_exec(CPUState *cpu)
cpu->exception_index = EXCP_DEBUG;
cpu_loop_exit(cpu);
}
if (interrupt_request & CPU_INTERRUPT_HALT) {
if (replay_mode == REPLAY_MODE_PLAY
&& !replay_has_interrupt()) {
/* Do nothing */
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
replay_interrupt();
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
cpu->halted = 1;
cpu->exception_index = EXCP_HLT;
cpu_loop_exit(cpu);
}
#if defined(TARGET_I386)
if (interrupt_request & CPU_INTERRUPT_INIT) {
else if (interrupt_request & CPU_INTERRUPT_INIT) {
replay_interrupt();
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
do_cpu_init(x86_cpu);
cpu->exception_index = EXCP_HALTED;
cpu_loop_exit(cpu);
}
#else
if (interrupt_request & CPU_INTERRUPT_RESET) {
else if (interrupt_request & CPU_INTERRUPT_RESET) {
replay_interrupt();
cpu_reset(cpu);
cpu_loop_exit(cpu);
}
#endif
/* The target hook has 3 exit conditions:
False when the interrupt isn't processed,
True when it is, and we should restart on a new TB,
and via longjmp via cpu_loop_exit. */
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
next_tb = 0;
else {
replay_interrupt();
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
next_tb = 0;
}
}
/* Don't use the cached interrupt_request value,
do_interrupt may have updated the EXITTB flag. */
Expand All @@ -454,7 +482,8 @@ int cpu_exec(CPUState *cpu)
next_tb = 0;
}
}
if (unlikely(cpu->exit_request)) {
if (unlikely(cpu->exit_request
|| replay_has_interrupt())) {
cpu->exit_request = 0;
cpu->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(cpu);
Expand Down Expand Up @@ -519,7 +548,7 @@ int cpu_exec(CPUState *cpu)
if (insns_left > 0) {
/* Execute remaining instructions. */
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
cpu_exec_nocache(cpu, insns_left, tb);
cpu_exec_nocache(cpu, insns_left, tb, false);
align_clocks(&sc, cpu);
}
cpu->exception_index = EXCP_INTERRUPT;
Expand Down
64 changes: 47 additions & 17 deletions cpus.c
Expand Up @@ -42,6 +42,7 @@
#include "qemu/seqlock.h"
#include "qapi-event.h"
#include "hw/nmi.h"
#include "sysemu/replay.h"

#ifndef _WIN32
#include "qemu/compatfd.h"
Expand Down Expand Up @@ -334,7 +335,7 @@ static int64_t qemu_icount_round(int64_t count)
return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
}

static void icount_warp_rt(void *opaque)
static void icount_warp_rt(void)
{
/* The icount_warp_timer is rescheduled soon after vm_clock_warp_start
* changes from -1 to another value, so the race here is okay.
Expand All @@ -345,7 +346,8 @@ static void icount_warp_rt(void *opaque)

seqlock_write_lock(&timers_state.vm_clock_seqlock);
if (runstate_is_running()) {
int64_t clock = cpu_get_clock_locked();
int64_t clock = REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT,
cpu_get_clock_locked());
int64_t warp_delta;

warp_delta = clock - vm_clock_warp_start;
Expand All @@ -368,6 +370,11 @@ static void icount_warp_rt(void *opaque)
}
}

static void icount_dummy_timer(void *opaque)
{
(void)opaque;
}

void qtest_clock_warp(int64_t dest)
{
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
Expand Down Expand Up @@ -403,6 +410,18 @@ void qemu_clock_warp(QEMUClockType type)
return;
}

/* Nothing to do if the VM is stopped: QEMU_CLOCK_VIRTUAL timers
* do not fire, so computing the deadline does not make sense.
*/
if (!runstate_is_running()) {
return;
}

/* warp clock deterministically in record/replay mode */
if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP)) {
return;
}

if (icount_sleep) {
/*
* If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now.
Expand All @@ -412,7 +431,7 @@ void qemu_clock_warp(QEMUClockType type)
* the CPU starts running, in case the CPU is woken by an event other
* than the earliest QEMU_CLOCK_VIRTUAL timer.
*/
icount_warp_rt(NULL);
icount_warp_rt();
timer_del(icount_warp_timer);
}
if (!all_cpu_threads_idle()) {
Expand Down Expand Up @@ -605,7 +624,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
icount_sleep = qemu_opt_get_bool(opts, "sleep", true);
if (icount_sleep) {
icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
icount_warp_rt, NULL);
icount_dummy_timer, NULL);
}

icount_align_option = qemu_opt_get_bool(opts, "align", false);
Expand Down Expand Up @@ -1402,6 +1421,28 @@ int vm_stop_force_state(RunState state)
}
}

static int64_t tcg_get_icount_limit(void)
{
int64_t deadline;

if (replay_mode != REPLAY_MODE_PLAY) {
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;
}

return qemu_icount_round(deadline);
} else {
return replay_get_instructions();
}
}

static int tcg_cpu_exec(CPUState *cpu)
{
int ret;
Expand All @@ -1414,24 +1455,12 @@ static int tcg_cpu_exec(CPUState *cpu)
#endif
if (use_icount) {
int64_t count;
int64_t deadline;
int decr;
timers_state.qemu_icount -= (cpu->icount_decr.u16.low
+ cpu->icount_extra);
cpu->icount_decr.u16.low = 0;
cpu->icount_extra = 0;
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);
count = tcg_get_icount_limit();
timers_state.qemu_icount += count;
decr = (count > 0xffff) ? 0xffff : count;
count -= decr;
Expand All @@ -1449,6 +1478,7 @@ static int tcg_cpu_exec(CPUState *cpu)
+ cpu->icount_extra);
cpu->icount_decr.u32 = 0;
cpu->icount_extra = 0;
replay_account_executed_instructions();
}
return ret;
}
Expand Down

0 comments on commit 9319738

Please sign in to comment.