Generic CPUs / accelerators patch queue

- Access CPUState::thread_kicked atomically
 - Fix bql_locked status with condvar APIs
 - Document cpu_memory_rw_debug()
 - Rename init_clocks() -> qemu_init_clocks() to avoid name clashing
 - Fix QEMU_HEXDUMP_LINE_WIDTH logic
 - Fix interrupts check in rx_cpu_do_interrupt()
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmkIrCIACgkQ4+MsLN6t
 wN6wSRAAkfYKbLKLqdrYpuz+D94KSnhrBxqXaC9RH+Q48VQS5Du4IBXfuTPtUa5+
 ii73XmEl3J83NbK+miH5rqRuRNCqj/MC1MUeFuXDjI2kkIupZMnarus4kS/zZ0zE
 KgJeZxfuHXkxs7SLjk/N1b8/BJSZXfXybtNVhnzPTS6UyuGvx3MBf5g3NtwlVC4B
 J3o/5klyxFzB9oyASg0pTCXnjdTnqakre1MnYFoEctxDq+W3AJgiT6MVkVWuPtxn
 AbN1Zf9vi/e7UyVB2r8NprMfgukJBiMIQK/yfwkWOr1iE4aUSapLCvZEc1ZuL5RF
 asFZ5sptn0QU0nJX2UTs/dWWdukLyffem/OIp737WsXR3EPCcWIEVF8oXlRcdGR0
 BBkyWP6H0v75lvD4V+cn0hUXeT2tSAWBddtSvIZ08tfIo1z6s+ckVPY1C3m3xbXt
 BsWjKaFG7UlkUXfmgXlkaNYzzicZTg1arOIQ4InPlIeJ+6gzWad3ciRk7zIyEpSA
 EizIIxI9WILcG2Qp5MvXuCiTQvPlN2AhOq7Z3L+XyeAK/7qXpUmlrdMeTshJE5z4
 rQHt0tb689ma/Vm0/NbZZ8RY66xgdpGcYjNYgthm4nkah02a07keLVKXxBF8oWbV
 v4LRE9Vprv0WP8zVKfuWi7s/L2HmNZodHGB+lrAJddqTl7X2lIc=
 =BKNk
 -----END PGP SIGNATURE-----

Merge tag 'accel-cpus-20251103' of https://github.com/philmd/qemu into staging

Generic CPUs / accelerators patch queue

- Access CPUState::thread_kicked atomically
- Fix bql_locked status with condvar APIs
- Document cpu_memory_rw_debug()
- Rename init_clocks() -> qemu_init_clocks() to avoid name clashing
- Fix QEMU_HEXDUMP_LINE_WIDTH logic
- Fix interrupts check in rx_cpu_do_interrupt()

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmkIrCIACgkQ4+MsLN6t
# wN6wSRAAkfYKbLKLqdrYpuz+D94KSnhrBxqXaC9RH+Q48VQS5Du4IBXfuTPtUa5+
# ii73XmEl3J83NbK+miH5rqRuRNCqj/MC1MUeFuXDjI2kkIupZMnarus4kS/zZ0zE
# KgJeZxfuHXkxs7SLjk/N1b8/BJSZXfXybtNVhnzPTS6UyuGvx3MBf5g3NtwlVC4B
# J3o/5klyxFzB9oyASg0pTCXnjdTnqakre1MnYFoEctxDq+W3AJgiT6MVkVWuPtxn
# AbN1Zf9vi/e7UyVB2r8NprMfgukJBiMIQK/yfwkWOr1iE4aUSapLCvZEc1ZuL5RF
# asFZ5sptn0QU0nJX2UTs/dWWdukLyffem/OIp737WsXR3EPCcWIEVF8oXlRcdGR0
# BBkyWP6H0v75lvD4V+cn0hUXeT2tSAWBddtSvIZ08tfIo1z6s+ckVPY1C3m3xbXt
# BsWjKaFG7UlkUXfmgXlkaNYzzicZTg1arOIQ4InPlIeJ+6gzWad3ciRk7zIyEpSA
# EizIIxI9WILcG2Qp5MvXuCiTQvPlN2AhOq7Z3L+XyeAK/7qXpUmlrdMeTshJE5z4
# rQHt0tb689ma/Vm0/NbZZ8RY66xgdpGcYjNYgthm4nkah02a07keLVKXxBF8oWbV
# v4LRE9Vprv0WP8zVKfuWi7s/L2HmNZodHGB+lrAJddqTl7X2lIc=
# =BKNk
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 03 Nov 2025 02:20:34 PM CET
# gpg:                using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD  6BB2 E3E3 2C2C DEAD C0DE

* tag 'accel-cpus-20251103' of https://github.com/philmd/qemu:
  rx: cpu: fix interrupts check in rx_cpu_do_interrupt()
  util/hexdump: fix QEMU_HEXDUMP_LINE_WIDTH logic
  timers: properly prefix init_clocks()
  exec/cpu: Declare cpu_memory_rw_debug() in 'hw/core/cpu.h' and document
  bql: Fix bql_locked status with condvar APIs
  accel/tcg: Use cpu_is_stopped() helper to access CPUState::stopped
  cpus: Access CPUState::thread_kicked atomically

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2025-11-04 12:48:03 +01:00
commit dcc6d1d956
13 changed files with 119 additions and 53 deletions

View file

@ -197,7 +197,7 @@ static void *rr_cpu_thread_fn(void *arg)
qemu_guest_random_seed_thread_part2(cpu->random_seed);
/* wait for initial kick-off after machine start */
while (first_cpu->stopped) {
while (cpu_is_stopped(first_cpu)) {
qemu_cond_wait_bql(first_cpu->halt_cond);
/* process any pending work */

View file

@ -150,10 +150,6 @@ typedef int (RAMBlockIterFunc)(RAMBlock *rb, void *opaque);
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
/* Returns: 0 on success, -1 on error */
int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
void *ptr, size_t len, bool is_write);
/* vl.c */
void list_cpus(void);

View file

@ -688,6 +688,26 @@ int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
/**
* cpu_memory_rw_debug:
* @cpu: The CPU whose memory is to be accessed
* @addr: guest virtual address
* @ptr: buffer with the data transferred
* @len: the number of bytes to read or write
* @is_write: indicates the transfer direction
*
* Take a virtual address, convert it to a physical address via
* an MMU lookup using the current settings of the specified CPU,
* and then perform the access (using address_space_rw() for
* reads or address_space_write_rom() for writes).
*
* This function is intended for use by the GDB stub and similar code.
*
* Returns: 0 on success, -1 on error
*/
int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
void *ptr, size_t len, bool is_write);
/**
* cpu_get_crash_info:
* @cpu: The CPU to get crash information for

View file

@ -270,6 +270,24 @@ void rust_bql_mock_lock(void);
*/
bool bql_locked(void);
/**
* mutex_is_bql:
*
* @mutex: the mutex pointer
*
* Returns whether the mutex is the BQL.
*/
bool mutex_is_bql(QemuMutex *mutex);
/**
* bql_update_status:
*
* @locked: update status on whether the BQL is locked
*
* NOTE: this should normally only be invoked when the status changed.
*/
void bql_update_status(bool locked);
/**
* bql_block: Allow/deny releasing the BQL
*

View file

@ -786,11 +786,12 @@ static inline int64_t qemu_soonest_timeout(int64_t timeout1, int64_t timeout2)
}
/**
* initclocks:
* qemu_init_clocks:
* @notify_cb: optional call-back for timer expiry
*
* Initialise the clock & timer infrastructure
*/
void init_clocks(QEMUTimerListNotifyCB *notify_cb);
void qemu_init_clocks(QEMUTimerListNotifyCB *notify_cb);
static inline int64_t get_max_clock_jump(void)
{

View file

@ -34,3 +34,12 @@ void bql_block_unlock(bool increase)
assert((new_value > bql_unlock_blocked) == increase);
bql_unlock_blocked = new_value;
}
bool mutex_is_bql(QemuMutex *mutex)
{
return false;
}
void bql_update_status(bool locked)
{
}

View file

@ -480,10 +480,10 @@ void qemu_process_cpu_events(CPUState *cpu)
void cpus_kick_thread(CPUState *cpu)
{
if (cpu->thread_kicked) {
if (qatomic_read(&cpu->thread_kicked)) {
return;
}
cpu->thread_kicked = true;
qatomic_set(&cpu->thread_kicked, true);
#ifndef _WIN32
int err = pthread_kill(cpu->thread->thread, SIG_IPI);
@ -524,6 +524,18 @@ bool qemu_in_vcpu_thread(void)
QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
bool mutex_is_bql(QemuMutex *mutex)
{
return mutex == &bql;
}
void bql_update_status(bool locked)
{
/* This function should only be used when an update happened.. */
assert(bql_locked() != locked);
set_bql_locked(locked);
}
static uint32_t bql_unlock_blocked;
void bql_block_unlock(bool increase)
@ -564,14 +576,12 @@ void bql_lock_impl(const char *file, int line)
g_assert(!bql_locked());
bql_lock_fn(&bql, file, line);
set_bql_locked(true);
}
void bql_unlock(void)
{
g_assert(bql_locked());
g_assert(!bql_unlock_blocked);
set_bql_locked(false);
qemu_mutex_unlock(&bql);
}

View file

@ -41,11 +41,9 @@ void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte)
env->psw_c = FIELD_EX32(psw, PSW, C);
}
#define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR)
void rx_cpu_do_interrupt(CPUState *cs)
{
CPURXState *env = cpu_env(cs);
int do_irq = cpu_test_interrupt(cs, INT_FLAGS);
uint32_t save_psw;
uint64_t last_pc = env->pc;
@ -59,29 +57,26 @@ void rx_cpu_do_interrupt(CPUState *cs)
save_psw = rx_cpu_pack_psw(env);
env->psw_pm = env->psw_i = env->psw_u = 0;
if (do_irq) {
if (do_irq & CPU_INTERRUPT_FIR) {
env->bpc = env->pc;
env->bpsw = save_psw;
env->pc = env->fintv;
env->psw_ipl = 15;
cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR);
qemu_set_irq(env->ack, env->ack_irq);
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
} else if (do_irq & CPU_INTERRUPT_HARD) {
env->isp -= 4;
cpu_stl_data(env, env->isp, save_psw);
env->isp -= 4;
cpu_stl_data(env, env->isp, env->pc);
env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
env->psw_ipl = env->ack_ipl;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
qemu_set_irq(env->ack, env->ack_irq);
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
qemu_log_mask(CPU_LOG_INT,
"interrupt 0x%02x raised\n", env->ack_irq);
}
if (cpu_test_interrupt(cs, CPU_INTERRUPT_FIR)) {
env->bpc = env->pc;
env->bpsw = save_psw;
env->pc = env->fintv;
env->psw_ipl = 15;
cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR);
qemu_set_irq(env->ack, env->ack_irq);
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
} else if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD)) {
env->isp -= 4;
cpu_stl_data(env, env->isp, save_psw);
env->isp -= 4;
cpu_stl_data(env, env->isp, env->pc);
env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
env->psw_ipl = env->ack_ipl;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
qemu_set_irq(env->ack, env->ack_irq);
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
qemu_log_mask(CPU_LOG_INT, "interrupt 0x%02x raised\n", env->ack_irq);
} else {
uint32_t vec = cs->exception_index;
const char *expname = "unknown exception";

View file

@ -443,7 +443,7 @@ static void test_multi_mutex_10(void)
int main(int argc, char **argv)
{
init_clocks(NULL);
qemu_init_clocks(NULL);
g_test_init(&argc, &argv, NULL);
g_test_add_func("/aio/multi/lifecycle", test_lifecycle);

View file

@ -22,6 +22,19 @@ static inline char hexdump_nibble(unsigned x)
return (x < 10 ? '0' : 'a' - 10) + x;
}
static size_t hexdump_line_length(size_t buf_len, size_t unit_len,
size_t block_len)
{
size_t est = buf_len * 2;
if (unit_len) {
est += buf_len / unit_len;
}
if (block_len) {
est += buf_len / block_len;
}
return est;
}
GString *qemu_hexdump_line(GString *str, const void *vbuf, size_t len,
size_t unit_len, size_t block_len)
{
@ -30,14 +43,8 @@ GString *qemu_hexdump_line(GString *str, const void *vbuf, size_t len,
if (str == NULL) {
/* Estimate the length of the output to avoid reallocs. */
size_t est = len * 2;
if (unit_len) {
est += len / unit_len;
}
if (block_len) {
est += len / block_len;
}
str = g_string_sized_new(est + 1);
str = g_string_sized_new(hexdump_line_length(len, unit_len, block_len)
+ 1);
}
for (u = 0, b = 0; len; u++, b++, len--, buf++) {
@ -76,13 +83,16 @@ static void asciidump_line(char *line, const void *bufptr, size_t len)
}
#define QEMU_HEXDUMP_LINE_BYTES 16
#define QEMU_HEXDUMP_LINE_WIDTH \
(QEMU_HEXDUMP_LINE_BYTES * 2 + QEMU_HEXDUMP_LINE_BYTES / 4)
#define QEMU_HEXDUMP_UNIT 1
#define QEMU_HEXDUMP_BLOCK 4
void qemu_hexdump(FILE *fp, const char *prefix,
const void *bufptr, size_t size)
{
g_autoptr(GString) str = g_string_sized_new(QEMU_HEXDUMP_LINE_WIDTH + 1);
int width = hexdump_line_length(QEMU_HEXDUMP_LINE_BYTES,
QEMU_HEXDUMP_UNIT,
QEMU_HEXDUMP_BLOCK);
g_autoptr(GString) str = g_string_sized_new(width + 1);
char ascii[QEMU_HEXDUMP_LINE_BYTES + 1];
size_t b, len;
@ -90,11 +100,11 @@ void qemu_hexdump(FILE *fp, const char *prefix,
len = MIN(size - b, QEMU_HEXDUMP_LINE_BYTES);
g_string_truncate(str, 0);
qemu_hexdump_line(str, bufptr + b, len, 1, 4);
qemu_hexdump_line(str, bufptr + b, len,
QEMU_HEXDUMP_UNIT, QEMU_HEXDUMP_BLOCK);
asciidump_line(ascii, bufptr + b, len);
fprintf(fp, "%s: %04zx: %-*s %s\n",
prefix, b, QEMU_HEXDUMP_LINE_WIDTH, str->str, ascii);
fprintf(fp, "%s: %04zx: %-*s %s\n", prefix, b, width, str->str, ascii);
}
}

View file

@ -162,7 +162,7 @@ int qemu_init_main_loop(Error **errp)
int ret;
GSource *src;
init_clocks(qemu_timer_notify_cb);
qemu_init_clocks(qemu_timer_notify_cb);
ret = qemu_signal_init(errp);
if (ret) {

View file

@ -14,6 +14,7 @@
#define QEMU_THREAD_COMMON_H
#include "qemu/thread.h"
#include "qemu/main-loop.h"
#include "trace.h"
static inline void qemu_mutex_post_init(QemuMutex *mutex)
@ -39,6 +40,9 @@ static inline void qemu_mutex_post_lock(QemuMutex *mutex,
mutex->line = line;
#endif
trace_qemu_mutex_locked(mutex, file, line);
if (mutex_is_bql(mutex)) {
bql_update_status(true);
}
}
static inline void qemu_mutex_pre_unlock(QemuMutex *mutex,
@ -49,6 +53,9 @@ static inline void qemu_mutex_pre_unlock(QemuMutex *mutex,
mutex->line = 0;
#endif
trace_qemu_mutex_unlock(mutex, file, line);
if (mutex_is_bql(mutex)) {
bql_update_status(false);
}
}
#endif

View file

@ -637,7 +637,7 @@ static void qemu_virtual_clock_set_ns(int64_t time)
return cpus_set_virtual_clock(time);
}
void init_clocks(QEMUTimerListNotifyCB *notify_cb)
void qemu_init_clocks(QEMUTimerListNotifyCB *notify_cb)
{
QEMUClockType type;
for (type = 0; type < QEMU_CLOCK_MAX; type++) {