diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-04-04 17:42:56 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-04-04 18:29:25 +0100 |
commit | bae2c270906475093e3d5f4c3103dbe67bf82009 (patch) | |
tree | c1344aaf7b7b20461209e3d4075a635455f31d75 /cpu-exec.c | |
parent | cd7ccc83512a0cba5aa0c778e7507f267cfb1b16 (diff) |
cpu-exec: Unlock tb_lock if we longjmp out of code generation
If the guest attempts to execute from unreadable memory, this will
cause us to longjmp back to the main loop from inside the
target frontend decoder. For linux-user mode, this means we will
still hold the tb_ctx.tb_lock, and will deadlock when we try to
start executing code again. Unlock the lock in the return-from-longjmp
code path to avoid this.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Acked-by: Andrei Warkentin <andrey.warkentin@gmail.com>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'cpu-exec.c')
-rw-r--r-- | cpu-exec.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index 0914d3c85c..2f54054d8c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -227,6 +227,8 @@ int cpu_exec(CPUArchState *env) TranslationBlock *tb; uint8_t *tc_ptr; uintptr_t next_tb; + /* This must be volatile so it is not trashed by longjmp() */ + volatile bool have_tb_lock = false; if (cpu->halted) { if (!cpu_has_work(cpu)) { @@ -600,6 +602,7 @@ int cpu_exec(CPUArchState *env) cpu_loop_exit(cpu); } spin_lock(&tcg_ctx.tb_ctx.tb_lock); + have_tb_lock = true; tb = tb_find_fast(env); /* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */ @@ -621,6 +624,7 @@ int cpu_exec(CPUArchState *env) tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK), next_tb & TB_EXIT_MASK, tb); } + have_tb_lock = false; spin_unlock(&tcg_ctx.tb_ctx.tb_lock); /* cpu_interrupt might be called while translating the @@ -692,6 +696,10 @@ int cpu_exec(CPUArchState *env) #ifdef TARGET_I386 x86_cpu = X86_CPU(cpu); #endif + if (have_tb_lock) { + spin_unlock(&tcg_ctx.tb_ctx.tb_lock); + have_tb_lock = false; + } } } /* for(;;) */ |