From d157e540edc2dbc30b66c26d8378c724ffcac8d0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 22 Jan 2024 16:34:09 +0100 Subject: 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 ++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 43 deletions(-) (limited to 'accel/tcg/cpu-exec.c') 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 -- cgit 1.4.1 From f5e9362af1ad9514fb2cb283cecaa723b5c6cc40 Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Wed, 24 Jan 2024 08:41:56 +0100 Subject: 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(-) (limited to 'accel/tcg/cpu-exec.c') 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; } -- cgit 1.4.1 From 93c6091bfa41792b28b25cd7e3c1f578e44b0d15 Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Wed, 24 Jan 2024 11:16:34 +0100 Subject: 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(-) (limited to 'accel/tcg/cpu-exec.c') 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; -- cgit 1.4.1 From 991bd65ddd3282f2422837a593adc621c0defc2d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 28 Jan 2024 12:57:59 +1000 Subject: 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 | 101 ++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 49 deletions(-) (limited to 'accel/tcg/cpu-exec.c') 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 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); + 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; + *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 (replay_exception()) { + const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - 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; + 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; } -- cgit 1.4.1 From 0fdc69b76ee67583e0fe0e0fd31da212f506cd66 Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Wed, 24 Jan 2024 11:16:36 +0100 Subject: 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(-) (limited to 'accel/tcg/cpu-exec.c') 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 */ -- cgit 1.4.1 From 6ae754815f341f0a6dfe9c43ffe25e51375264b8 Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Wed, 24 Jan 2024 11:16:37 +0100 Subject: 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(-) (limited to 'accel/tcg/cpu-exec.c') 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 */ }; -- cgit 1.4.1 From b7e9a4a9b0d74aca386682d384d4ad0d20226d24 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 28 Jan 2024 13:12:54 +1000 Subject: 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(-) (limited to 'accel/tcg/cpu-exec.c') 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(); } /* -- cgit 1.4.1 From aa6fb65746c90496c3829fd49f86c7b059c4b846 Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Wed, 24 Jan 2024 11:16:38 +0100 Subject: 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(+) (limited to 'accel/tcg/cpu-exec.c') 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 * -- cgit 1.4.1 From ec1d32af123e7f13d98754a72bcaa7aa8c8e9d27 Mon Sep 17 00:00:00 2001 From: Philippe Mathieu-Daudé Date: Wed, 24 Jan 2024 11:16:39 +0100 Subject: 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(-) (limited to 'accel/tcg/cpu-exec.c') 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, -- cgit 1.4.1