From d157e540edc2dbc30b66c26d8378c724ffcac8d0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 22 Jan 2024 16:34:09 +0100 Subject: [PATCH 01/31] cpu-exec: simplify jump cache management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unless I'm missing something egregious, the jmp cache is only every populated with a valid entry by the same thread that reads the cache. Therefore, the contents of any valid entry are always consistent and there is no need for any acquire/release magic. Indeed ->tb has to be accessed with atomics, because concurrent invalidations would otherwise cause data races. But ->pc is only ever accessed by one thread, and accesses to ->tb and ->pc within tb_lookup can never race with another tb_lookup. While the TranslationBlock (especially the flags) could be modified by a concurrent invalidation, store-release and load-acquire operations on the cache entry would not add any additional ordering beyond what you get from performing the accesses within a single thread. Because of this, there is really nothing to win in splitting the CF_PCREL and !CF_PCREL paths. It is easier to just always use the ->pc field in the jump cache. I noticed this while working on splitting commit 8ed558ec0cb ("accel/tcg: Introduce TARGET_TB_PCREL", 2022-10-04) into multiple pieces, for the sake of finding a more fine-grained bisection result for https://gitlab.com/qemu-project/qemu/-/issues/2092. It does not (and does not intend to) fix that issue; therefore it may make sense to not commit it until the root cause of issue #2092 is found. Signed-off-by: Paolo Bonzini Tested-by: Alex Bennée Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20240122153409.351959-1-pbonzini@redhat.com> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 66 ++++++++++++++-------------------------- accel/tcg/tb-jmp-cache.h | 8 +++-- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 67eda9865e..40c268bfa1 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -253,43 +253,29 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, vaddr pc, hash = tb_jmp_cache_hash_func(pc); jc = cpu->tb_jmp_cache; - if (cflags & CF_PCREL) { - /* Use acquire to ensure current load of pc from jc. */ - tb = qatomic_load_acquire(&jc->array[hash].tb); - - if (likely(tb && - jc->array[hash].pc == pc && - tb->cs_base == cs_base && - tb->flags == flags && - tb_cflags(tb) == cflags)) { - return tb; - } - tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags); - if (tb == NULL) { - return NULL; - } - jc->array[hash].pc = pc; - /* Ensure pc is written first. */ - qatomic_store_release(&jc->array[hash].tb, tb); - } else { - /* Use rcu_read to ensure current load of pc from *tb. */ - tb = qatomic_rcu_read(&jc->array[hash].tb); - - if (likely(tb && - tb->pc == pc && - tb->cs_base == cs_base && - tb->flags == flags && - tb_cflags(tb) == cflags)) { - return tb; - } - tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags); - if (tb == NULL) { - return NULL; - } - /* Use the pc value already stored in tb->pc. */ - qatomic_set(&jc->array[hash].tb, tb); + tb = qatomic_read(&jc->array[hash].tb); + if (likely(tb && + jc->array[hash].pc == pc && + tb->cs_base == cs_base && + tb->flags == flags && + tb_cflags(tb) == cflags)) { + goto hit; } + tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags); + if (tb == NULL) { + return NULL; + } + + jc->array[hash].pc = pc; + qatomic_set(&jc->array[hash].tb, tb); + +hit: + /* + * As long as tb is not NULL, the contents are consistent. Therefore, + * the virtual PC has to match for non-CF_PCREL translations. + */ + assert((tb_cflags(tb) & CF_PCREL) || tb->pc == pc); return tb; } @@ -1012,14 +998,8 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) */ h = tb_jmp_cache_hash_func(pc); jc = cpu->tb_jmp_cache; - if (cflags & CF_PCREL) { - jc->array[h].pc = pc; - /* Ensure pc is written first. */ - qatomic_store_release(&jc->array[h].tb, tb); - } else { - /* Use the pc value already stored in tb->pc. */ - qatomic_set(&jc->array[h].tb, tb); - } + jc->array[h].pc = pc; + qatomic_set(&jc->array[h].tb, tb); } #ifndef CONFIG_USER_ONLY diff --git a/accel/tcg/tb-jmp-cache.h b/accel/tcg/tb-jmp-cache.h index bb424c8a05..4ab8553afc 100644 --- a/accel/tcg/tb-jmp-cache.h +++ b/accel/tcg/tb-jmp-cache.h @@ -13,9 +13,11 @@ #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) /* - * Accessed in parallel; all accesses to 'tb' must be atomic. - * For CF_PCREL, accesses to 'pc' must be protected by a - * load_acquire/store_release to 'tb'. + * Invalidated in parallel; all accesses to 'tb' must be atomic. + * A valid entry is read/written by a single CPU, therefore there is + * no need for qatomic_rcu_read() and pc is always consistent with a + * non-NULL value of 'tb'. Strictly speaking pc is only needed for + * CF_PCREL, but it's used always for simplicity. */ struct CPUJumpCache { struct rcu_head rcu; From c4b3f46c15153308054703c7b0053f2bad26242d Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:39:56 +0100 Subject: [PATCH 02/31] include/exec: Move vaddr defines to separate file Needed to work around circular includes. vaddr is currently defined in cpu-common.h and needed by hw/core/cpu.h, but cpu-common.h also need cpu.h to know the size of the CPUState. [Maybe we can instead move parts of cpu-common.h w. hw/core/cpu.h to sort out the circular inclusion.] Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-7-anjo@rev.ng> Reviewed-by: Richard Henderson [rth: Add include of vaddr.h into cpu-common.h] Signed-off-by: Richard Henderson --- include/exec/cpu-common.h | 13 +------------ include/exec/vaddr.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 include/exec/vaddr.h diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index fef3138d29..3109c6b67d 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -3,6 +3,7 @@ /* CPU interfaces that are target independent. */ +#include "exec/vaddr.h" #ifndef CONFIG_USER_ONLY #include "exec/hwaddr.h" #endif @@ -14,18 +15,6 @@ #define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */ #define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */ -/** - * vaddr: - * Type wide enough to contain any #target_ulong virtual address. - */ -typedef uint64_t vaddr; -#define VADDR_PRId PRId64 -#define VADDR_PRIu PRIu64 -#define VADDR_PRIo PRIo64 -#define VADDR_PRIx PRIx64 -#define VADDR_PRIX PRIX64 -#define VADDR_MAX UINT64_MAX - void cpu_exec_init_all(void); void cpu_exec_step_atomic(CPUState *cpu); diff --git a/include/exec/vaddr.h b/include/exec/vaddr.h new file mode 100644 index 0000000000..b9844afc77 --- /dev/null +++ b/include/exec/vaddr.h @@ -0,0 +1,18 @@ +/* Define vaddr. */ + +#ifndef VADDR_H +#define VADDR_H + +/** + * vaddr: + * Type wide enough to contain any #target_ulong virtual address. + */ +typedef uint64_t vaddr; +#define VADDR_PRId PRId64 +#define VADDR_PRIu PRIu64 +#define VADDR_PRIo PRIo64 +#define VADDR_PRIx PRIx64 +#define VADDR_PRIX PRIX64 +#define VADDR_MAX UINT64_MAX + +#endif From 61d6a915132db4616f601d5144fdac45f429a4cd Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:39:57 +0100 Subject: [PATCH 03/31] hw/core: Include vaddr.h from cpu.h cpu-common.h is only needed for vaddr Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-8-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/hw/core/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 238c02c05e..db58f12233 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -22,8 +22,8 @@ #include "hw/qdev-core.h" #include "disas/dis-asm.h" -#include "exec/cpu-common.h" #include "exec/hwaddr.h" +#include "exec/vaddr.h" #include "exec/memattrs.h" #include "exec/tlb-common.h" #include "qapi/qapi-types-run-state.h" From 32f0c394bbf7fb2be635658cbf84c72a124720a0 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:39:58 +0100 Subject: [PATCH 04/31] target: Use vaddr in gen_intermediate_code Makes gen_intermediate_code() signature target agnostic so the function can be called from accel/tcg/translate-all.c without target specifics. Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-9-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/exec/translator.h | 2 +- target/alpha/translate.c | 2 +- target/arm/tcg/translate.c | 2 +- target/avr/translate.c | 2 +- target/cris/translate.c | 2 +- target/hexagon/translate.c | 2 +- target/hppa/translate.c | 2 +- target/i386/tcg/translate.c | 2 +- target/loongarch/tcg/translate.c | 2 +- target/m68k/translate.c | 2 +- target/microblaze/translate.c | 2 +- target/mips/tcg/translate.c | 2 +- target/nios2/translate.c | 2 +- target/openrisc/translate.c | 2 +- target/ppc/translate.c | 2 +- target/riscv/translate.c | 2 +- target/rx/translate.c | 2 +- target/s390x/tcg/translate.c | 2 +- target/sh4/translate.c | 2 +- target/sparc/translate.c | 2 +- target/tricore/translate.c | 2 +- target/xtensa/translate.c | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/exec/translator.h b/include/exec/translator.h index 6d3f59d095..b0412ea6b6 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -33,7 +33,7 @@ * the target-specific DisasContext, and then invoke translator_loop. */ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc); + vaddr pc, void *host_pc); /** * DisasJumpType: diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 32333081d8..134eb7225b 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -2971,7 +2971,7 @@ static const TranslatorOps alpha_tr_ops = { }; void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; translator_loop(cpu, tb, max_insns, pc, host_pc, &alpha_tr_ops, &dc.base); diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index b3660173d1..5fa8249723 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -9691,7 +9691,7 @@ static const TranslatorOps thumb_translator_ops = { /* generate intermediate code for basic block 'tb'. */ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc = { }; const TranslatorOps *ops = &arm_translator_ops; diff --git a/target/avr/translate.c b/target/avr/translate.c index cdffa04519..e5dd057799 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2805,7 +2805,7 @@ static const TranslatorOps avr_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc = { }; translator_loop(cs, tb, max_insns, pc, host_pc, &avr_tr_ops, &dc.base); diff --git a/target/cris/translate.c b/target/cris/translate.c index b3974ba0bb..ee1402a9a3 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -3172,7 +3172,7 @@ static const TranslatorOps cris_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; translator_loop(cs, tb, max_insns, pc, host_pc, &cris_tr_ops, &dc.base); diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 95579ae243..a14211cf68 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -1154,7 +1154,7 @@ static const TranslatorOps hexagon_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 3ef39b1bd7..08d09d50d7 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -4631,7 +4631,7 @@ static const TranslatorOps hppa_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index e193c74472..2808903661 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -7088,7 +7088,7 @@ static const TranslatorOps i386_tr_ops = { /* generate intermediate code for basic block 'tb'. */ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c index 21f4db6fbd..235515c629 100644 --- a/target/loongarch/tcg/translate.c +++ b/target/loongarch/tcg/translate.c @@ -343,7 +343,7 @@ static const TranslatorOps loongarch_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 4a0b0b2703..5ec88c5f0d 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -6088,7 +6088,7 @@ static const TranslatorOps m68k_tr_ops = { }; void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; translator_loop(cpu, tb, max_insns, pc, host_pc, &m68k_tr_ops, &dc.base); diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 49bfb4a0ea..2e628647d1 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1792,7 +1792,7 @@ static const TranslatorOps mb_tr_ops = { }; void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base); diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 13e43fa3b6..e10232738c 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -15554,7 +15554,7 @@ static const TranslatorOps mips_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/nios2/translate.c b/target/nios2/translate.c index e806623594..3078372b36 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -1036,7 +1036,7 @@ static const TranslatorOps nios2_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base); diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index ecff4412b7..d4cbc5eaea 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1658,7 +1658,7 @@ static const TranslatorOps openrisc_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 329da4d518..049f636927 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7518,7 +7518,7 @@ static const TranslatorOps ppc_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 071fbad7ef..ab18899122 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1287,7 +1287,7 @@ static const TranslatorOps riscv_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/rx/translate.c b/target/rx/translate.c index c6ce717a95..2265bd14ac 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -2266,7 +2266,7 @@ static const TranslatorOps rx_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 8df00b7df9..a5fd9cccaa 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6547,7 +6547,7 @@ static const TranslatorOps s390x_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc; diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 81f825f125..6a6d862b10 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -2317,7 +2317,7 @@ static const TranslatorOps sh4_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 9387299559..97184fa403 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -5327,7 +5327,7 @@ static const TranslatorOps sparc_tr_ops = { }; void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc = {}; diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 66553d1be0..f1156c39e7 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8472,7 +8472,7 @@ static const TranslatorOps tricore_tr_ops = { void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext ctx; translator_loop(cs, tb, max_insns, pc, host_pc, diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 87947236ca..e4772462b5 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1239,7 +1239,7 @@ static const TranslatorOps xtensa_translator_ops = { }; void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc) + vaddr pc, void *host_pc) { DisasContext dc = {}; translator_loop(cpu, tb, max_insns, pc, host_pc, From 85c19af63e7d1070062e5513bfcab223b93653f3 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:39:59 +0100 Subject: [PATCH 05/31] include/exec: Use vaddr in DisasContextBase for virtual addresses Updates target/ QEMU_LOG macros to use VADDR_PRIx for printing updated DisasContextBase fields. Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-10-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/exec/translator.h | 6 +++--- target/hexagon/translate.c | 3 ++- target/m68k/translate.c | 2 +- target/mips/tcg/translate.c | 12 ++++++------ target/mips/tcg/translate.h | 3 ++- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/exec/translator.h b/include/exec/translator.h index b0412ea6b6..51624feb10 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -79,8 +79,8 @@ typedef enum DisasJumpType { */ typedef struct DisasContextBase { TranslationBlock *tb; - target_ulong pc_first; - target_ulong pc_next; + vaddr pc_first; + vaddr pc_next; DisasJumpType is_jmp; int num_insns; int max_insns; @@ -235,7 +235,7 @@ void translator_fake_ldb(uint8_t insn8, abi_ptr pc); * Translators can use this to enforce the rule that only single-insn * translation blocks are allowed to cross page boundaries. */ -static inline bool is_same_page(const DisasContextBase *db, target_ulong addr) +static inline bool is_same_page(const DisasContextBase *db, vaddr addr) { return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0; } diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index a14211cf68..f163eefe97 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -234,7 +234,8 @@ static int read_packet_words(CPUHexagonState *env, DisasContext *ctx, g_assert(ctx->base.num_insns == 1); } - HEX_DEBUG_LOG("decode_packet: pc = 0x%x\n", ctx->base.pc_next); + HEX_DEBUG_LOG("decode_packet: pc = 0x%" VADDR_PRIx "\n", + ctx->base.pc_next); HEX_DEBUG_LOG(" words = { "); for (int i = 0; i < nwords; i++) { HEX_DEBUG_LOG("0x%x, ", words[i]); diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 5ec88c5f0d..f886190f88 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -1457,7 +1457,7 @@ DISAS_INSN(undef) * for the 680x0 series, as well as those that are implemented * but actually illegal for CPU32 or pre-68020. */ - qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n", + qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %" VADDR_PRIx "\n", insn, s->base.pc_next); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL); } diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index e10232738c..12094cc1e7 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -4585,8 +4585,8 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay / forbidden slot at PC 0x" - TARGET_FMT_lx "\n", ctx->base.pc_next); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x%016" + VADDR_PRIx "\n", ctx->base.pc_next); #endif gen_reserved_instruction(ctx); goto out; @@ -9061,8 +9061,8 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx - "\n", ctx->base.pc_next); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x%016" + VADDR_PRIx "\n", ctx->base.pc_next); #endif gen_reserved_instruction(ctx); return; @@ -11274,8 +11274,8 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx - "\n", ctx->base.pc_next); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x%016" + VADDR_PRIx "\n", ctx->base.pc_next); #endif gen_reserved_instruction(ctx); return; diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index cffcfeab8c..93a78b8121 100644 --- a/target/mips/tcg/translate.h +++ b/target/mips/tcg/translate.h @@ -202,7 +202,8 @@ extern TCGv bcond; do { \ if (MIPS_DEBUG_DISAS) { \ qemu_log_mask(CPU_LOG_TB_IN_ASM, \ - TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \ + "%016" VADDR_PRIx \ + ": %08x Invalid %s %03x %03x %03x\n", \ ctx->base.pc_next, ctx->opcode, op, \ ctx->opcode >> 26, ctx->opcode & 0x3F, \ ((ctx->opcode >> 16) & 0x1F)); \ From f7ee94f05fe2385e591dc6c8aadd1253e7055490 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:40:00 +0100 Subject: [PATCH 06/31] include/exec: typedef abi_ptr to vaddr Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-11-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/exec/cpu_ldst.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 6061e33ac9..eb8f3f0595 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -121,8 +121,8 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) h2g_nocheck(x); \ }) #else -typedef target_ulong abi_ptr; -#define TARGET_ABI_FMT_ptr TARGET_FMT_lx +typedef vaddr abi_ptr; +#define TARGET_ABI_FMT_ptr VADDR_PRIx #endif uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr); From 58771921af60ede4beb35a4f0871014704405029 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:40:04 +0100 Subject: [PATCH 07/31] include/exec: Move PAGE_* macros to common header These don't vary across targets and are used in soon-to-be common code (cputlb.c). Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-15-anjo@rev.ng> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 24 ------------------------ include/exec/cpu-common.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 5340907cfd..edee87d3f4 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -171,34 +171,10 @@ extern const TargetPageBits target_page; #define TARGET_PAGE_ALIGN(addr) ROUND_UP((addr), TARGET_PAGE_SIZE) -/* same as PROT_xxx */ -#define PAGE_READ 0x0001 -#define PAGE_WRITE 0x0002 -#define PAGE_EXEC 0x0004 -#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) -#define PAGE_VALID 0x0008 -/* - * Original state of the write flag (used when tracking self-modifying code) - */ -#define PAGE_WRITE_ORG 0x0010 -/* - * Invalidate the TLB entry immediately, helpful for s390x - * Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs() - */ -#define PAGE_WRITE_INV 0x0020 -/* For use with page_set_flags: page is being replaced; target_data cleared. */ -#define PAGE_RESET 0x0040 -/* For linux-user, indicates that the page is MAP_ANON. */ -#define PAGE_ANON 0x0080 - #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY) /* FIXME: Code that sets/uses this is broken and needs to go away. */ #define PAGE_RESERVED 0x0100 #endif -/* Target-specific bits that will be used via page_get_flags(). */ -#define PAGE_TARGET_1 0x0200 -#define PAGE_TARGET_2 0x0400 - /* * For linux-user, indicates that the page is mapped with the same semantics * in both guest and host. diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 3109c6b67d..608708ea48 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -206,4 +206,34 @@ G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); G_NORETURN void cpu_loop_exit(CPUState *cpu); G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); +/* same as PROT_xxx */ +#define PAGE_READ 0x0001 +#define PAGE_WRITE 0x0002 +#define PAGE_EXEC 0x0004 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) +#define PAGE_VALID 0x0008 +/* + * Original state of the write flag (used when tracking self-modifying code) + */ +#define PAGE_WRITE_ORG 0x0010 +/* + * Invalidate the TLB entry immediately, helpful for s390x + * Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs() + */ +#define PAGE_WRITE_INV 0x0020 +/* For use with page_set_flags: page is being replaced; target_data cleared. */ +#define PAGE_RESET 0x0040 +/* For linux-user, indicates that the page is MAP_ANON. */ +#define PAGE_ANON 0x0080 + +/* Target-specific bits that will be used via page_get_flags(). */ +#define PAGE_TARGET_1 0x0200 +#define PAGE_TARGET_2 0x0400 + +/* + * For linux-user, indicates that the page is mapped with the same semantics + * in both guest and host. + */ +#define PAGE_PASSTHROUGH 0x0800 + #endif /* CPU_COMMON_H */ From a7f6f4f53fe0d43c37cb2375e3e648f978296941 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Jan 2024 15:40:06 +0100 Subject: [PATCH 08/31] include/exec: Move cpu_*()/cpu_env() to common header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Functions are target independent. Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-17-anjo@rev.ng> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 25 ------------------------- include/exec/cpu-common.h | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index edee87d3f4..8501a33dbf 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -384,33 +384,8 @@ static inline bool tlb_hit(uint64_t tlb_addr, vaddr addr) #endif /* !CONFIG_USER_ONLY */ -/* accel/tcg/cpu-exec.c */ -int cpu_exec(CPUState *cpu); - /* Validate correct placement of CPUArchState. */ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); -/** - * env_archcpu(env) - * @env: The architecture environment - * - * Return the ArchCPU associated with the environment. - */ -static inline ArchCPU *env_archcpu(CPUArchState *env) -{ - return (void *)env - sizeof(CPUState); -} - -/** - * env_cpu(env) - * @env: The architecture environment - * - * Return the CPUState associated with the environment. - */ -static inline CPUState *env_cpu(CPUArchState *env) -{ - return (void *)env - sizeof(CPUState); -} - #endif /* CPU_ALL_H */ diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 608708ea48..dcbd5f5783 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -7,6 +7,7 @@ #ifndef CONFIG_USER_ONLY #include "exec/hwaddr.h" #endif +#include "hw/core/cpu.h" #define EXCP_INTERRUPT 0x10000 /* async interruption */ #define EXCP_HLT 0x10001 /* hlt instruction reached */ @@ -236,4 +237,29 @@ G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); */ #define PAGE_PASSTHROUGH 0x0800 +/* accel/tcg/cpu-exec.c */ +int cpu_exec(CPUState *cpu); + +/** + * env_archcpu(env) + * @env: The architecture environment + * + * Return the ArchCPU associated with the environment. + */ +static inline ArchCPU *env_archcpu(CPUArchState *env) +{ + return (void *)env - sizeof(CPUState); +} + +/** + * env_cpu(env) + * @env: The architecture environment + * + * Return the CPUState associated with the environment. + */ +static inline CPUState *env_cpu(CPUArchState *env) +{ + return (void *)env - sizeof(CPUState); +} + #endif /* CPU_COMMON_H */ From b11cdf27482af998a3fa42f36bc17a3f59404037 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Sun, 28 Jan 2024 10:24:10 +1000 Subject: [PATCH 09/31] include/hw/core: Move do_interrupt in TCGCPUOps The ifdef out of which it is moved is not quite right: do_interrupt is only needed for system mode. Move it to the top of a different ifdef block, which preserves its position within the structure for that case. Signed-off-by: Anton Johansson Message-Id: <20240119144024.14289-18-anjo@rev.ng> [rth: Split from a larger patch and simplified.] Signed-off-by: Richard Henderson --- include/hw/core/tcg-cpu-ops.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index 479713a36e..d6fe55d471 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -58,11 +58,6 @@ struct TCGCPUOps { * cpu execution loop (hack for x86 user mode). */ void (*fake_user_interrupt)(CPUState *cpu); -#else - /** - * @do_interrupt: Callback for interrupt handling. - */ - void (*do_interrupt)(CPUState *cpu); #endif /* !CONFIG_USER_ONLY || !TARGET_I386 */ #ifdef CONFIG_USER_ONLY /** @@ -114,6 +109,8 @@ struct TCGCPUOps { void (*record_sigbus)(CPUState *cpu, vaddr addr, MMUAccessType access_type, uintptr_t ra); #else + /** @do_interrupt: Callback for interrupt handling. */ + void (*do_interrupt)(CPUState *cpu); /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */ bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request); /** From fd3f7d24d48d3a70afe30af60bdbacdb993af945 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Sun, 28 Jan 2024 10:32:47 +1000 Subject: [PATCH 10/31] include/hw/core: Remove i386 conditional on fake_user_interrupt Always include fake_user_interrupt in user-only build, despite only being used for i386. This will enable cpu-exec.c to be compiled only once. Signed-off-by: Anton Johansson Message-ID: <20240119144024.14289-18-anjo@rev.ng> [rth: Split out of a larger patch; remove TARGET_I386 conditional.] Signed-off-by: Richard Henderson --- include/hw/core/tcg-cpu-ops.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index d6fe55d471..3ed279836f 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -50,7 +50,7 @@ struct TCGCPUOps { void (*debug_excp_handler)(CPUState *cpu); #ifdef NEED_CPU_H -#if defined(CONFIG_USER_ONLY) && defined(TARGET_I386) +#ifdef CONFIG_USER_ONLY /** * @fake_user_interrupt: Callback for 'fake exception' handling. * @@ -58,8 +58,7 @@ struct TCGCPUOps { * cpu execution loop (hack for x86 user mode). */ void (*fake_user_interrupt)(CPUState *cpu); -#endif /* !CONFIG_USER_ONLY || !TARGET_I386 */ -#ifdef CONFIG_USER_ONLY + /** * record_sigsegv: * @cpu: cpu context From 87ab270429618c13a6bf6dfc90d5edf6a3fa99b9 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 29 Jan 2024 10:32:14 +0100 Subject: [PATCH 11/31] linux-user: Allow gdbstub to ignore page protection gdbserver ignores page protection by virtue of using /proc/$pid/mem. Teach qemu gdbstub to do this too. This will not work if /proc is not mounted; accept this limitation. One alternative is to temporarily grant the missing PROT_* bit, but this is inherently racy. Another alternative is self-debugging with ptrace(POKE), which will break if QEMU itself is being debugged - a much more severe limitation. Reviewed-by: Richard Henderson Signed-off-by: Ilya Leoshkevich Message-Id: <20240129093410.3151-2-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- cpu-target.c | 78 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index f6e07c3deb..958d63e882 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -382,6 +382,9 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, vaddr l, page; void * p; uint8_t *buf = ptr; + ssize_t written; + int ret = -1; + int fd = -1; while (len > 0) { page = addr & TARGET_PAGE_MASK; @@ -389,30 +392,75 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, if (l > len) l = len; flags = page_get_flags(page); - if (!(flags & PAGE_VALID)) - return -1; + if (!(flags & PAGE_VALID)) { + goto out_close; + } if (is_write) { - if (!(flags & PAGE_WRITE)) - return -1; + if (flags & PAGE_WRITE) { + /* XXX: this code should not depend on lock_user */ + p = lock_user(VERIFY_WRITE, addr, l, 0); + if (!p) { + goto out_close; + } + memcpy(p, buf, l); + unlock_user(p, addr, l); + } else { + /* Bypass the host page protection using ptrace. */ + if (fd == -1) { + fd = open("/proc/self/mem", O_WRONLY); + if (fd == -1) { + goto out; + } + } + /* + * If there is a TranslationBlock and we weren't bypassing the + * host page protection, the memcpy() above would SEGV, + * ultimately leading to page_unprotect(). So invalidate the + * translations manually. Both invalidation and pwrite() must + * be under mmap_lock() in order to prevent the creation of + * another TranslationBlock in between. + */ + mmap_lock(); + tb_invalidate_phys_range(addr, addr + l - 1); + written = pwrite(fd, buf, l, + (off_t)(uintptr_t)g2h_untagged(addr)); + mmap_unlock(); + if (written != l) { + goto out_close; + } + } + } else if (flags & PAGE_READ) { /* XXX: this code should not depend on lock_user */ - if (!(p = lock_user(VERIFY_WRITE, addr, l, 0))) - return -1; - memcpy(p, buf, l); - unlock_user(p, addr, l); - } else { - if (!(flags & PAGE_READ)) - return -1; - /* XXX: this code should not depend on lock_user */ - if (!(p = lock_user(VERIFY_READ, addr, l, 1))) - return -1; + p = lock_user(VERIFY_READ, addr, l, 1); + if (!p) { + goto out_close; + } memcpy(buf, p, l); unlock_user(p, addr, 0); + } else { + /* Bypass the host page protection using ptrace. */ + if (fd == -1) { + fd = open("/proc/self/mem", O_RDONLY); + if (fd == -1) { + goto out; + } + } + if (pread(fd, buf, l, + (off_t)(uintptr_t)g2h_untagged(addr)) != l) { + goto out_close; + } } len -= l; buf += l; addr += l; } - return 0; + ret = 0; +out_close: + if (fd != -1) { + close(fd); + } +out: + return ret; } #endif From 4d48c1bc079147a02ec1a3df9a41497c515d2e61 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 29 Jan 2024 10:32:15 +0100 Subject: [PATCH 12/31] tests/tcg: Factor out gdbstub test functions Both the report() function as well as the initial gdbstub test sequence are copy-pasted into ~10 files with slight modifications. This indicates that they are indeed generic, so factor them out. While at it, add a few newlines to make the formatting closer to PEP-8. Signed-off-by: Ilya Leoshkevich Message-Id: <20240129093410.3151-3-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- tests/guest-debug/run-test.py | 7 ++- tests/guest-debug/test_gdbstub.py | 60 +++++++++++++++++++ tests/tcg/aarch64/gdbstub/test-sve-ioctl.py | 34 +---------- tests/tcg/aarch64/gdbstub/test-sve.py | 33 +--------- tests/tcg/multiarch/gdbstub/interrupt.py | 47 ++------------- tests/tcg/multiarch/gdbstub/memory.py | 39 +----------- tests/tcg/multiarch/gdbstub/registers.py | 41 ++----------- tests/tcg/multiarch/gdbstub/sha1.py | 38 ++---------- .../multiarch/gdbstub/test-proc-mappings.py | 39 +----------- .../multiarch/gdbstub/test-qxfer-auxv-read.py | 37 +----------- .../gdbstub/test-thread-breakpoint.py | 37 +----------- tests/tcg/s390x/gdbstub/test-signals-s390x.py | 42 +------------ tests/tcg/s390x/gdbstub/test-svc.py | 39 +----------- 13 files changed, 98 insertions(+), 395 deletions(-) create mode 100644 tests/guest-debug/test_gdbstub.py diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py index b13b27d4b1..368ff8a890 100755 --- a/tests/guest-debug/run-test.py +++ b/tests/guest-debug/run-test.py @@ -97,7 +97,12 @@ def log(output, msg): sleep(1) log(output, "GDB CMD: %s" % (gdb_cmd)) - result = subprocess.call(gdb_cmd, shell=True, stdout=output, stderr=stderr) + gdb_env = dict(os.environ) + gdb_pythonpath = gdb_env.get("PYTHONPATH", "").split(os.pathsep) + gdb_pythonpath.append(os.path.dirname(os.path.realpath(__file__))) + gdb_env["PYTHONPATH"] = os.pathsep.join(gdb_pythonpath) + result = subprocess.call(gdb_cmd, shell=True, stdout=output, stderr=stderr, + env=gdb_env) # A result of greater than 128 indicates a fatal signal (likely a # crash due to gdb internal failure). That's a problem for GDB and diff --git a/tests/guest-debug/test_gdbstub.py b/tests/guest-debug/test_gdbstub.py new file mode 100644 index 0000000000..7f71d34da1 --- /dev/null +++ b/tests/guest-debug/test_gdbstub.py @@ -0,0 +1,60 @@ +"""Helper functions for gdbstub testing + +""" +from __future__ import print_function +import gdb +import os +import sys +import traceback + +fail_count = 0 + + +def report(cond, msg): + """Report success/fail of a test""" + if cond: + print("PASS: {}".format(msg)) + else: + print("FAIL: {}".format(msg)) + global fail_count + fail_count += 1 + + +def main(test, expected_arch=None): + """Run a test function + + This runs as the script it sourced (via -x, via run-test.py).""" + try: + inferior = gdb.selected_inferior() + arch = inferior.architecture() + print("ATTACHED: {}".format(arch.name())) + if expected_arch is not None: + report(arch.name() == expected_arch, + "connected to {}".format(expected_arch)) + except (gdb.error, AttributeError): + print("SKIP: not connected") + exit(0) + + if gdb.parse_and_eval("$pc") == 0: + print("SKIP: PC not set") + exit(0) + + try: + test() + except: + print("GDB Exception:") + traceback.print_exc(file=sys.stdout) + global fail_count + fail_count += 1 + if "QEMU_TEST_INTERACTIVE" in os.environ: + import code + code.InteractiveConsole(locals=globals()).interact() + raise + + try: + gdb.execute("kill") + except gdb.error: + pass + + print("All tests complete: {} failures".format(fail_count)) + exit(fail_count) diff --git a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py index ee8d467e59..a78a3a2514 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py +++ b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py @@ -8,19 +8,10 @@ # import gdb -import sys +from test_gdbstub import main, report initial_vlen = 0 -failcount = 0 -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 class TestBreakpoint(gdb.Breakpoint): def __init__(self, sym_name="__sve_ld_done"): @@ -64,26 +55,5 @@ def run_test(): gdb.execute("c") -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - report(arch.name() == "aarch64", "connected to aarch64") -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) -try: - # Run the actual tests - run_test() -except: - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - import code - code.InteractiveConsole(locals=globals()).interact() - raise - -print("All tests complete: %d failures" % failcount) -exit(failcount) +main(run_test, expected_arch="aarch64") diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py index afd8ece98d..84cdcd4a32 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve.py +++ b/tests/tcg/aarch64/gdbstub/test-sve.py @@ -6,20 +6,10 @@ # import gdb -import sys +from test_gdbstub import main, report MAGIC = 0xDEADBEEF -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 def run_test(): "Run through the tests one by one" @@ -54,24 +44,5 @@ def run_test(): report(str(v.type) == "uint64_t", "size of %s" % (reg)) report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC)) -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - report(arch.name() == "aarch64", "connected to aarch64") -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) -try: - # Run the actual tests - run_test() -except: - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - -print("All tests complete: %d failures" % failcount) - -exit(failcount) +main(run_test, expected_arch="aarch64") diff --git a/tests/tcg/multiarch/gdbstub/interrupt.py b/tests/tcg/multiarch/gdbstub/interrupt.py index c016e7afbb..90a45b5140 100644 --- a/tests/tcg/multiarch/gdbstub/interrupt.py +++ b/tests/tcg/multiarch/gdbstub/interrupt.py @@ -8,19 +8,7 @@ # import gdb -import sys - -failcount = 0 - - -def report(cond, msg): - "Report success/fail of test" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 +from test_gdbstub import main, report def check_interrupt(thread): @@ -59,6 +47,9 @@ def run_test(): Test if interrupting the code always lands us on the same thread when running with scheduler-lock enabled. """ + if len(gdb.selected_inferior().threads()) == 1: + print("SKIP: set to run on a single thread") + exit(0) gdb.execute("set scheduler-locking on") for thread in gdb.selected_inferior().threads(): @@ -66,32 +57,4 @@ def run_test(): "thread %d resumes correctly on interrupt" % thread.num) -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) -if len(gdb.selected_inferior().threads()) == 1: - print("SKIP: set to run on a single thread") - exit(0) - -try: - # Run the actual tests - run_test() -except (gdb.error): - print("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -# Finally kill the inferior and exit gdb with a count of failures -gdb.execute("kill") -exit(failcount) +main(run_test) diff --git a/tests/tcg/multiarch/gdbstub/memory.py b/tests/tcg/multiarch/gdbstub/memory.py index fb1d06b7bb..532b92e7fb 100644 --- a/tests/tcg/multiarch/gdbstub/memory.py +++ b/tests/tcg/multiarch/gdbstub/memory.py @@ -9,18 +9,7 @@ import gdb import sys - -failcount = 0 - - -def report(cond, msg): - "Report success/fail of test" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 +from test_gdbstub import main, report def check_step(): @@ -99,29 +88,5 @@ def run_test(): report(cbp.hit_count == 0, "didn't reach backstop") -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # Run the actual tests - run_test() -except (gdb.error): - print("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -# Finally kill the inferior and exit gdb with a count of failures -gdb.execute("kill") -exit(failcount) +main(run_test) diff --git a/tests/tcg/multiarch/gdbstub/registers.py b/tests/tcg/multiarch/gdbstub/registers.py index 688c061107..b3d13cb077 100644 --- a/tests/tcg/multiarch/gdbstub/registers.py +++ b/tests/tcg/multiarch/gdbstub/registers.py @@ -7,20 +7,11 @@ # SPDX-License-Identifier: GPL-2.0-or-later import gdb -import sys import xml.etree.ElementTree as ET +from test_gdbstub import main, report + initial_vlen = 0 -failcount = 0 - -def report(cond, msg): - "Report success/fail of test." - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 def fetch_xml_regmap(): @@ -75,6 +66,7 @@ def fetch_xml_regmap(): return reg_map + def get_register_by_regnum(reg_map, regnum): """ Helper to find a register from the map via its XML regnum @@ -84,6 +76,7 @@ def get_register_by_regnum(reg_map, regnum): return entry return None + def crosscheck_remote_xml(reg_map): """ Cross-check the list of remote-registers with the XML info. @@ -144,6 +137,7 @@ def crosscheck_remote_xml(reg_map): elif "seen" not in x_reg: print(f"{x_reg} wasn't seen in remote-registers") + def initial_register_read(reg_map): """ Do an initial read of all registers that we know gdb cares about @@ -214,27 +208,4 @@ def run_test(): complete_and_diff(reg_map) -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) +main(run_test) diff --git a/tests/tcg/multiarch/gdbstub/sha1.py b/tests/tcg/multiarch/gdbstub/sha1.py index 416728415f..1ce711a402 100644 --- a/tests/tcg/multiarch/gdbstub/sha1.py +++ b/tests/tcg/multiarch/gdbstub/sha1.py @@ -7,19 +7,11 @@ # import gdb -import sys +from test_gdbstub import main, report + initial_vlen = 0 -failcount = 0 -def report(cond, msg): - "Report success/fail of test" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 def check_break(sym_name): "Setup breakpoint, continue and check we stopped." @@ -35,6 +27,7 @@ def check_break(sym_name): bp.delete() + def run_test(): "Run through the tests one by one" @@ -57,28 +50,5 @@ def run_test(): # finally check we don't barf inspecting registers gdb.execute("info registers") -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # Run the actual tests - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) +main(run_test) diff --git a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py index 04ec61d219..564613fabf 100644 --- a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py +++ b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py @@ -3,20 +3,7 @@ This runs as a sourced script (via -x, via run-test.py).""" from __future__ import print_function import gdb -import sys - - -n_failures = 0 - - -def report(cond, msg): - """Report success/fail of a test""" - if cond: - print("PASS: {}".format(msg)) - else: - print("FAIL: {}".format(msg)) - global n_failures - n_failures += 1 +from test_gdbstub import main, report def run_test(): @@ -37,26 +24,4 @@ def run_test(): # report("/sha1" in mappings, "Found the test binary name in the mappings") -def main(): - """Prepare the environment and run through the tests""" - try: - inferior = gdb.selected_inferior() - print("ATTACHED: {}".format(inferior.architecture().name())) - except (gdb.error, AttributeError): - print("SKIPPING (not connected)") - exit(0) - - if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - - try: - # Run the actual tests - run_test() - except gdb.error: - report(False, "GDB Exception: {}".format(sys.exc_info()[0])) - print("All tests complete: %d failures" % n_failures) - exit(n_failures) - - -main() +main(run_test) diff --git a/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py b/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py index 926fa962b7..00c26ab4a9 100644 --- a/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py +++ b/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py @@ -6,18 +6,8 @@ # import gdb -import sys +from test_gdbstub import main, report -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 def run_test(): "Run through the tests one by one" @@ -26,28 +16,5 @@ def run_test(): report(isinstance(auxv, str), "Fetched auxv from inferior") report(auxv.find("sha1"), "Found test binary name in auxv") -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # Run the actual tests - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) +main(run_test) diff --git a/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py b/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py index e57d2a8db8..4d6b6b9fbe 100644 --- a/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py +++ b/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py @@ -6,18 +6,8 @@ # import gdb -import sys +from test_gdbstub import main, report -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 def run_test(): "Run through the tests one by one" @@ -29,28 +19,5 @@ def run_test(): frame = gdb.selected_frame() report(str(frame.function()) == "thread1_func", "break @ %s"%frame) -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # Run the actual tests - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) +main(run_test) diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py b/tests/tcg/s390x/gdbstub/test-signals-s390x.py index ca2bbc0b03..b6b7b39fc4 100644 --- a/tests/tcg/s390x/gdbstub/test-signals-s390x.py +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py @@ -7,19 +7,7 @@ # import gdb -import sys - -failcount = 0 - - -def report(cond, msg): - """Report success/fail of test""" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 +from test_gdbstub import main, report def run_test(): @@ -42,31 +30,7 @@ def run_test(): gdb.Breakpoint("_exit") gdb.execute("c") status = int(gdb.parse_and_eval("$r2")) - report(status == 0, "status == 0"); + report(status == 0, "status == 0") -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval("$pc") == 0: - print("SKIP: PC not set") - exit(0) - -try: - # Run the actual tests - run_test() -except (gdb.error): - print("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) +main(run_test) diff --git a/tests/tcg/s390x/gdbstub/test-svc.py b/tests/tcg/s390x/gdbstub/test-svc.py index 804705fede..17210b4e02 100644 --- a/tests/tcg/s390x/gdbstub/test-svc.py +++ b/tests/tcg/s390x/gdbstub/test-svc.py @@ -3,20 +3,7 @@ This runs as a sourced script (via -x, via run-test.py).""" from __future__ import print_function import gdb -import sys - - -n_failures = 0 - - -def report(cond, msg): - """Report success/fail of a test""" - if cond: - print("PASS: {}".format(msg)) - else: - print("FAIL: {}".format(msg)) - global n_failures - n_failures += 1 +from test_gdbstub import main, report def run_test(): @@ -35,26 +22,4 @@ def run_test(): gdb.execute("si") -def main(): - """Prepare the environment and run through the tests""" - try: - inferior = gdb.selected_inferior() - print("ATTACHED: {}".format(inferior.architecture().name())) - except (gdb.error, AttributeError): - print("SKIPPING (not connected)") - exit(0) - - if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - - try: - # Run the actual tests - run_test() - except gdb.error: - report(False, "GDB Exception: {}".format(sys.exc_info()[0])) - print("All tests complete: %d failures" % n_failures) - exit(n_failures) - - -main() +main(run_test) From 82607a73f8f6dc84d50a7f9b04ab740cc493d1cc Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 29 Jan 2024 10:32:16 +0100 Subject: [PATCH 13/31] tests/tcg: Add the PROT_NONE gdbstub test Make sure that qemu gdbstub, like gdbserver, allows reading from and writing to PROT_NONE pages. Signed-off-by: Ilya Leoshkevich Message-Id: <20240129093410.3151-4-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- tests/tcg/multiarch/Makefile.target | 9 +++++- tests/tcg/multiarch/gdbstub/prot-none.py | 36 +++++++++++++++++++++ tests/tcg/multiarch/prot-none.c | 40 ++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/multiarch/gdbstub/prot-none.py create mode 100644 tests/tcg/multiarch/prot-none.c diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index d31ba8d6ae..315a2e1358 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -101,13 +101,20 @@ run-gdbstub-registers: sha512 --bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \ checking register enumeration) +run-gdbstub-prot-none: prot-none + $(call run-test, $@, env PROT_NONE_PY=1 $(GDB_SCRIPT) \ + --gdb $(GDB) \ + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ + --bin $< --test $(MULTIARCH_SRC)/gdbstub/prot-none.py, \ + accessing PROT_NONE memory) + else run-gdbstub-%: $(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support") endif EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \ run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \ - run-gdbstub-registers + run-gdbstub-registers run-gdbstub-prot-none # ARM Compatible Semi Hosting Tests # diff --git a/tests/tcg/multiarch/gdbstub/prot-none.py b/tests/tcg/multiarch/gdbstub/prot-none.py new file mode 100644 index 0000000000..e829d3ebc5 --- /dev/null +++ b/tests/tcg/multiarch/gdbstub/prot-none.py @@ -0,0 +1,36 @@ +"""Test that GDB can access PROT_NONE pages. + +This runs as a sourced script (via -x, via run-test.py). + +SPDX-License-Identifier: GPL-2.0-or-later +""" +import ctypes +from test_gdbstub import main, report + + +def probe_proc_self_mem(): + buf = ctypes.create_string_buffer(b'aaa') + try: + with open("/proc/self/mem", "rb") as fp: + fp.seek(ctypes.addressof(buf)) + return fp.read(3) == b'aaa' + except OSError: + return False + + +def run_test(): + """Run through the tests one by one""" + if not probe_proc_self_mem: + print("SKIP: /proc/self/mem is not usable") + exit(0) + gdb.Breakpoint("break_here") + gdb.execute("continue") + val = gdb.parse_and_eval("*(char[2] *)q").string() + report(val == "42", "{} == 42".format(val)) + gdb.execute("set *(char[3] *)q = \"24\"") + gdb.execute("continue") + exitcode = int(gdb.parse_and_eval("$_exitcode")) + report(exitcode == 0, "{} == 0".format(exitcode)) + + +main(run_test) diff --git a/tests/tcg/multiarch/prot-none.c b/tests/tcg/multiarch/prot-none.c new file mode 100644 index 0000000000..dc56aadb3c --- /dev/null +++ b/tests/tcg/multiarch/prot-none.c @@ -0,0 +1,40 @@ +/* + * Test that GDB can access PROT_NONE pages. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include +#include +#include +#include +#include + +void break_here(void *q) +{ +} + +int main(void) +{ + long pagesize = sysconf(_SC_PAGESIZE); + void *p, *q; + int err; + + p = mmap(NULL, pagesize * 2, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(p != MAP_FAILED); + q = p + pagesize - 1; + strcpy(q, "42"); + + err = mprotect(p, pagesize * 2, PROT_NONE); + assert(err == 0); + + break_here(q); + + err = mprotect(p, pagesize * 2, PROT_READ); + assert(err == 0); + if (getenv("PROT_NONE_PY")) { + assert(strcmp(q, "24") == 0); + } + + return EXIT_SUCCESS; +} From f5e9362af1ad9514fb2cb283cecaa723b5c6cc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 08:41:56 +0100 Subject: [PATCH 14/31] accel/tcg/cpu-exec: Use RCU_READ_LOCK_GUARD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the manual rcu_read_(un)lock calls in cpu_exec(). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240124074201.8239-2-philmd@linaro.org> [rth: Use RCU_READ_LOCK_GUARD not WITH_RCU_READ_LOCK_GUARD] Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 40c268bfa1..950dad63cb 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -1050,7 +1050,7 @@ int cpu_exec(CPUState *cpu) return EXCP_HALTED; } - rcu_read_lock(); + RCU_READ_LOCK_GUARD(); cpu_exec_enter(cpu); /* @@ -1064,8 +1064,6 @@ int cpu_exec(CPUState *cpu) ret = cpu_exec_setjmp(cpu, &sc); cpu_exec_exit(cpu); - rcu_read_unlock(); - return ret; } From f3d57a82003a1e56190e5ca6d8154713ac3e7365 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 24 Jan 2024 08:56:06 +0100 Subject: [PATCH 15/31] target: Make qemu_target_page_mask() available for *-user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently qemu_target_page_mask() is usable only from the softmmu code. Make it possible to use it from the *-user code as well. Signed-off-by: Ilya Leoshkevich Message-ID: <20231208003754.3688038-2-iii@linux.ibm.com> Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240124075609.14756-2-philmd@linaro.org> Reviewed-by: Richard Henderson [rth: Split out change to accel/tcg/perf.c] Signed-off-by: Richard Henderson --- system/physmem.c | 5 ----- target/meson.build | 2 ++ target/target-common.c | 10 ++++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 target/target-common.c diff --git a/system/physmem.c b/system/physmem.c index cc68a79763..5e66d9ae36 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3431,11 +3431,6 @@ size_t qemu_target_page_size(void) return TARGET_PAGE_SIZE; } -int qemu_target_page_mask(void) -{ - return TARGET_PAGE_MASK; -} - int qemu_target_page_bits(void) { return TARGET_PAGE_BITS; diff --git a/target/meson.build b/target/meson.build index a53a60486f..dee2ac47e0 100644 --- a/target/meson.build +++ b/target/meson.build @@ -19,3 +19,5 @@ subdir('sh4') subdir('sparc') subdir('tricore') subdir('xtensa') + +specific_ss.add(files('target-common.c')) diff --git a/target/target-common.c b/target/target-common.c new file mode 100644 index 0000000000..903b10cfe4 --- /dev/null +++ b/target/target-common.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "qemu/osdep.h" + +#include "cpu.h" +#include "exec/target_page.h" + +int qemu_target_page_mask(void) +{ + return TARGET_PAGE_MASK; +} From 8a6a9ab6e5d6daffb00c87f23c887c22529abcb2 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 25 Jan 2024 06:46:27 +0100 Subject: [PATCH 16/31] accel/tcg: Make use of qemu_target_page_mask() in perf.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using TARGET_PAGE_MASK in order to make perf.c more target-agnostic. Signed-off-by: Ilya Leoshkevich Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231212003837.64090-2-iii@linux.ibm.com> Reviewed-by: Richard Henderson Message-Id: <20240125054631.78867-2-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/perf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accel/tcg/perf.c b/accel/tcg/perf.c index cd1aa99a7e..ba75c1bbe4 100644 --- a/accel/tcg/perf.c +++ b/accel/tcg/perf.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "elf.h" +#include "exec/target_page.h" #include "exec/exec-all.h" #include "qemu/timer.h" #include "tcg/tcg.h" @@ -335,7 +336,7 @@ void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, /* FIXME: This replicates the restore_state_to_opc() logic. */ q[insn].address = gen_insn_data[insn * start_words + 0]; if (tb_cflags(tb) & CF_PCREL) { - q[insn].address |= (guest_pc & TARGET_PAGE_MASK); + q[insn].address |= (guest_pc & qemu_target_page_mask()); } else { #if defined(TARGET_I386) q[insn].address -= tb->cs_base; From 88d4b5138a8589262cf97477d7573949874b9ef8 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 25 Jan 2024 06:46:28 +0100 Subject: [PATCH 17/31] tcg: Make tb_cflags() usable from target-agnostic code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently tb_cflags() is defined in exec-all.h, which is not usable from target-agnostic code. Move it to translation-block.h, which is. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Ilya Leoshkevich Reviewed-by: Richard Henderson Message-ID: <20231212003837.64090-3-iii@linux.ibm.com> Message-Id: <20240125054631.78867-3-philmd@linaro.org> Signed-off-by: Richard Henderson --- include/exec/exec-all.h | 6 ------ include/exec/translation-block.h | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index df3d93a2e2..ce36bb10d4 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -459,12 +459,6 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, #endif -/* Hide the qatomic_read to make code a little easier on the eyes */ -static inline uint32_t tb_cflags(const TranslationBlock *tb) -{ - return qatomic_read(&tb->cflags); -} - static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb) { #ifdef CONFIG_USER_ONLY diff --git a/include/exec/translation-block.h b/include/exec/translation-block.h index e2b26e16da..48211c890a 100644 --- a/include/exec/translation-block.h +++ b/include/exec/translation-block.h @@ -145,4 +145,10 @@ struct TranslationBlock { /* The alignment given to TranslationBlock during allocation. */ #define CODE_GEN_ALIGN 16 +/* Hide the qatomic_read to make code a little easier on the eyes */ +static inline uint32_t tb_cflags(const TranslationBlock *tb) +{ + return qatomic_read(&tb->cflags); +} + #endif /* EXEC_TRANSLATION_BLOCK_H */ From ad66ac2b3a905db4417c8fae1db112e7808053e0 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 25 Jan 2024 06:46:29 +0100 Subject: [PATCH 18/31] accel/tcg: Remove #ifdef TARGET_I386 from perf.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparation for moving perf.c to tcg/. This affects only profiling guest code, which has code in a non-0 based segment, e.g., 16-bit code, which is not particularly important. Suggested-by: Richard Henderson Signed-off-by: Ilya Leoshkevich Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-ID: <20231212003837.64090-4-iii@linux.ibm.com> Message-Id: <20240125054631.78867-4-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/perf.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/accel/tcg/perf.c b/accel/tcg/perf.c index ba75c1bbe4..68a46b1b52 100644 --- a/accel/tcg/perf.c +++ b/accel/tcg/perf.c @@ -337,10 +337,6 @@ void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, q[insn].address = gen_insn_data[insn * start_words + 0]; if (tb_cflags(tb) & CF_PCREL) { q[insn].address |= (guest_pc & qemu_target_page_mask()); - } else { -#if defined(TARGET_I386) - q[insn].address -= tb->cs_base; -#endif } q[insn].flags = DEBUGINFO_SYMBOL | (jitdump ? DEBUGINFO_LINE : 0); } From 327b75a469f2e7c3894e7b5c44f817df51064033 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 25 Jan 2024 06:46:30 +0100 Subject: [PATCH 19/31] accel/tcg: Move perf and debuginfo support to tcg/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcg/ should not depend on accel/tcg/, but perf and debuginfo support provided by the latter are being used by tcg/tcg.c. Since that's the only user, move both to tcg/. Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Ilya Leoshkevich Reviewed-by: Richard Henderson Message-ID: <20231212003837.64090-5-iii@linux.ibm.com> Message-Id: <20240125054631.78867-5-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 4 ---- accel/tcg/translate-all.c | 2 +- hw/core/loader.c | 2 +- {accel => include}/tcg/debuginfo.h | 4 ++-- {accel => include}/tcg/perf.h | 4 ++-- linux-user/elfload.c | 2 +- linux-user/exit.c | 2 +- linux-user/main.c | 2 +- system/vl.c | 2 +- {accel/tcg => tcg}/debuginfo.c | 3 +-- tcg/meson.build | 5 +++++ {accel/tcg => tcg}/perf.c | 7 +++---- tcg/tcg.c | 2 +- 13 files changed, 20 insertions(+), 21 deletions(-) rename {accel => include}/tcg/debuginfo.h (96%) rename {accel => include}/tcg/perf.h (95%) rename {accel/tcg => tcg}/debuginfo.c (98%) rename {accel/tcg => tcg}/perf.c (99%) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index c15ac9ac8f..46f7d53eeb 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -16,10 +16,6 @@ tcg_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c')) if get_option('plugins') tcg_ss.add(files('plugin-gen.c')) endif -tcg_ss.add(when: libdw, if_true: files('debuginfo.c')) -if host_os == 'linux' - tcg_ss.add(files('perf.c')) -endif specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss) specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 1737bb3da5..1c695efe02 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -63,7 +63,7 @@ #include "tb-context.h" #include "internal-common.h" #include "internal-target.h" -#include "perf.h" +#include "tcg/perf.h" #include "tcg/insn-start-words.h" TBContext tb_ctx; diff --git a/hw/core/loader.c b/hw/core/loader.c index e7a9b3775b..b8e52f3fb0 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -62,7 +62,7 @@ #include "hw/boards.h" #include "qemu/cutils.h" #include "sysemu/runstate.h" -#include "accel/tcg/debuginfo.h" +#include "tcg/debuginfo.h" #include diff --git a/accel/tcg/debuginfo.h b/include/tcg/debuginfo.h similarity index 96% rename from accel/tcg/debuginfo.h rename to include/tcg/debuginfo.h index f064e1c144..858535b5da 100644 --- a/accel/tcg/debuginfo.h +++ b/include/tcg/debuginfo.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef ACCEL_TCG_DEBUGINFO_H -#define ACCEL_TCG_DEBUGINFO_H +#ifndef TCG_DEBUGINFO_H +#define TCG_DEBUGINFO_H #include "qemu/bitops.h" diff --git a/accel/tcg/perf.h b/include/tcg/perf.h similarity index 95% rename from accel/tcg/perf.h rename to include/tcg/perf.h index f92dd52c69..c96b5920a3 100644 --- a/accel/tcg/perf.h +++ b/include/tcg/perf.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef ACCEL_TCG_PERF_H -#define ACCEL_TCG_PERF_H +#ifndef TCG_PERF_H +#define TCG_PERF_H #if defined(CONFIG_TCG) && defined(CONFIG_LINUX) /* Start writing perf-.map. */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index daf7ef8435..b8eef893d0 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -22,7 +22,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "target_signal.h" -#include "accel/tcg/debuginfo.h" +#include "tcg/debuginfo.h" #ifdef TARGET_ARM #include "target/arm/cpu-features.h" diff --git a/linux-user/exit.c b/linux-user/exit.c index 50266314e0..1ff8fe4f07 100644 --- a/linux-user/exit.c +++ b/linux-user/exit.c @@ -17,7 +17,7 @@ * along with this program; if not, see . */ #include "qemu/osdep.h" -#include "accel/tcg/perf.h" +#include "tcg/perf.h" #include "gdbstub/syscalls.h" #include "qemu.h" #include "user-internals.h" diff --git a/linux-user/main.c b/linux-user/main.c index c9470eeccf..74b2fbb393 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -54,7 +54,7 @@ #include "signal-common.h" #include "loader.h" #include "user-mmap.h" -#include "accel/tcg/perf.h" +#include "tcg/perf.h" #ifdef CONFIG_SEMIHOSTING #include "semihosting/semihost.h" diff --git a/system/vl.c b/system/vl.c index 788d88ea03..60fd1e56b6 100644 --- a/system/vl.c +++ b/system/vl.c @@ -96,7 +96,7 @@ #endif #include "sysemu/qtest.h" #ifdef CONFIG_TCG -#include "accel/tcg/perf.h" +#include "tcg/perf.h" #endif #include "disas/disas.h" diff --git a/accel/tcg/debuginfo.c b/tcg/debuginfo.c similarity index 98% rename from accel/tcg/debuginfo.c rename to tcg/debuginfo.c index 71c66d04d1..3753f7ef67 100644 --- a/accel/tcg/debuginfo.c +++ b/tcg/debuginfo.c @@ -6,11 +6,10 @@ #include "qemu/osdep.h" #include "qemu/lockable.h" +#include "tcg/debuginfo.h" #include -#include "debuginfo.h" - static QemuMutex lock; static Dwfl *dwfl; static const Dwfl_Callbacks dwfl_callbacks = { diff --git a/tcg/meson.build b/tcg/meson.build index 5afdec1e1a..8251589fd4 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -22,6 +22,11 @@ if get_option('tcg_interpreter') tcg_ss.add(files('tci.c')) endif +tcg_ss.add(when: libdw, if_true: files('debuginfo.c')) +if host_os == 'linux' + tcg_ss.add(files('perf.c')) +endif + tcg_ss = tcg_ss.apply({}) libtcg_user = static_library('tcg_user', diff --git a/accel/tcg/perf.c b/tcg/perf.c similarity index 99% rename from accel/tcg/perf.c rename to tcg/perf.c index 68a46b1b52..412a987d95 100644 --- a/accel/tcg/perf.c +++ b/tcg/perf.c @@ -11,13 +11,12 @@ #include "qemu/osdep.h" #include "elf.h" #include "exec/target_page.h" -#include "exec/exec-all.h" +#include "exec/translation-block.h" #include "qemu/timer.h" +#include "tcg/debuginfo.h" +#include "tcg/perf.h" #include "tcg/tcg.h" -#include "debuginfo.h" -#include "perf.h" - static FILE *safe_fopen_w(const char *path) { int saved_errno; diff --git a/tcg/tcg.c b/tcg/tcg.c index e2c38f6d11..eeff4c1d51 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -55,7 +55,7 @@ #include "tcg/tcg-ldst.h" #include "tcg/tcg-temp-internal.h" #include "tcg-internal.h" -#include "accel/tcg/perf.h" +#include "tcg/perf.h" #ifdef CONFIG_USER_ONLY #include "exec/user/guest-base.h" #endif From 29c0e6836f89ac60763b453424ea374bc37e48d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:31 +0100 Subject: [PATCH 20/31] accel/tcg: Rename tcg_ss[] -> tcg_specific_ss[] in meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcg_ss[] source set contains target-specific units. Rename it as 'tcg_specific_ss[]' for clarity. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Anton Johansson Message-Id: <20240124101639.30056-2-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 46f7d53eeb..aef80de967 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -1,8 +1,8 @@ -tcg_ss = ss.source_set() common_ss.add(when: 'CONFIG_TCG', if_true: files( 'cpu-exec-common.c', )) -tcg_ss.add(files( +tcg_specific_ss = ss.source_set() +tcg_specific_ss.add(files( 'tcg-all.c', 'cpu-exec.c', 'tb-maint.c', @@ -11,12 +11,12 @@ tcg_ss.add(files( 'translate-all.c', 'translator.c', )) -tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) -tcg_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c')) +tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) +tcg_specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c')) if get_option('plugins') - tcg_ss.add(files('plugin-gen.c')) + tcg_specific_ss.add(files('plugin-gen.c')) endif -specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss) +specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( 'cputlb.c', From cca2f62e74cacb23d1a63b2596ab79f28ae09770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:32 +0100 Subject: [PATCH 21/31] accel/tcg: Rename tcg_cpus_destroy() -> tcg_cpu_destroy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcg_cpus_destroy() operates on a single vCPU, rename it as 'tcg_cpu_destroy'. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20240124101639.30056-3-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/tcg-accel-ops-mttcg.c | 2 +- accel/tcg/tcg-accel-ops-rr.c | 2 +- accel/tcg/tcg-accel-ops.c | 2 +- accel/tcg/tcg-accel-ops.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index af7307013a..bcba314a65 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -118,7 +118,7 @@ static void *mttcg_cpu_thread_fn(void *arg) qemu_wait_io_event(cpu); } while (!cpu->unplug || cpu_can_run(cpu)); - tcg_cpus_destroy(cpu); + tcg_cpu_destroy(cpu); bql_unlock(); rcu_remove_force_rcu_notifier(&force_rcu.notifier); rcu_unregister_thread(); diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 3208035d85..0617f66b5b 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -131,7 +131,7 @@ static void rr_deal_with_unplugged_cpus(void) CPU_FOREACH(cpu) { if (cpu->unplug && !cpu_can_run(cpu)) { - tcg_cpus_destroy(cpu); + tcg_cpu_destroy(cpu); break; } } diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 813065c0ec..9b84b84218 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -63,7 +63,7 @@ void tcg_cpu_init_cflags(CPUState *cpu, bool parallel) cpu->tcg_cflags |= cflags; } -void tcg_cpus_destroy(CPUState *cpu) +void tcg_cpu_destroy(CPUState *cpu) { cpu_thread_signal_destroyed(cpu); } diff --git a/accel/tcg/tcg-accel-ops.h b/accel/tcg/tcg-accel-ops.h index f9bc6330e2..17c7ed00eb 100644 --- a/accel/tcg/tcg-accel-ops.h +++ b/accel/tcg/tcg-accel-ops.h @@ -14,7 +14,7 @@ #include "sysemu/cpus.h" -void tcg_cpus_destroy(CPUState *cpu); +void tcg_cpu_destroy(CPUState *cpu); int tcg_cpus_exec(CPUState *cpu); void tcg_handle_interrupt(CPUState *cpu, int mask); void tcg_cpu_init_cflags(CPUState *cpu, bool parallel); From f4cf2ef93f26fcdc3110919f9eb1e6bc8620dd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:33 +0100 Subject: [PATCH 22/31] accel/tcg: Rename tcg_cpus_exec() -> tcg_cpu_exec() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcg_cpus_exec() operates on a single vCPU, rename it as 'tcg_cpu_exec'. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Anton Johansson Message-Id: <20240124101639.30056-4-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/tcg-accel-ops-mttcg.c | 2 +- accel/tcg/tcg-accel-ops-rr.c | 2 +- accel/tcg/tcg-accel-ops.c | 2 +- accel/tcg/tcg-accel-ops.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index bcba314a65..c552b45b8e 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -92,7 +92,7 @@ static void *mttcg_cpu_thread_fn(void *arg) if (cpu_can_run(cpu)) { int r; bql_unlock(); - r = tcg_cpus_exec(cpu); + r = tcg_cpu_exec(cpu); bql_lock(); switch (r) { case EXCP_DEBUG: diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 0617f66b5b..894e73e52c 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -258,7 +258,7 @@ static void *rr_cpu_thread_fn(void *arg) if (icount_enabled()) { icount_prepare_for_run(cpu, cpu_budget); } - r = tcg_cpus_exec(cpu); + r = tcg_cpu_exec(cpu); if (icount_enabled()) { icount_process_data(cpu); } diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 9b84b84218..9c957f421c 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -68,7 +68,7 @@ void tcg_cpu_destroy(CPUState *cpu) cpu_thread_signal_destroyed(cpu); } -int tcg_cpus_exec(CPUState *cpu) +int tcg_cpu_exec(CPUState *cpu) { int ret; assert(tcg_enabled()); diff --git a/accel/tcg/tcg-accel-ops.h b/accel/tcg/tcg-accel-ops.h index 17c7ed00eb..44c4079972 100644 --- a/accel/tcg/tcg-accel-ops.h +++ b/accel/tcg/tcg-accel-ops.h @@ -15,7 +15,7 @@ #include "sysemu/cpus.h" void tcg_cpu_destroy(CPUState *cpu); -int tcg_cpus_exec(CPUState *cpu); +int tcg_cpu_exec(CPUState *cpu); void tcg_handle_interrupt(CPUState *cpu, int mask); void tcg_cpu_init_cflags(CPUState *cpu, bool parallel); From 93c6091bfa41792b28b25cd7e3c1f578e44b0d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:34 +0100 Subject: [PATCH 23/31] accel/tcg: Un-inline icount_exit_request() for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert packed logic to dumb icount_exit_request() helper. No functional change intended. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Anton Johansson Message-Id: <20240124101639.30056-5-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 950dad63cb..f2535a2991 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -777,6 +777,17 @@ static inline bool need_replay_interrupt(int interrupt_request) } #endif /* !CONFIG_USER_ONLY */ +static inline bool icount_exit_request(CPUState *cpu) +{ + if (!icount_enabled()) { + return false; + } + if (cpu->cflags_next_tb != -1 && !(cpu->cflags_next_tb & CF_USE_ICOUNT)) { + return false; + } + return cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0; +} + static inline bool cpu_handle_interrupt(CPUState *cpu, TranslationBlock **last_tb) { @@ -882,10 +893,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, } /* Finally, check if we need to exit to the main loop. */ - if (unlikely(qatomic_read(&cpu->exit_request)) - || (icount_enabled() - && (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT) - && cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0)) { + if (unlikely(qatomic_read(&cpu->exit_request)) || icount_exit_request(cpu)) { qatomic_set(&cpu->exit_request, 0); if (cpu->exception_index == -1) { cpu->exception_index = EXCP_INTERRUPT; From 1764ad70ce7c78b7f2f18bcf79cbab42a4e18b96 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 28 Jan 2024 12:46:44 +1000 Subject: [PATCH 24/31] include/qemu: Add TCGCPUOps typedef to typedefs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU coding style recommends using structure typedefs. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- bsd-user/signal.c | 4 ++-- include/hw/core/cpu.h | 5 +---- include/qemu/typedefs.h | 1 + linux-user/signal.c | 4 ++-- target/alpha/cpu.c | 2 +- target/arm/cpu.c | 2 +- target/arm/tcg/cpu32.c | 2 +- target/avr/cpu.c | 2 +- target/cris/cpu.c | 4 ++-- target/hexagon/cpu.c | 2 +- target/hppa/cpu.c | 2 +- target/i386/tcg/tcg-cpu.c | 2 +- target/loongarch/cpu.c | 2 +- target/m68k/cpu.c | 2 +- target/microblaze/cpu.c | 2 +- target/mips/cpu.c | 2 +- target/nios2/cpu.c | 2 +- target/openrisc/cpu.c | 2 +- target/ppc/cpu_init.c | 2 +- target/riscv/tcg/tcg-cpu.c | 2 +- target/rx/cpu.c | 2 +- target/s390x/cpu.c | 2 +- target/sh4/cpu.c | 2 +- target/sparc/cpu.c | 2 +- target/tricore/cpu.c | 2 +- target/xtensa/cpu.c | 2 +- 26 files changed, 29 insertions(+), 31 deletions(-) diff --git a/bsd-user/signal.c b/bsd-user/signal.c index ca31470772..f4352e4530 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -1022,7 +1022,7 @@ void process_pending_signals(CPUArchState *env) void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, MMUAccessType access_type, bool maperr, uintptr_t ra) { - const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; + const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; if (tcg_ops->record_sigsegv) { tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra); @@ -1038,7 +1038,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, MMUAccessType access_type, uintptr_t ra) { - const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; + const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; if (tcg_ops->record_sigbus) { tcg_ops->record_sigbus(cpu, addr, access_type, ra); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index db58f12233..2c284d6397 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -90,9 +90,6 @@ typedef enum MMUAccessType { typedef struct CPUWatchpoint CPUWatchpoint; -/* see tcg-cpu-ops.h */ -struct TCGCPUOps; - /* see accel-cpu.h */ struct AccelCPUClass; @@ -177,7 +174,7 @@ struct CPUClass { const struct SysemuCPUOps *sysemu_ops; /* when TCG is not available, this pointer is NULL */ - const struct TCGCPUOps *tcg_ops; + const TCGCPUOps *tcg_ops; /* * if not NULL, this is called in order for the CPUClass to initialize diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 5abdbc3874..d7c703b4ae 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -131,6 +131,7 @@ typedef struct Range Range; typedef struct ReservedRegion ReservedRegion; typedef struct SHPCDevice SHPCDevice; typedef struct SSIBus SSIBus; +typedef struct TCGCPUOps TCGCPUOps; typedef struct TCGHelperInfo TCGHelperInfo; typedef struct TranslationBlock TranslationBlock; typedef struct VirtIODevice VirtIODevice; diff --git a/linux-user/signal.c b/linux-user/signal.c index c9527adfa3..d3e62ab030 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -671,7 +671,7 @@ void force_sigsegv(int oldsig) void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, MMUAccessType access_type, bool maperr, uintptr_t ra) { - const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; + const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; if (tcg_ops->record_sigsegv) { tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra); @@ -687,7 +687,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, MMUAccessType access_type, uintptr_t ra) { - const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; + const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; if (tcg_ops->record_sigbus) { tcg_ops->record_sigbus(cpu, addr, access_type, ra); diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index b8ed29e343..de705c3703 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -203,7 +203,7 @@ static const struct SysemuCPUOps alpha_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps alpha_tcg_ops = { +static const TCGCPUOps alpha_tcg_ops = { .initialize = alpha_translate_init, .restore_state_to_opc = alpha_restore_state_to_opc, diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b60e103046..6a96b245f2 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2458,7 +2458,7 @@ static const struct SysemuCPUOps arm_sysemu_ops = { #endif #ifdef CONFIG_TCG -static const struct TCGCPUOps arm_tcg_ops = { +static const TCGCPUOps arm_tcg_ops = { .initialize = arm_translate_init, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index d9e0e2a4dd..1125305115 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -1018,7 +1018,7 @@ static void pxa270c5_initfn(Object *obj) cpu->reset_sctlr = 0x00000078; } -static const struct TCGCPUOps arm_v7m_tcg_ops = { +static const TCGCPUOps arm_v7m_tcg_ops = { .initialize = arm_translate_init, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, diff --git a/target/avr/cpu.c b/target/avr/cpu.c index f5cbdc4a8c..1c68748b24 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -210,7 +210,7 @@ static const struct SysemuCPUOps avr_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps avr_tcg_ops = { +static const TCGCPUOps avr_tcg_ops = { .initialize = avr_cpu_tcg_init, .synchronize_from_tb = avr_cpu_synchronize_from_tb, .restore_state_to_opc = avr_restore_state_to_opc, diff --git a/target/cris/cpu.c b/target/cris/cpu.c index 9ba08e8b0c..6349148b65 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -178,7 +178,7 @@ static const struct SysemuCPUOps cris_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps crisv10_tcg_ops = { +static const TCGCPUOps crisv10_tcg_ops = { .initialize = cris_initialize_crisv10_tcg, .restore_state_to_opc = cris_restore_state_to_opc, @@ -189,7 +189,7 @@ static const struct TCGCPUOps crisv10_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static const struct TCGCPUOps crisv32_tcg_ops = { +static const TCGCPUOps crisv32_tcg_ops = { .initialize = cris_initialize_tcg, .restore_state_to_opc = cris_restore_state_to_opc, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index c0cd739e15..759ea62814 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -337,7 +337,7 @@ static void hexagon_cpu_init(Object *obj) #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps hexagon_tcg_ops = { +static const TCGCPUOps hexagon_tcg_ops = { .initialize = hexagon_translate_init, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, .restore_state_to_opc = hexagon_restore_state_to_opc, diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 14e17fa9aa..3c019855b4 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -170,7 +170,7 @@ static const struct SysemuCPUOps hppa_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps hppa_tcg_ops = { +static const TCGCPUOps hppa_tcg_ops = { .initialize = hppa_translate_init, .synchronize_from_tb = hppa_cpu_synchronize_from_tb, .restore_state_to_opc = hppa_restore_state_to_opc, diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index e1405b7be9..8e148e9bc4 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -106,7 +106,7 @@ static bool x86_debug_check_breakpoint(CPUState *cs) #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps x86_tcg_ops = { +static const TCGCPUOps x86_tcg_ops = { .initialize = tcg_x86_init, .synchronize_from_tb = x86_cpu_synchronize_from_tb, .restore_state_to_opc = x86_restore_state_to_opc, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 064540397d..dd3e46a726 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -734,7 +734,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" -static struct TCGCPUOps loongarch_tcg_ops = { +static TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_translate_init, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, .restore_state_to_opc = loongarch_restore_state_to_opc, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 1421e77c2c..44000f5869 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -525,7 +525,7 @@ static const struct SysemuCPUOps m68k_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps m68k_tcg_ops = { +static const TCGCPUOps m68k_tcg_ops = { .initialize = m68k_tcg_init, .restore_state_to_opc = m68k_restore_state_to_opc, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index bbb3335cad..2318ad7013 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -387,7 +387,7 @@ static const struct SysemuCPUOps mb_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps mb_tcg_ops = { +static const TCGCPUOps mb_tcg_ops = { .initialize = mb_tcg_init, .synchronize_from_tb = mb_cpu_synchronize_from_tb, .restore_state_to_opc = mb_restore_state_to_opc, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index a0023edd43..df544ab39b 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -549,7 +549,7 @@ static const struct SysemuCPUOps mips_sysemu_ops = { * NB: cannot be const, as some elements are changed for specific * mips hardware (see hw/mips/jazz.c). */ -static const struct TCGCPUOps mips_tcg_ops = { +static const TCGCPUOps mips_tcg_ops = { .initialize = mips_tcg_init, .synchronize_from_tb = mips_cpu_synchronize_from_tb, .restore_state_to_opc = mips_restore_state_to_opc, diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index a27732bf2b..596c0c5617 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -354,7 +354,7 @@ static const struct SysemuCPUOps nios2_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps nios2_tcg_ops = { +static const TCGCPUOps nios2_tcg_ops = { .initialize = nios2_tcg_init, .restore_state_to_opc = nios2_restore_state_to_opc, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 381ebe00d3..477d49d4bc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -213,7 +213,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps openrisc_tcg_ops = { +static const TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, .synchronize_from_tb = openrisc_cpu_synchronize_from_tb, .restore_state_to_opc = openrisc_restore_state_to_opc, diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 344196a8ce..23eb5522b6 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7332,7 +7332,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = { #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps ppc_tcg_ops = { +static const TCGCPUOps ppc_tcg_ops = { .initialize = ppc_translate_init, .restore_state_to_opc = ppc_restore_state_to_opc, diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 994ca1cdf9..b7da92783b 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -129,7 +129,7 @@ static void riscv_restore_state_to_opc(CPUState *cs, env->bins = data[1]; } -static const struct TCGCPUOps riscv_tcg_ops = { +static const TCGCPUOps riscv_tcg_ops = { .initialize = riscv_translate_init, .synchronize_from_tb = riscv_cpu_synchronize_from_tb, .restore_state_to_opc = riscv_restore_state_to_opc, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index c5ffeffe32..353132dac2 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -178,7 +178,7 @@ static const struct SysemuCPUOps rx_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps rx_tcg_ops = { +static const TCGCPUOps rx_tcg_ops = { .initialize = rx_translate_init, .synchronize_from_tb = rx_cpu_synchronize_from_tb, .restore_state_to_opc = rx_restore_state_to_opc, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 6acfa1c91b..7f123863dc 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -319,7 +319,7 @@ static void s390_cpu_reset_full(DeviceState *dev) #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps s390_tcg_ops = { +static const TCGCPUOps s390_tcg_ops = { .initialize = s390x_translate_init, .restore_state_to_opc = s390x_restore_state_to_opc, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 806a0ef875..39772955b5 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -237,7 +237,7 @@ static const struct SysemuCPUOps sh4_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps superh_tcg_ops = { +static const TCGCPUOps superh_tcg_ops = { .initialize = sh4_translate_init, .synchronize_from_tb = superh_cpu_synchronize_from_tb, .restore_state_to_opc = superh_restore_state_to_opc, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index befa7fc4eb..7d0d629a3d 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -874,7 +874,7 @@ static const struct SysemuCPUOps sparc_sysemu_ops = { #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps sparc_tcg_ops = { +static const TCGCPUOps sparc_tcg_ops = { .initialize = sparc_tcg_init, .synchronize_from_tb = sparc_cpu_synchronize_from_tb, .restore_state_to_opc = sparc_restore_state_to_opc, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 8acacdf0c0..e6d91c74b5 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -173,7 +173,7 @@ static const struct SysemuCPUOps tricore_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps tricore_tcg_ops = { +static const TCGCPUOps tricore_tcg_ops = { .initialize = tricore_tcg_init, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, .restore_state_to_opc = tricore_restore_state_to_opc, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 99c0ca130f..62020b1f33 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -222,7 +222,7 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = { #include "hw/core/tcg-cpu-ops.h" -static const struct TCGCPUOps xtensa_tcg_ops = { +static const TCGCPUOps xtensa_tcg_ops = { .initialize = xtensa_translate_init, .debug_excp_handler = xtensa_breakpoint_handler, .restore_state_to_opc = xtensa_restore_state_to_opc, From 2889fb8bd25204436da40ac1e88ca7c7a4580e6a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 28 Jan 2024 12:47:52 +1000 Subject: [PATCH 25/31] target/loongarch: Constify loongarch_tcg_ops Signed-off-by: Richard Henderson --- target/loongarch/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index dd3e46a726..fb8dde7def 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -734,7 +734,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" -static TCGCPUOps loongarch_tcg_ops = { +static const TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_translate_init, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, .restore_state_to_opc = loongarch_restore_state_to_opc, From 991bd65ddd3282f2422837a593adc621c0defc2d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 28 Jan 2024 12:57:59 +1000 Subject: [PATCH 26/31] accel/tcg: Use CPUState.cc instead of CPU_GET_CLASS in cpu-exec.c CPU_GET_CLASS does runtime type checking; use the cached copy of the class instead. Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 109 ++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index f2535a2991..3aebf46849 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -343,9 +343,9 @@ static bool check_for_breakpoints_slow(CPUState *cpu, vaddr pc, #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - CPUClass *cc = CPU_GET_CLASS(cpu); - assert(cc->tcg_ops->debug_check_breakpoint); - match_bp = cc->tcg_ops->debug_check_breakpoint(cpu); + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; + assert(tcg_ops->debug_check_breakpoint); + match_bp = tcg_ops->debug_check_breakpoint(cpu); #endif } @@ -462,10 +462,11 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) * counter hit zero); we must restore the guest PC to the address * of the start of the TB. */ - CPUClass *cc = CPU_GET_CLASS(cpu); + CPUClass *cc = cpu->cc; + const TCGCPUOps *tcg_ops = cc->tcg_ops; - if (cc->tcg_ops->synchronize_from_tb) { - cc->tcg_ops->synchronize_from_tb(cpu, last_tb); + if (tcg_ops->synchronize_from_tb) { + tcg_ops->synchronize_from_tb(cpu, last_tb); } else { tcg_debug_assert(!(tb_cflags(last_tb) & CF_PCREL)); assert(cc->set_pc); @@ -497,19 +498,19 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) static void cpu_exec_enter(CPUState *cpu) { - CPUClass *cc = CPU_GET_CLASS(cpu); + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - if (cc->tcg_ops->cpu_exec_enter) { - cc->tcg_ops->cpu_exec_enter(cpu); + if (tcg_ops->cpu_exec_enter) { + tcg_ops->cpu_exec_enter(cpu); } } static void cpu_exec_exit(CPUState *cpu) { - CPUClass *cc = CPU_GET_CLASS(cpu); + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - if (cc->tcg_ops->cpu_exec_exit) { - cc->tcg_ops->cpu_exec_exit(cpu); + if (tcg_ops->cpu_exec_exit) { + tcg_ops->cpu_exec_exit(cpu); } } @@ -685,7 +686,7 @@ static inline bool cpu_handle_halt(CPUState *cpu) static inline void cpu_handle_debug_exception(CPUState *cpu) { - CPUClass *cc = CPU_GET_CLASS(cpu); + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; CPUWatchpoint *wp; if (!cpu->watchpoint_hit) { @@ -694,8 +695,8 @@ static inline void cpu_handle_debug_exception(CPUState *cpu) } } - if (cc->tcg_ops->debug_excp_handler) { - cc->tcg_ops->debug_excp_handler(cpu); + if (tcg_ops->debug_excp_handler) { + tcg_ops->debug_excp_handler(cpu); } } @@ -712,6 +713,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) #endif return false; } + if (cpu->exception_index >= EXCP_INTERRUPT) { /* exit request from the cpu execution loop */ *ret = cpu->exception_index; @@ -720,43 +722,45 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) } cpu->exception_index = -1; return true; - } else { -#if defined(CONFIG_USER_ONLY) - /* if user mode only, we simulate a fake exception - which will be handled outside the cpu execution - loop */ -#if defined(TARGET_I386) - CPUClass *cc = CPU_GET_CLASS(cpu); - cc->tcg_ops->fake_user_interrupt(cpu); -#endif /* TARGET_I386 */ - *ret = cpu->exception_index; - cpu->exception_index = -1; - return true; -#else - if (replay_exception()) { - CPUClass *cc = CPU_GET_CLASS(cpu); - bql_lock(); - cc->tcg_ops->do_interrupt(cpu); - bql_unlock(); - cpu->exception_index = -1; + } - if (unlikely(cpu->singlestep_enabled)) { - /* - * After processing the exception, ensure an EXCP_DEBUG is - * raised when single-stepping so that GDB doesn't miss the - * next instruction. - */ - *ret = EXCP_DEBUG; - cpu_handle_debug_exception(cpu); - return true; - } - } else if (!replay_has_interrupt()) { - /* give a chance to iothread in replay mode */ - *ret = EXCP_INTERRUPT; +#if defined(CONFIG_USER_ONLY) + /* + * If user mode only, we simulate a fake exception which will be + * handled outside the cpu execution loop. + */ +#if defined(TARGET_I386) + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; + tcg_ops->fake_user_interrupt(cpu); +#endif /* TARGET_I386 */ + *ret = cpu->exception_index; + cpu->exception_index = -1; + return true; +#else + if (replay_exception()) { + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; + + bql_lock(); + tcg_ops->do_interrupt(cpu); + bql_unlock(); + cpu->exception_index = -1; + + if (unlikely(cpu->singlestep_enabled)) { + /* + * After processing the exception, ensure an EXCP_DEBUG is + * raised when single-stepping so that GDB doesn't miss the + * next instruction. + */ + *ret = EXCP_DEBUG; + cpu_handle_debug_exception(cpu); return true; } -#endif + } else if (!replay_has_interrupt()) { + /* give a chance to iothread in replay mode */ + *ret = EXCP_INTERRUPT; + return true; } +#endif return false; } @@ -856,10 +860,10 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, True when it is, and we should restart on a new TB, and via longjmp via cpu_loop_exit. */ else { - CPUClass *cc = CPU_GET_CLASS(cpu); + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - if (cc->tcg_ops->cpu_exec_interrupt && - cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) { + if (tcg_ops->cpu_exec_interrupt && + tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) { if (need_replay_interrupt(interrupt_request)) { replay_interrupt(); } @@ -1078,10 +1082,9 @@ int cpu_exec(CPUState *cpu) bool tcg_exec_realizefn(CPUState *cpu, Error **errp) { static bool tcg_target_initialized; - CPUClass *cc = CPU_GET_CLASS(cpu); if (!tcg_target_initialized) { - cc->tcg_ops->initialize(); + cpu->cc->tcg_ops->initialize(); tcg_target_initialized = true; } From 0fdc69b76ee67583e0fe0e0fd31da212f506cd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:36 +0100 Subject: [PATCH 27/31] accel/tcg: Introduce TCGCPUOps::need_replay_interrupt() handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make accel/tcg/ target agnostic, introduce the need_replay_interrupt() handler. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Anton Johansson Reviewed-by: Pavel Dovgalyuk Message-Id: <20240124101639.30056-7-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 8 +++++--- include/hw/core/tcg-cpu-ops.h | 5 +++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 3aebf46849..34d10eb173 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -771,12 +771,14 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) * "real" interrupt event later. It does not need to be recorded for * replay purposes. */ -static inline bool need_replay_interrupt(int interrupt_request) +static inline bool need_replay_interrupt(CPUState *cpu, int interrupt_request) { #if defined(TARGET_I386) return !(interrupt_request & CPU_INTERRUPT_POLL); #else - return true; + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; + return !tcg_ops->need_replay_interrupt + || tcg_ops->need_replay_interrupt(interrupt_request); #endif } #endif /* !CONFIG_USER_ONLY */ @@ -864,7 +866,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, if (tcg_ops->cpu_exec_interrupt && tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) { - if (need_replay_interrupt(interrupt_request)) { + if (need_replay_interrupt(cpu, interrupt_request)) { replay_interrupt(); } /* diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index 3ed279836f..013867b890 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -166,6 +166,11 @@ struct TCGCPUOps { */ bool (*io_recompile_replay_branch)(CPUState *cpu, const TranslationBlock *tb); + /** + * @need_replay_interrupt: Return %true if @interrupt_request + * needs to be recorded for replay purposes. + */ + bool (*need_replay_interrupt)(int interrupt_request); #endif /* !CONFIG_USER_ONLY */ #endif /* NEED_CPU_H */ From 6ae754815f341f0a6dfe9c43ffe25e51375264b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:37 +0100 Subject: [PATCH 28/31] target/i386: Extract x86_need_replay_interrupt() from accel/tcg/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move this x86-specific code out of the generic accel/tcg/. Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Reviewed-by: Pavel Dovgalyuk Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240124101639.30056-8-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 4 ---- target/i386/tcg/helper-tcg.h | 1 + target/i386/tcg/sysemu/seg_helper.c | 10 ++++++++++ target/i386/tcg/tcg-cpu.c | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 34d10eb173..2eacd694ea 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -773,13 +773,9 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) */ static inline bool need_replay_interrupt(CPUState *cpu, int interrupt_request) { -#if defined(TARGET_I386) - return !(interrupt_request & CPU_INTERRUPT_POLL); -#else const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; return !tcg_ops->need_replay_interrupt || tcg_ops->need_replay_interrupt(interrupt_request); -#endif } #endif /* !CONFIG_USER_ONLY */ diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index ce34b737bb..253b1f561e 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -39,6 +39,7 @@ QEMU_BUILD_BUG_ON(TCG_PHYS_ADDR_BITS > TARGET_PHYS_ADDR_SPACE_BITS); */ void x86_cpu_do_interrupt(CPUState *cpu); #ifndef CONFIG_USER_ONLY +bool x86_need_replay_interrupt(int interrupt_request); bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req); #endif diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c index 1cb5a0db45..e6f42282bb 100644 --- a/target/i386/tcg/sysemu/seg_helper.c +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -127,6 +127,16 @@ void x86_cpu_do_interrupt(CPUState *cs) } } +bool x86_need_replay_interrupt(int interrupt_request) +{ + /* + * CPU_INTERRUPT_POLL is a virtual event which gets converted into a + * "real" interrupt event later. It does not need to be recorded for + * replay purposes. + */ + return !(interrupt_request & CPU_INTERRUPT_POLL); +} + bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { X86CPU *cpu = X86_CPU(cs); diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 8e148e9bc4..5bdcf45199 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -123,6 +123,7 @@ static const TCGCPUOps x86_tcg_ops = { .do_unaligned_access = x86_cpu_do_unaligned_access, .debug_excp_handler = breakpoint_handler, .debug_check_breakpoint = x86_debug_check_breakpoint, + .need_replay_interrupt = x86_need_replay_interrupt, #endif /* !CONFIG_USER_ONLY */ }; From b7e9a4a9b0d74aca386682d384d4ad0d20226d24 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 28 Jan 2024 13:12:54 +1000 Subject: [PATCH 29/31] accel/tcg: Inline need_replay_interrupt The function is now trivial, and with inlining we can re-use the calling function's tcg_ops variable. Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 2eacd694ea..75f7ba7bed 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -765,20 +765,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) return false; } -#ifndef CONFIG_USER_ONLY -/* - * CPU_INTERRUPT_POLL is a virtual event which gets converted into a - * "real" interrupt event later. It does not need to be recorded for - * replay purposes. - */ -static inline bool need_replay_interrupt(CPUState *cpu, int interrupt_request) -{ - const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - return !tcg_ops->need_replay_interrupt - || tcg_ops->need_replay_interrupt(interrupt_request); -} -#endif /* !CONFIG_USER_ONLY */ - static inline bool icount_exit_request(CPUState *cpu) { if (!icount_enabled()) { @@ -862,7 +848,8 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, if (tcg_ops->cpu_exec_interrupt && tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) { - if (need_replay_interrupt(cpu, interrupt_request)) { + if (!tcg_ops->need_replay_interrupt || + tcg_ops->need_replay_interrupt(interrupt_request)) { replay_interrupt(); } /* From aa6fb65746c90496c3829fd49f86c7b059c4b846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:38 +0100 Subject: [PATCH 30/31] accel/tcg: Introduce TCGCPUOps::cpu_exec_halt() handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make accel/tcg/ target agnostic, introduce the cpu_exec_halt() handler. Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240124101639.30056-9-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 5 +++++ include/hw/core/tcg-cpu-ops.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 75f7ba7bed..82627b12b8 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -664,6 +664,8 @@ static inline bool cpu_handle_halt(CPUState *cpu) { #ifndef CONFIG_USER_ONLY if (cpu->halted) { + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; + #if defined(TARGET_I386) if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { X86CPU *x86_cpu = X86_CPU(cpu); @@ -673,6 +675,9 @@ static inline bool cpu_handle_halt(CPUState *cpu) bql_unlock(); } #endif /* TARGET_I386 */ + if (tcg_ops->cpu_exec_halt) { + tcg_ops->cpu_exec_halt(cpu); + } if (!cpu_has_work(cpu)) { return true; } diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index 013867b890..bf8ff8e3ee 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -112,6 +112,8 @@ struct TCGCPUOps { void (*do_interrupt)(CPUState *cpu); /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */ bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request); + /** @cpu_exec_halt: Callback for handling halt in cpu_exec */ + void (*cpu_exec_halt)(CPUState *cpu); /** * @tlb_fill: Handle a softmmu tlb miss * From ec1d32af123e7f13d98754a72bcaa7aa8c8e9d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jan 2024 11:16:39 +0100 Subject: [PATCH 31/31] target/i386: Extract x86_cpu_exec_halt() from accel/tcg/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move this x86-specific code out of the generic accel/tcg/. Reported-by: Anton Johansson Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20240124101639.30056-10-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 12 ------------ target/i386/tcg/helper-tcg.h | 1 + target/i386/tcg/sysemu/seg_helper.c | 13 +++++++++++++ target/i386/tcg/tcg-cpu.c | 1 + 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 82627b12b8..977576ca14 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -30,9 +30,6 @@ #include "qemu/rcu.h" #include "exec/log.h" #include "qemu/main-loop.h" -#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY) -#include "hw/i386/apic.h" -#endif #include "sysemu/cpus.h" #include "exec/cpu-all.h" #include "sysemu/cpu-timers.h" @@ -666,15 +663,6 @@ static inline bool cpu_handle_halt(CPUState *cpu) if (cpu->halted) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; -#if defined(TARGET_I386) - if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { - X86CPU *x86_cpu = X86_CPU(cpu); - bql_lock(); - apic_poll_irq(x86_cpu->apic_state); - cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL); - bql_unlock(); - } -#endif /* TARGET_I386 */ if (tcg_ops->cpu_exec_halt) { tcg_ops->cpu_exec_halt(cpu); } diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index 253b1f561e..effc2c1c98 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -39,6 +39,7 @@ QEMU_BUILD_BUG_ON(TCG_PHYS_ADDR_BITS > TARGET_PHYS_ADDR_SPACE_BITS); */ void x86_cpu_do_interrupt(CPUState *cpu); #ifndef CONFIG_USER_ONLY +void x86_cpu_exec_halt(CPUState *cpu); bool x86_need_replay_interrupt(int interrupt_request); bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req); #endif diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c index e6f42282bb..2db8083748 100644 --- a/target/i386/tcg/sysemu/seg_helper.c +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" @@ -127,6 +128,18 @@ void x86_cpu_do_interrupt(CPUState *cs) } } +void x86_cpu_exec_halt(CPUState *cpu) +{ + if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { + X86CPU *x86_cpu = X86_CPU(cpu); + + bql_lock(); + apic_poll_irq(x86_cpu->apic_state); + cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL); + bql_unlock(); + } +} + bool x86_need_replay_interrupt(int interrupt_request) { /* diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 5bdcf45199..cca19cd40e 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -119,6 +119,7 @@ static const TCGCPUOps x86_tcg_ops = { #else .tlb_fill = x86_cpu_tlb_fill, .do_interrupt = x86_cpu_do_interrupt, + .cpu_exec_halt = x86_cpu_exec_halt, .cpu_exec_interrupt = x86_cpu_exec_interrupt, .do_unaligned_access = x86_cpu_do_unaligned_access, .debug_excp_handler = breakpoint_handler,