diff options
author | Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 2015-09-17 19:24:16 +0300 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-11-06 10:16:00 +0100 |
commit | 6f0609697f3670bf755a91477487507a8ffee471 (patch) | |
tree | 675e4469cbeb2832fd1e9135bf7db7bfd3dfa65b /cpu-exec.c | |
parent | 8b42704441865611a5ee241ac9fc5cabc47a079b (diff) |
replay: interrupts and exceptions
This patch includes modifications of common cpu files. All interrupts and
exceptions occured during recording are written into the replay log.
These events allow correct replaying the execution by kicking cpu thread
when one of these events is found in the log.
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162416.8676.57647.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'cpu-exec.c')
-rw-r--r-- | cpu-exec.c | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index a1e3d58692..a57b388623 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -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. */ @@ -346,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(); @@ -402,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 */ @@ -421,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. */ @@ -455,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); |