提交 08e73c48 编写于 作者: P Pranith Kumar 提交者: Alex Bennée

tcg: handle EXCP_ATOMIC exception for system emulation

The patch enables handling atomic code in the guest. This should be
preferably done in cpu_handle_exception(), but the current assumptions
regarding when we can execute atomic sections cause a deadlock.

The current mechanism discards the flags which were set in atomic
execution. We ensure they are properly saved by calling the
cc->cpu_exec_enter/leave() functions around the loop.

As we are running cpu_exec_step_atomic() from the outermost loop we
need to avoid an abort() when single stepping over atomic code since
debug exception longjmp will point to the the setlongjmp in
cpu_exec(). We do this by setting a new jmp_env so that it jumps back
here on an exception.
Signed-off-by: NPranith Kumar <bobby.prani@gmail.com>
[AJB: tweak title, merge with new patches, add mmap_lock]
Signed-off-by: NAlex Bennée <alex.bennee@linaro.org>
Reviewed-by: NRichard Henderson <rth@twiddle.net>
CC: Paolo Bonzini <pbonzini@redhat.com>
上级 37257942
...@@ -228,24 +228,43 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles, ...@@ -228,24 +228,43 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
static void cpu_exec_step(CPUState *cpu) static void cpu_exec_step(CPUState *cpu)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUArchState *env = (CPUArchState *)cpu->env_ptr; CPUArchState *env = (CPUArchState *)cpu->env_ptr;
TranslationBlock *tb; TranslationBlock *tb;
target_ulong cs_base, pc; target_ulong cs_base, pc;
uint32_t flags; uint32_t flags;
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
tb_lock(); if (sigsetjmp(cpu->jmp_env, 0) == 0) {
tb = tb_gen_code(cpu, pc, cs_base, flags, mmap_lock();
1 | CF_NOCACHE | CF_IGNORE_ICOUNT); tb_lock();
tb->orig_tb = NULL; tb = tb_gen_code(cpu, pc, cs_base, flags,
tb_unlock(); 1 | CF_NOCACHE | CF_IGNORE_ICOUNT);
/* execute the generated code */ tb->orig_tb = NULL;
trace_exec_tb_nocache(tb, pc); tb_unlock();
cpu_tb_exec(cpu, tb); mmap_unlock();
tb_lock();
tb_phys_invalidate(tb, -1); cc->cpu_exec_enter(cpu);
tb_free(tb); /* execute the generated code */
tb_unlock(); trace_exec_tb_nocache(tb, pc);
cpu_tb_exec(cpu, tb);
cc->cpu_exec_exit(cpu);
tb_lock();
tb_phys_invalidate(tb, -1);
tb_free(tb);
tb_unlock();
} else {
/* We may have exited due to another problem here, so we need
* to reset any tb_locks we may have taken but didn't release.
* The mmap_lock is dropped by tb_gen_code if it runs out of
* memory.
*/
#ifndef CONFIG_SOFTMMU
tcg_debug_assert(!have_mmap_lock());
#endif
tb_lock_reset();
}
} }
void cpu_exec_step_atomic(CPUState *cpu) void cpu_exec_step_atomic(CPUState *cpu)
......
...@@ -1348,6 +1348,11 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) ...@@ -1348,6 +1348,11 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
if (r == EXCP_DEBUG) { if (r == EXCP_DEBUG) {
cpu_handle_guest_debug(cpu); cpu_handle_guest_debug(cpu);
break; break;
} else if (r == EXCP_ATOMIC) {
qemu_mutex_unlock_iothread();
cpu_exec_step_atomic(cpu);
qemu_mutex_lock_iothread();
break;
} }
} else if (cpu->stop) { } else if (cpu->stop) {
if (cpu->unplug) { if (cpu->unplug) {
...@@ -1458,6 +1463,10 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) ...@@ -1458,6 +1463,10 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
*/ */
g_assert(cpu->halted); g_assert(cpu->halted);
break; break;
case EXCP_ATOMIC:
qemu_mutex_unlock_iothread();
cpu_exec_step_atomic(cpu);
qemu_mutex_lock_iothread();
default: default:
/* Ignore everything else? */ /* Ignore everything else? */
break; break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册