#include "qemu-common.h"
#define NO_CPU_IO_DEFS
#include "cpu.h"
-#include "trace.h"
+#include "trace-root.h"
#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg.h"
#include "translate-all.h"
#include "qemu/bitmap.h"
#include "qemu/timer.h"
+#include "qemu/main-loop.h"
#include "exec/log.h"
+#include "sysemu/cpus.h"
/* #define DEBUG_TB_INVALIDATE */
/* #define DEBUG_TB_FLUSH */
-/* #define DEBUG_LOCKING */
/* make various TB consistency checks */
/* #define DEBUG_TB_CHECK */
* access to the memory related structures are protected with the
* mmap_lock.
*/
-#ifdef DEBUG_LOCKING
-#define DEBUG_MEM_LOCKS 1
-#else
-#define DEBUG_MEM_LOCKS 0
-#endif
-
#ifdef CONFIG_SOFTMMU
-#define assert_memory_lock() do { /* nothing */ } while (0)
+#define assert_memory_lock() tcg_debug_assert(have_tb_lock)
#else
-#define assert_memory_lock() do { \
- if (DEBUG_MEM_LOCKS) { \
- g_assert(have_mmap_lock()); \
- } \
- } while (0)
+#define assert_memory_lock() tcg_debug_assert(have_mmap_lock())
#endif
#define SMC_BITMAP_USE_THRESHOLD 10
bool parallel_cpus;
/* translation block context */
-#ifdef CONFIG_USER_ONLY
__thread int have_tb_lock;
-#endif
static void page_table_config_init(void)
{
assert(v_l2_levels >= 0);
}
+#define assert_tb_locked() tcg_debug_assert(have_tb_lock)
+#define assert_tb_unlocked() tcg_debug_assert(!have_tb_lock)
+
void tb_lock(void)
{
-#ifdef CONFIG_USER_ONLY
- assert(!have_tb_lock);
+ assert_tb_unlocked();
qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
have_tb_lock++;
-#endif
}
void tb_unlock(void)
{
-#ifdef CONFIG_USER_ONLY
- assert(have_tb_lock);
+ assert_tb_locked();
have_tb_lock--;
qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
-#endif
}
void tb_lock_reset(void)
{
-#ifdef CONFIG_USER_ONLY
if (have_tb_lock) {
qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
have_tb_lock = 0;
}
-#endif
}
-#ifdef DEBUG_LOCKING
-#define DEBUG_TB_LOCKS 1
-#else
-#define DEBUG_TB_LOCKS 0
-#endif
-
-#ifdef CONFIG_SOFTMMU
-#define assert_tb_lock() do { /* nothing */ } while (0)
-#else
-#define assert_tb_lock() do { \
- if (DEBUG_TB_LOCKS) { \
- g_assert(have_tb_lock); \
- } \
- } while (0)
-#endif
-
-
static TranslationBlock *tb_find_pc(uintptr_t tc_ptr);
void cpu_gen_init(void)
TranslationBlock *tb;
bool r = false;
+ /* A retaddr of zero is invalid so we really shouldn't have ended
+ * up here. The target code has likely forgotten to check retaddr
+ * != 0 before attempting to restore state. We return early to
+ * avoid blowing up on a recursive tb_lock(). The target must have
+ * previously survived a failed cpu_restore_state because
+ * tb_find_pc(0) would have failed anyway. It still should be
+ * fixed though.
+ */
+
+ if (!retaddr) {
+ return r;
+ }
+
tb_lock();
tb = tb_find_pc(retaddr);
if (tb) {
{
TranslationBlock *tb;
- assert_tb_lock();
+ assert_tb_locked();
if (tcg_ctx.tb_ctx.nb_tbs >= tcg_ctx.code_gen_max_blocks) {
return NULL;
/* Called with tb_lock held. */
void tb_free(TranslationBlock *tb)
{
- assert_tb_lock();
+ assert_tb_locked();
/* In practice this is mostly used for single use temporary TB
Ignore the hard cases and just back up if this TB happens to
uint32_t h;
tb_page_addr_t phys_pc;
- assert_tb_lock();
+ assert_tb_locked();
atomic_set(&tb->invalid, true);
/* flush must be done */
tb_flush(cpu);
mmap_unlock();
+ /* Make the execution loop process the flush as soon as possible. */
+ cpu->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(cpu);
}
#ifdef CONFIG_SOFTMMU
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
{
- assert_tb_lock();
+ assert_tb_locked();
tb_invalidate_phys_range_1(start, end);
}
#else
#endif /* TARGET_HAS_PRECISE_SMC */
assert_memory_lock();
- assert_tb_lock();
+ assert_tb_locked();
p = page_find(start >> TARGET_PAGE_BITS);
if (!p) {
#ifdef CONFIG_SOFTMMU
/* len must be <= 8 and start must be a multiple of len.
* Called via softmmu_template.h when code areas are written to with
- * tb_lock held.
+ * iothread mutex not held.
*/
void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
{
#ifndef CONFIG_USER_ONLY
/* in deterministic execution mode, instructions doing device I/Os
- must be at the end of the TB */
+ * must be at the end of the TB.
+ *
+ * Called by softmmu_template.h, with iothread mutex not held.
+ */
void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
{
#if defined(TARGET_MIPS) || defined(TARGET_SH4)
void cpu_interrupt(CPUState *cpu, int mask)
{
+ g_assert(qemu_mutex_iothread_locked());
cpu->interrupt_request |= mask;
- cpu->tcg_exit_req = 1;
+ cpu->icount_decr.u16.high = -1;
}
/*