From bfff072c5035b8dfbdebeb6b9143f3ae8fe9f9f4 Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Tue, 22 Sep 2020 17:42:41 +1000 Subject: [PATCH 01/10] tcg: update the cpu running flag in cpu_exec_step_atomic The cpu_exec_step_atomic() function is called with the cpu->running clear and proceeds to run target code without setting this flag. If this target code generates an exception then handle_cpu_signal() will unnecessarily abort. For example if atomic code generates a memory protection fault. This patch at least sets and clears this running flag, and adds some assertions to help detect other cases. Signed-off-by: Douglas Crosher Message-Id: Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index e0df9b6a1d..8053aa3f11 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -285,6 +285,9 @@ void cpu_exec_step_atomic(CPUState *cpu) if (sigsetjmp(cpu->jmp_env, 0) == 0) { start_exclusive(); + g_assert(cpu == current_cpu); + g_assert(!cpu->running); + cpu->running = true; tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask); if (tb == NULL) { @@ -323,6 +326,7 @@ void cpu_exec_step_atomic(CPUState *cpu) */ g_assert(cpu_in_exclusive_context(cpu)); parallel_cpus = true; + cpu->running = false; end_exclusive(); } From c52ea111e0ea2d5368a3ae601baafaae75e3317f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Jan 2021 10:04:04 -1000 Subject: [PATCH 02/10] qemu/compiler: Split out qemu_build_not_reached_always MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a symbol that can always be used to signal an error, regardless of optimization. Usage of this should be protected by e.g. __builtin_constant_p, which guards for optimization. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/qemu/compiler.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index d620a841e4..cf28bb2bcd 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -215,9 +215,10 @@ * supports QEMU_ERROR, this will be reported at compile time; otherwise * this will be reported at link time due to the missing symbol. */ -#if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) extern void QEMU_NORETURN QEMU_ERROR("code path is reachable") - qemu_build_not_reached(void); + qemu_build_not_reached_always(void); +#if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) +#define qemu_build_not_reached() qemu_build_not_reached_always() #else #define qemu_build_not_reached() g_assert_not_reached() #endif From 666cc794abe7aa2e123a0963934e519d28a7102c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 16 Feb 2020 13:43:10 -0800 Subject: [PATCH 03/10] tcg: Optimize inline dup_const for MO_64 Avoid the out-of-line function call for immediate MO_64. In addition, diagnose all invalid constants at compile-time. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- include/tcg/tcg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 504c5e9bb0..c5a9d65d5f 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -1325,7 +1325,8 @@ uint64_t dup_const(unsigned vece, uint64_t c); ? ( (VECE) == MO_8 ? 0x0101010101010101ull * (uint8_t)(C) \ : (VECE) == MO_16 ? 0x0001000100010001ull * (uint16_t)(C) \ : (VECE) == MO_32 ? 0x0000000100000001ull * (uint32_t)(C) \ - : dup_const(VECE, C)) \ + : (VECE) == MO_64 ? (uint64_t)(C) \ + : (qemu_build_not_reached_always(), 0)) \ : dup_const(VECE, C)) From d9d699dd7c7d2570e86ea7ff323465d5ea34e9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 17 Jan 2021 17:48:08 +0100 Subject: [PATCH 04/10] accel/tcg: Make cpu_gen_init() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_gen_init() is TCG specific, only used in tcg/translate-all.c. No need to export it to other accelerators, declare it statically. Reviewed-by: Claudio Fontana Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210117164813.4101761-2-f4bug@amsat.org> Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 2 +- include/exec/exec-all.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index e9de6ff9dd..ca7ef6aa17 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -243,7 +243,7 @@ static void page_table_config_init(void) assert(v_l2_levels >= 0); } -void cpu_gen_init(void) +static void cpu_gen_init(void) { tcg_context_init(&tcg_init_ctx); } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 2e5b4bba48..516013e735 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -47,8 +47,6 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns); void restore_state_to_opc(CPUArchState *env, TranslationBlock *tb, target_ulong *data); -void cpu_gen_init(void); - /** * cpu_restore_state: * @cpu: the vCPU state is to be restore to From 0f4abea8efa658ea53600739a8912969736b2d4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 20 Jan 2021 19:53:20 -1000 Subject: [PATCH 05/10] accel/tcg: Move tb_flush_jmp_cache() to cputlb.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move and make the function static, as the only users are here in cputlb.c. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 18 ++++++++++++++++++ accel/tcg/translate-all.c | 17 ----------------- include/exec/exec-all.h | 3 --- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index ced3dc077e..0fa1643ed3 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -25,6 +25,7 @@ #include "exec/address-spaces.h" #include "exec/cpu_ldst.h" #include "exec/cputlb.h" +#include "exec/tb-hash.h" #include "exec/memory-internal.h" #include "exec/ram_addr.h" #include "tcg/tcg.h" @@ -97,6 +98,23 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, desc->window_max_entries = max_entries; } +static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) +{ + unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr); + + for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { + qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL); + } +} + +static void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr) +{ + /* Discard jump cache entries for any tb which might potentially + overlap the flushed page. */ + tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); + tb_jmp_cache_clear_page(cpu, addr); +} + /** * tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary * @desc: The CPUTLBDesc portion of the TLB diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index ca7ef6aa17..5bd0e267c8 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -2461,23 +2461,6 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) cpu_loop_exit_noexc(cpu); } -static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) -{ - unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr); - - for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { - qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL); - } -} - -void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr) -{ - /* Discard jump cache entries for any tb which might potentially - overlap the flushed page. */ - tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); - tb_jmp_cache_clear_page(cpu, addr); -} - static void print_qht_statistics(struct qht_stats hst) { uint32_t hgram_opts; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 516013e735..1e3e7cf8e7 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -663,9 +663,6 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length); void tlb_set_dirty(CPUState *cpu, target_ulong vaddr); -/* exec.c */ -void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr); - MemoryRegionSection * address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, hwaddr *xlat, hwaddr *plen, From c03f041f128301c6a6c32242846be08719cd4fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 20 Jan 2021 20:15:06 -1000 Subject: [PATCH 06/10] accel/tcg: Restrict tb_gen_code() from other accelerators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tb_gen_code() is only called within TCG accelerator, declare it locally. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210117164813.4101761-4-f4bug@amsat.org> [rth: Adjust vs changed tb_flush_jmp_cache patch.] Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 + accel/tcg/internal.h | 18 ++++++++++++++++++ accel/tcg/translate-all.c | 1 + include/exec/exec-all.h | 5 ----- 4 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 accel/tcg/internal.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 8053aa3f11..37d17c8e88 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -41,6 +41,7 @@ #include "exec/cpu-all.h" #include "sysemu/cpu-timers.h" #include "sysemu/replay.h" +#include "internal.h" /* -icount align implementation. */ diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h new file mode 100644 index 0000000000..06b341fceb --- /dev/null +++ b/accel/tcg/internal.h @@ -0,0 +1,18 @@ +/* + * Internal execution defines for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef ACCEL_TCG_INTERNAL_H +#define ACCEL_TCG_INTERNAL_H + +#include "exec/exec-all.h" + +TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, + target_ulong cs_base, uint32_t flags, + int cflags); + +#endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 5bd0e267c8..73fef47148 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -60,6 +60,7 @@ #include "sysemu/cpu-timers.h" #include "sysemu/tcg.h" #include "qapi/error.h" +#include "internal.h" /* #define DEBUG_TB_INVALIDATE */ /* #define DEBUG_TB_FLUSH */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 1e3e7cf8e7..3acc7c2943 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -64,11 +64,6 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc, bool will_exit); void QEMU_NORETURN cpu_loop_exit_noexc(CPUState *cpu); void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); -TranslationBlock *tb_gen_code(CPUState *cpu, - target_ulong pc, target_ulong cs_base, - uint32_t flags, - int cflags); - void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); void QEMU_NORETURN cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); From ee64036a4bec9fe79919812beddcf1a5f51f6bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 17 Jan 2021 17:48:11 +0100 Subject: [PATCH 07/10] accel/tcg: Declare missing cpu_loop_exit*() stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_loop_exit*() functions are declared in accel/tcg/cpu-exec-common.c, and are not available when TCG accelerator is not built. Add stubs so linking without TCG succeed. Problematic files: - hw/semihosting/console.c in qemu_semihosting_console_inc() - hw/ppc/spapr_hcall.c in h_confer() - hw/s390x/ipl.c in s390_ipl_reset_request() - hw/misc/mips_itu.c Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210117164813.4101761-5-f4bug@amsat.org> Signed-off-by: Richard Henderson --- accel/stubs/tcg-stub.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 8c18d3eabd..2304606f8e 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -28,3 +28,13 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, /* Handled by hardware accelerator. */ g_assert_not_reached(); } + +void QEMU_NORETURN cpu_loop_exit(CPUState *cpu) +{ + g_assert_not_reached(); +} + +void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc) +{ + g_assert_not_reached(); +} From 65269192241104342e3b1ba2b7b0f50e5042052e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 17 Jan 2021 17:48:12 +0100 Subject: [PATCH 08/10] accel/tcg: Restrict cpu_io_recompile() from other accelerators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As cpu_io_recompile() is only called within TCG accelerator in cputlb.c, declare it locally. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210117164813.4101761-6-f4bug@amsat.org> [rth: Adjust vs changed tb_flush_jmp_cache patch.] Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 1 + accel/tcg/internal.h | 2 ++ include/exec/exec-all.h | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 0fa1643ed3..7a69726ba4 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -37,6 +37,7 @@ #include "exec/translate-all.h" #include "trace/trace-root.h" #include "trace/mem.h" +#include "internal.h" #ifdef CONFIG_PLUGIN #include "qemu/plugin-memory.h" #endif diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 06b341fceb..e9c145e0fb 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -15,4 +15,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, target_ulong cs_base, uint32_t flags, int cflags); +void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); + #endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 3acc7c2943..125000bcf7 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -63,7 +63,6 @@ void restore_state_to_opc(CPUArchState *env, TranslationBlock *tb, bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc, bool will_exit); void QEMU_NORETURN cpu_loop_exit_noexc(CPUState *cpu); -void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); void QEMU_NORETURN cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); From 653b87eb36045b506b79f0bb433016ef1c54bc9a Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Wed, 13 Jan 2021 06:28:07 +0300 Subject: [PATCH 09/10] tcg: Toggle page execution for Apple Silicon Pages can't be both write and executable at the same time on Apple Silicon. macOS provides public API to switch write protection [1] for JIT applications, like TCG. 1. https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon Tested-by: Alexander Graf Signed-off-by: Roman Bolshakov Message-Id: <20210113032806.18220-1-r.bolshakov@yadro.com> [rth: Inline the qemu_thread_jit_* functions; drop the MAP_JIT change for a follow-on patch.] Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 2 ++ accel/tcg/translate-all.c | 3 +++ include/qemu/osdep.h | 28 ++++++++++++++++++++++++++++ tcg/tcg.c | 1 + 4 files changed, 34 insertions(+) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 37d17c8e88..6d017e46dd 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -186,6 +186,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) } #endif /* DEBUG_DISAS */ + qemu_thread_jit_execute(); ret = tcg_qemu_tb_exec(env, tb_ptr); cpu->can_do_io = 1; /* @@ -410,6 +411,7 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, { uintptr_t old; + qemu_thread_jit_write(); assert(n < ARRAY_SIZE(tb->jmp_list_next)); qemu_spin_lock(&tb_next->jmp_lock); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 73fef47148..d09c187e0f 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1670,7 +1670,9 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) static void tb_phys_invalidate__locked(TranslationBlock *tb) { + qemu_thread_jit_write(); do_tb_phys_invalidate(tb, true); + qemu_thread_jit_execute(); } /* invalidate one TB @@ -1872,6 +1874,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, #endif assert_memory_lock(); + qemu_thread_jit_write(); phys_pc = get_page_addr_code(env, pc); diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index a434382c58..b6ffdc15bf 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -119,6 +119,10 @@ extern int daemon(int, int); #include "sysemu/os-posix.h" #endif +#ifdef __APPLE__ +#include +#endif + #include "glib-compat.h" #include "qemu/typedefs.h" @@ -682,4 +686,28 @@ char *qemu_get_host_name(Error **errp); */ size_t qemu_get_host_physmem(void); +/* + * Toggle write/execute on the pages marked MAP_JIT + * for the current thread. + */ +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 +static inline void qemu_thread_jit_execute(void) +{ + if (__builtin_available(macOS 11.0, *)) { + pthread_jit_write_protect_np(true); + } +} + +static inline void qemu_thread_jit_write(void) +{ + if (__builtin_available(macOS 11.0, *)) { + pthread_jit_write_protect_np(false); + } +} +#else +static inline void qemu_thread_jit_write(void) {} +static inline void qemu_thread_jit_execute(void) {} +#endif + #endif diff --git a/tcg/tcg.c b/tcg/tcg.c index 8f8badb61c..67b08f708d 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1112,6 +1112,7 @@ void tcg_prologue_init(TCGContext *s) s->pool_labels = NULL; #endif + qemu_thread_jit_write(); /* Generate the prologue. */ tcg_target_qemu_prologue(s); From ae30e86661b0f48562cd95918d37cbeec5d02262 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 23 Jan 2021 12:11:17 -1000 Subject: [PATCH 10/10] tcg: Restart code generation when we run out of temps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some large translation blocks can generate so many unique constants that we run out of temps to hold them. In this case, longjmp back to the start of code generation and restart with a smaller translation block. Buglink: https://bugs.launchpad.net/bugs/1912065 Tested-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 15 ++++++++++++++- include/tcg/tcg.h | 3 +++ tcg/tcg.c | 11 ++++++++--- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index d09c187e0f..81d4c83f22 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1926,11 +1926,17 @@ TranslationBlock *tb_gen_code(CPUState *cpu, ti = profile_getclock(); #endif + gen_code_size = sigsetjmp(tcg_ctx->jmp_trans, 0); + if (unlikely(gen_code_size != 0)) { + goto error_return; + } + tcg_func_start(tcg_ctx); tcg_ctx->cpu = env_cpu(env); gen_intermediate_code(cpu, tb, max_insns); tcg_ctx->cpu = NULL; + max_insns = tb->icount; trace_translate_block(tb, tb->pc, tb->tc.ptr); @@ -1955,6 +1961,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, gen_code_size = tcg_gen_code(tcg_ctx, tb); if (unlikely(gen_code_size < 0)) { + error_return: switch (gen_code_size) { case -1: /* @@ -1966,6 +1973,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu, * flush the TBs, allocate a new TB, re-initialize it per * above, and re-do the actual code generation. */ + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation for " + "code_gen_buffer overflow\n"); goto buffer_overflow; case -2: @@ -1978,9 +1988,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu, * Try again with half as many insns as we attempted this time. * If a single insn overflows, there's a bug somewhere... */ - max_insns = tb->icount; assert(max_insns > 1); max_insns /= 2; + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation with " + "smaller translation block (max %d insns)\n", + max_insns); goto tb_overflow; default: diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index c5a9d65d5f..0f0695e90d 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -680,6 +680,9 @@ struct TCGContext { uint16_t gen_insn_end_off[TCG_MAX_INSNS]; target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS]; + + /* Exit to translator on overflow. */ + sigjmp_buf jmp_trans; }; static inline bool temp_readonly(TCGTemp *ts) diff --git a/tcg/tcg.c b/tcg/tcg.c index 67b08f708d..9e1b0d73c7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1205,18 +1205,23 @@ void tcg_func_start(TCGContext *s) QSIMPLEQ_INIT(&s->labels); } -static inline TCGTemp *tcg_temp_alloc(TCGContext *s) +static TCGTemp *tcg_temp_alloc(TCGContext *s) { int n = s->nb_temps++; - tcg_debug_assert(n < TCG_MAX_TEMPS); + + if (n >= TCG_MAX_TEMPS) { + /* Signal overflow, starting over with fewer guest insns. */ + siglongjmp(s->jmp_trans, -2); + } return memset(&s->temps[n], 0, sizeof(TCGTemp)); } -static inline TCGTemp *tcg_global_alloc(TCGContext *s) +static TCGTemp *tcg_global_alloc(TCGContext *s) { TCGTemp *ts; tcg_debug_assert(s->nb_globals == s->nb_temps); + tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); s->nb_globals++; ts = tcg_temp_alloc(s); ts->kind = TEMP_GLOBAL;