* [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts
@ 2026-10-26 12:56 Peter Maydell
2026-10-26 12:56 ` [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept Peter Maydell
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Peter Maydell @ 2026-10-26 12:56 UTC (permalink / raw)
To: qemu-devel; +Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini
Currently both system/qtest.c and libqtest have a 256 IRQ limit
on the size of an irq_intercept_in. If you try it with more then
qtest.c will overrun its array, and libqtest will trip an assert.
We have some real devices in board models that use more inbound
IRQs than this (e.g. the GIC in the Arm virt board).
This series removes both the fixed-sized arrays, so there's
no artificial limit on how many GPIO lines we can cope with.
I also fix in patch 2 a bug I noticed while doing this, where
we don't check the GPIO group name for irq_intercept_in, so
we apply the intercept to every input GPIO group the device
has rather than only to the unnamed GPIO inputs.
I haven't bothered to cc:stable on these because we don't
trip over the limit for any of our existing qtests, though
I don't anticipate there being any issues with the backport.
thanks
-- PMM
Peter Maydell (3):
system/qtest: Avoid fixed-size irq_levels array for IRQ intercept
system/qtest: Check ngl->name for irq_intercept_in
tests/qtest/libqtest: Use a GArray for QTestState::irq_level[]
system/qtest.c | 47 +++++++++++++++++++++++++++++-------------
tests/qtest/libqtest.c | 28 ++++++++++++-------------
2 files changed, 47 insertions(+), 28 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept
2026-10-26 12:56 [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Peter Maydell
@ 2026-10-26 12:56 ` Peter Maydell
2026-10-27 12:21 ` Fabiano Rosas
2026-10-26 12:56 ` [PATCH 2/3] system/qtest: Check ngl->name for irq_intercept_in Peter Maydell
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2026-10-26 12:56 UTC (permalink / raw)
To: qemu-devel; +Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini
The current implementation of the irq_intercept_out and
irq_intercept_in commands uses a fixed-size static irq_levels[] array
to track the state of the intercepted IRQ lines. This is sized at
MAX_IRQ == 256, which is smaller than some real device models use
(for instance the GICv2 on the virt board has 384 inputs). A test
that tried to intercept the inputs to such a device and then assert
an interrupt over 255 would overrun the array.
Reimplement the IRQ interception so that it allocates an array
of the required size rather than using a static one.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
system/qtest.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/system/qtest.c b/system/qtest.c
index 47c954838dd..a3de815ce65 100644
--- a/system/qtest.c
+++ b/system/qtest.c
@@ -57,12 +57,18 @@ static DeviceState *irq_intercept_dev;
static FILE *qtest_log_fp;
static QTest *qtest;
static GString *inbuf;
-static int irq_levels[MAX_IRQ];
static GTimer *timer;
static bool qtest_opened;
static void (*qtest_server_send)(void*, const char*);
static void *qtest_server_send_opaque;
+typedef struct IrqInterceptState {
+ int *irq_levels;
+ int num_irqs;
+} IrqInterceptState;
+
+IrqInterceptState irq_intercept_state;
+
#define FMT_timeval "%.06f"
/**
@@ -327,9 +333,10 @@ void qtest_sendf(CharFrontend *chr, const char *fmt, ...)
static void qtest_irq_handler(void *opaque, int n, int level)
{
- if (irq_levels[n] != level) {
+ assert(n >= 0 && n < irq_intercept_state.num_irqs);
+ if (irq_intercept_state.irq_levels[n] != level) {
CharFrontend *chr = &qtest->qtest_chr;
- irq_levels[n] = level;
+ irq_intercept_state.irq_levels[n] = level;
qtest_sendf(chr, "IRQ %s %d\n",
level ? "raise" : "lower", n);
}
@@ -353,6 +360,13 @@ static void qtest_install_gpio_out_intercept(DeviceState *dev, const char *name,
*disconnected = qdev_intercept_gpio_out(dev, icpt, name, n);
}
+static void qtest_init_irq_intercept(int num_irqs)
+{
+ g_free(irq_intercept_state.irq_levels);
+ irq_intercept_state.irq_levels = g_new0(int, num_irqs);
+ irq_intercept_state.num_irqs = num_irqs;
+}
+
static void qtest_process_command(CharFrontend *chr, gchar **words)
{
const gchar *command;
@@ -413,12 +427,14 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)
/* NULL is valid and matchable, for "unnamed GPIO" */
if (g_strcmp0(ngl->name, words[2]) == 0) {
int i;
+ qtest_init_irq_intercept(ngl->num_out);
for (i = 0; i < ngl->num_out; ++i) {
qtest_install_gpio_out_intercept(dev, ngl->name, i);
}
interception_succeeded = true;
}
} else {
+ qtest_init_irq_intercept(ngl->num_in);
qemu_irq_set_observer(ngl->in, qtest_irq_handler,
ngl->num_in);
interception_succeeded = true;
@@ -861,8 +877,10 @@ static void qtest_event(void *opaque, QEMUChrEvent event)
* used. Injects an extra reset even when it's not used, and
* that can mess up tests, e.g. -boot once.
*/
- for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
- irq_levels[i] = 0;
+ if (irq_intercept_state.irq_levels) {
+ for (i = 0; i < irq_intercept_state.num_irqs; i++) {
+ irq_intercept_state.irq_levels[i] = 0;
+ }
}
g_clear_pointer(&timer, g_timer_destroy);
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] system/qtest: Check ngl->name for irq_intercept_in
2026-10-26 12:56 [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Peter Maydell
2026-10-26 12:56 ` [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept Peter Maydell
@ 2026-10-26 12:56 ` Peter Maydell
2026-10-27 12:24 ` Fabiano Rosas
2026-10-26 12:56 ` [PATCH 3/3] tests/qtest/libqtest: Use a GArray for QTestState::irq_level[] Peter Maydell
2026-10-27 12:30 ` [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Fabiano Rosas
3 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2026-10-26 12:56 UTC (permalink / raw)
To: qemu-devel; +Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini
Currently we check the name of the NamedGPIOList when doing
irq_intercept_out, but not for irq_intercept_in. Even though we
don't currently support irq_intercept_in on named GPIO lines, we
still need to check the name, because otherwise we will install the
observer on every set of GPIO inputs the device has, rather than only
for the unnamed GPIO inputs.
This doesn't currently affect any test cases, because of all the
tests which use irq_intercept_in only tests/qtest-l2vic-test.c uses
it on a device that creates named GPIO inputs. That device has both
unnamed GPIO inputs and a named GPIO input "reset". The effect is
that a change in the "reset" line state looks like a change in
interrupt input line 0; but since the test doesn't cause "reset" to
change this doesn't happen and there are no observable effects of the
bug.
Check the ngl->name against the specified one for both input
and output interception. (Currently this will be equivalent to
a check against NULL for input intercepts.) As we're now checking
for an exact name match unconditionally, we can break out of the
loop as soon as we've found it.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
The forbidding of intercept_in for named GPIOs is done before
the loop. I think the only reason we forbid it is that we don't
have a mechanism for the "IRQ raise"/"IRQ lower" messages to
say what GPIO they're for. Similarly I don't think supporting
intercepts of multiple devices simultaneously would be too
hard; but I'd rather wait til we have a test that actually wants
that functionality.
---
system/qtest.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/system/qtest.c b/system/qtest.c
index a3de815ce65..5ff3f9f27d8 100644
--- a/system/qtest.c
+++ b/system/qtest.c
@@ -422,23 +422,24 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)
}
QLIST_FOREACH(ngl, &dev->gpios, node) {
- /* We don't support inbound interception of named GPIOs yet */
+ /* NULL is valid and matchable, for "unnamed GPIO" */
+ if (g_strcmp0(ngl->name, words[2]) != 0) {
+ continue;
+ }
+
if (is_outbound) {
- /* NULL is valid and matchable, for "unnamed GPIO" */
- if (g_strcmp0(ngl->name, words[2]) == 0) {
- int i;
- qtest_init_irq_intercept(ngl->num_out);
- for (i = 0; i < ngl->num_out; ++i) {
- qtest_install_gpio_out_intercept(dev, ngl->name, i);
- }
- interception_succeeded = true;
+ int i;
+ qtest_init_irq_intercept(ngl->num_out);
+ for (i = 0; i < ngl->num_out; ++i) {
+ qtest_install_gpio_out_intercept(dev, ngl->name, i);
}
} else {
qtest_init_irq_intercept(ngl->num_in);
qemu_irq_set_observer(ngl->in, qtest_irq_handler,
ngl->num_in);
- interception_succeeded = true;
}
+ interception_succeeded = true;
+ break;
}
if (interception_succeeded) {
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/3] tests/qtest/libqtest: Use a GArray for QTestState::irq_level[]
2026-10-26 12:56 [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Peter Maydell
2026-10-26 12:56 ` [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept Peter Maydell
2026-10-26 12:56 ` [PATCH 2/3] system/qtest: Check ngl->name for irq_intercept_in Peter Maydell
@ 2026-10-26 12:56 ` Peter Maydell
2026-10-27 12:30 ` Fabiano Rosas
2026-10-27 12:30 ` [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Fabiano Rosas
3 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2026-10-26 12:56 UTC (permalink / raw)
To: qemu-devel; +Cc: Fabiano Rosas, Laurent Vivier, Paolo Bonzini
Currently we use a fixed irq_level[] array of 256 elements in
QTestState to implement capturing the IRQ level reported by the QEMU
under test so we can return it in qtest_get_irq(). This is smaller
than is actually used by some devices, and if a test tries to
intercept more IRQs than this and one is reported to libqtest then
we'll fail an assertion in qtest_rsp_args().
Switch to a GArray, which automatically resizes as required.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
tests/qtest/libqtest.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 9e7a2d43a18..22b0dc193c9 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -42,8 +42,6 @@
#include "qobject/qstring.h"
#include "qobject/qbool.h"
-#define MAX_IRQ 256
-
#define ACCEPT_TIMEOUT_MS 250
#define ACCEPT_RETRIES (4 * 50)
@@ -88,7 +86,7 @@ struct QTestState
#endif
int expected_status;
bool big_endian;
- bool irq_level[MAX_IRQ];
+ GArray *irq_level;
GString *rx;
QTestTransportOps ops;
GList *pending_events;
@@ -501,7 +499,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
void *opaque)
{
QTestState *s;
- int sock, qmpsock, i;
+ int sock, qmpsock;
g_autofree gchar *socket_path = qtest_socket_path("sock");
g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp");
g_autofree gchar *args = qtest_qemu_args(extra_args);
@@ -525,9 +523,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
qtest_client_set_tx_handler(s, qtest_client_socket_send);
s->rx = g_string_new("");
- for (i = 0; i < MAX_IRQ; i++) {
- s->irq_level[i] = false;
- }
+ s->irq_level = g_array_new(false, true, sizeof(bool));
s->fd = -1;
s->qmp_fd = -1;
@@ -693,6 +689,7 @@ void qtest_quit(QTestState *s)
close(s->fd);
close(s->qmp_fd);
g_string_free(s->rx, true);
+ g_array_unref(s->irq_level);
for (GList *it = s->pending_events; it != NULL; it = it->next) {
qobject_unref((QDict *)it->data);
@@ -778,12 +775,14 @@ redo:
ret = qemu_strtol(words[2], NULL, 0, &irq);
g_assert(!ret);
g_assert_cmpint(irq, >=, 0);
- g_assert_cmpint(irq, <, MAX_IRQ);
+ if (s->irq_level->len <= irq) {
+ g_array_set_size(s->irq_level, irq + 1);
+ }
if (strcmp(words[1], "raise") == 0) {
- s->irq_level[irq] = true;
+ g_array_index(s->irq_level, bool, irq) = true;
} else {
- s->irq_level[irq] = false;
+ g_array_index(s->irq_level, bool, irq) = false;
}
g_strfreev(words);
@@ -1192,7 +1191,10 @@ bool qtest_get_irq(QTestState *s, int num)
/* dummy operation in order to make sure irq is up to date */
qtest_inb(s, 0);
- return s->irq_level[num];
+ if (s->irq_level->len <= num) {
+ return false;
+ }
+ return g_array_index(s->irq_level, bool, num);
}
void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
@@ -2100,9 +2102,7 @@ QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
qts->pending_events = NULL;
*s = qts; /* Expose qts early on, since the query endianness relies on it */
qts->wstatus = 0;
- for (int i = 0; i < MAX_IRQ; i++) {
- qts->irq_level[i] = false;
- }
+ qts->irq_level = g_array_new(false, true, sizeof(bool));
qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line);
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept
2026-10-26 12:56 ` [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept Peter Maydell
@ 2026-10-27 12:21 ` Fabiano Rosas
0 siblings, 0 replies; 8+ messages in thread
From: Fabiano Rosas @ 2026-10-27 12:21 UTC (permalink / raw)
To: Peter Maydell, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini
Peter Maydell <peter.maydell@linaro.org> writes:
> The current implementation of the irq_intercept_out and
> irq_intercept_in commands uses a fixed-size static irq_levels[] array
> to track the state of the intercepted IRQ lines. This is sized at
> MAX_IRQ == 256, which is smaller than some real device models use
> (for instance the GICv2 on the virt board has 384 inputs). A test
> that tried to intercept the inputs to such a device and then assert
> an interrupt over 255 would overrun the array.
>
> Reimplement the IRQ interception so that it allocates an array
> of the required size rather than using a static one.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> system/qtest.c | 28 +++++++++++++++++++++++-----
> 1 file changed, 23 insertions(+), 5 deletions(-)
>
> diff --git a/system/qtest.c b/system/qtest.c
> index 47c954838dd..a3de815ce65 100644
> --- a/system/qtest.c
> +++ b/system/qtest.c
> @@ -57,12 +57,18 @@ static DeviceState *irq_intercept_dev;
> static FILE *qtest_log_fp;
> static QTest *qtest;
> static GString *inbuf;
> -static int irq_levels[MAX_IRQ];
> static GTimer *timer;
> static bool qtest_opened;
> static void (*qtest_server_send)(void*, const char*);
> static void *qtest_server_send_opaque;
>
> +typedef struct IrqInterceptState {
> + int *irq_levels;
> + int num_irqs;
> +} IrqInterceptState;
> +
> +IrqInterceptState irq_intercept_state;
> +
> #define FMT_timeval "%.06f"
>
> /**
> @@ -327,9 +333,10 @@ void qtest_sendf(CharFrontend *chr, const char *fmt, ...)
>
> static void qtest_irq_handler(void *opaque, int n, int level)
> {
> - if (irq_levels[n] != level) {
> + assert(n >= 0 && n < irq_intercept_state.num_irqs);
> + if (irq_intercept_state.irq_levels[n] != level) {
> CharFrontend *chr = &qtest->qtest_chr;
> - irq_levels[n] = level;
> + irq_intercept_state.irq_levels[n] = level;
> qtest_sendf(chr, "IRQ %s %d\n",
> level ? "raise" : "lower", n);
> }
> @@ -353,6 +360,13 @@ static void qtest_install_gpio_out_intercept(DeviceState *dev, const char *name,
> *disconnected = qdev_intercept_gpio_out(dev, icpt, name, n);
> }
>
> +static void qtest_init_irq_intercept(int num_irqs)
> +{
> + g_free(irq_intercept_state.irq_levels);
> + irq_intercept_state.irq_levels = g_new0(int, num_irqs);
> + irq_intercept_state.num_irqs = num_irqs;
> +}
> +
> static void qtest_process_command(CharFrontend *chr, gchar **words)
> {
> const gchar *command;
> @@ -413,12 +427,14 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)
> /* NULL is valid and matchable, for "unnamed GPIO" */
> if (g_strcmp0(ngl->name, words[2]) == 0) {
> int i;
> + qtest_init_irq_intercept(ngl->num_out);
> for (i = 0; i < ngl->num_out; ++i) {
> qtest_install_gpio_out_intercept(dev, ngl->name, i);
> }
> interception_succeeded = true;
> }
> } else {
> + qtest_init_irq_intercept(ngl->num_in);
> qemu_irq_set_observer(ngl->in, qtest_irq_handler,
> ngl->num_in);
> interception_succeeded = true;
> @@ -861,8 +877,10 @@ static void qtest_event(void *opaque, QEMUChrEvent event)
> * used. Injects an extra reset even when it's not used, and
> * that can mess up tests, e.g. -boot once.
> */
> - for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
> - irq_levels[i] = 0;
> + if (irq_intercept_state.irq_levels) {
> + for (i = 0; i < irq_intercept_state.num_irqs; i++) {
> + irq_intercept_state.irq_levels[i] = 0;
> + }
> }
>
> g_clear_pointer(&timer, g_timer_destroy);
Reviewed-by: Fabiano Rosas <farosas@suse.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] system/qtest: Check ngl->name for irq_intercept_in
2026-10-26 12:56 ` [PATCH 2/3] system/qtest: Check ngl->name for irq_intercept_in Peter Maydell
@ 2026-10-27 12:24 ` Fabiano Rosas
0 siblings, 0 replies; 8+ messages in thread
From: Fabiano Rosas @ 2026-10-27 12:24 UTC (permalink / raw)
To: Peter Maydell, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini
Peter Maydell <peter.maydell@linaro.org> writes:
> Currently we check the name of the NamedGPIOList when doing
> irq_intercept_out, but not for irq_intercept_in. Even though we
> don't currently support irq_intercept_in on named GPIO lines, we
> still need to check the name, because otherwise we will install the
> observer on every set of GPIO inputs the device has, rather than only
> for the unnamed GPIO inputs.
>
> This doesn't currently affect any test cases, because of all the
> tests which use irq_intercept_in only tests/qtest-l2vic-test.c uses
> it on a device that creates named GPIO inputs. That device has both
> unnamed GPIO inputs and a named GPIO input "reset". The effect is
> that a change in the "reset" line state looks like a change in
> interrupt input line 0; but since the test doesn't cause "reset" to
> change this doesn't happen and there are no observable effects of the
> bug.
>
> Check the ngl->name against the specified one for both input
> and output interception. (Currently this will be equivalent to
> a check against NULL for input intercepts.) As we're now checking
> for an exact name match unconditionally, we can break out of the
> loop as soon as we've found it.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> The forbidding of intercept_in for named GPIOs is done before
> the loop. I think the only reason we forbid it is that we don't
> have a mechanism for the "IRQ raise"/"IRQ lower" messages to
> say what GPIO they're for. Similarly I don't think supporting
> intercepts of multiple devices simultaneously would be too
> hard; but I'd rather wait til we have a test that actually wants
> that functionality.
> ---
> system/qtest.c | 21 +++++++++++----------
> 1 file changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/system/qtest.c b/system/qtest.c
> index a3de815ce65..5ff3f9f27d8 100644
> --- a/system/qtest.c
> +++ b/system/qtest.c
> @@ -422,23 +422,24 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)
> }
>
> QLIST_FOREACH(ngl, &dev->gpios, node) {
> - /* We don't support inbound interception of named GPIOs yet */
> + /* NULL is valid and matchable, for "unnamed GPIO" */
> + if (g_strcmp0(ngl->name, words[2]) != 0) {
> + continue;
> + }
> +
> if (is_outbound) {
> - /* NULL is valid and matchable, for "unnamed GPIO" */
> - if (g_strcmp0(ngl->name, words[2]) == 0) {
> - int i;
> - qtest_init_irq_intercept(ngl->num_out);
> - for (i = 0; i < ngl->num_out; ++i) {
> - qtest_install_gpio_out_intercept(dev, ngl->name, i);
> - }
> - interception_succeeded = true;
> + int i;
> + qtest_init_irq_intercept(ngl->num_out);
> + for (i = 0; i < ngl->num_out; ++i) {
> + qtest_install_gpio_out_intercept(dev, ngl->name, i);
> }
> } else {
> qtest_init_irq_intercept(ngl->num_in);
> qemu_irq_set_observer(ngl->in, qtest_irq_handler,
> ngl->num_in);
> - interception_succeeded = true;
> }
> + interception_succeeded = true;
> + break;
> }
>
> if (interception_succeeded) {
Reviewed-by: Fabiano Rosas <farosas@suse.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] tests/qtest/libqtest: Use a GArray for QTestState::irq_level[]
2026-10-26 12:56 ` [PATCH 3/3] tests/qtest/libqtest: Use a GArray for QTestState::irq_level[] Peter Maydell
@ 2026-10-27 12:30 ` Fabiano Rosas
0 siblings, 0 replies; 8+ messages in thread
From: Fabiano Rosas @ 2026-10-27 12:30 UTC (permalink / raw)
To: Peter Maydell, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini
Peter Maydell <peter.maydell@linaro.org> writes:
> Currently we use a fixed irq_level[] array of 256 elements in
> QTestState to implement capturing the IRQ level reported by the QEMU
> under test so we can return it in qtest_get_irq(). This is smaller
> than is actually used by some devices, and if a test tries to
> intercept more IRQs than this and one is reported to libqtest then
> we'll fail an assertion in qtest_rsp_args().
>
> Switch to a GArray, which automatically resizes as required.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> tests/qtest/libqtest.c | 28 ++++++++++++++--------------
> 1 file changed, 14 insertions(+), 14 deletions(-)
>
> diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
> index 9e7a2d43a18..22b0dc193c9 100644
> --- a/tests/qtest/libqtest.c
> +++ b/tests/qtest/libqtest.c
> @@ -42,8 +42,6 @@
> #include "qobject/qstring.h"
> #include "qobject/qbool.h"
>
> -#define MAX_IRQ 256
> -
> #define ACCEPT_TIMEOUT_MS 250
> #define ACCEPT_RETRIES (4 * 50)
>
> @@ -88,7 +86,7 @@ struct QTestState
> #endif
> int expected_status;
> bool big_endian;
> - bool irq_level[MAX_IRQ];
> + GArray *irq_level;
> GString *rx;
> QTestTransportOps ops;
> GList *pending_events;
> @@ -501,7 +499,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
> void *opaque)
> {
> QTestState *s;
> - int sock, qmpsock, i;
> + int sock, qmpsock;
> g_autofree gchar *socket_path = qtest_socket_path("sock");
> g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp");
> g_autofree gchar *args = qtest_qemu_args(extra_args);
> @@ -525,9 +523,7 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
> qtest_client_set_tx_handler(s, qtest_client_socket_send);
>
> s->rx = g_string_new("");
> - for (i = 0; i < MAX_IRQ; i++) {
> - s->irq_level[i] = false;
> - }
> + s->irq_level = g_array_new(false, true, sizeof(bool));
>
> s->fd = -1;
> s->qmp_fd = -1;
> @@ -693,6 +689,7 @@ void qtest_quit(QTestState *s)
> close(s->fd);
> close(s->qmp_fd);
> g_string_free(s->rx, true);
> + g_array_unref(s->irq_level);
>
> for (GList *it = s->pending_events; it != NULL; it = it->next) {
> qobject_unref((QDict *)it->data);
> @@ -778,12 +775,14 @@ redo:
> ret = qemu_strtol(words[2], NULL, 0, &irq);
> g_assert(!ret);
> g_assert_cmpint(irq, >=, 0);
> - g_assert_cmpint(irq, <, MAX_IRQ);
>
> + if (s->irq_level->len <= irq) {
> + g_array_set_size(s->irq_level, irq + 1);
> + }
> if (strcmp(words[1], "raise") == 0) {
> - s->irq_level[irq] = true;
> + g_array_index(s->irq_level, bool, irq) = true;
> } else {
> - s->irq_level[irq] = false;
> + g_array_index(s->irq_level, bool, irq) = false;
> }
>
> g_strfreev(words);
> @@ -1192,7 +1191,10 @@ bool qtest_get_irq(QTestState *s, int num)
> /* dummy operation in order to make sure irq is up to date */
> qtest_inb(s, 0);
>
> - return s->irq_level[num];
> + if (s->irq_level->len <= num) {
> + return false;
> + }
> + return g_array_index(s->irq_level, bool, num);
> }
>
> void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
> @@ -2100,9 +2102,7 @@ QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
> qts->pending_events = NULL;
> *s = qts; /* Expose qts early on, since the query endianness relies on it */
> qts->wstatus = 0;
> - for (int i = 0; i < MAX_IRQ; i++) {
> - qts->irq_level[i] = false;
> - }
> + qts->irq_level = g_array_new(false, true, sizeof(bool));
>
> qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line);
Reviewed-by: Fabiano Rosas <farosas@suse.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts
2026-10-26 12:56 [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Peter Maydell
` (2 preceding siblings ...)
2026-10-26 12:56 ` [PATCH 3/3] tests/qtest/libqtest: Use a GArray for QTestState::irq_level[] Peter Maydell
@ 2026-10-27 12:30 ` Fabiano Rosas
3 siblings, 0 replies; 8+ messages in thread
From: Fabiano Rosas @ 2026-10-27 12:30 UTC (permalink / raw)
To: Peter Maydell, qemu-devel; +Cc: Laurent Vivier, Paolo Bonzini
Peter Maydell <peter.maydell@linaro.org> writes:
> Currently both system/qtest.c and libqtest have a 256 IRQ limit
> on the size of an irq_intercept_in. If you try it with more then
> qtest.c will overrun its array, and libqtest will trip an assert.
> We have some real devices in board models that use more inbound
> IRQs than this (e.g. the GIC in the Arm virt board).
>
> This series removes both the fixed-sized arrays, so there's
> no artificial limit on how many GPIO lines we can cope with.
> I also fix in patch 2 a bug I noticed while doing this, where
> we don't check the GPIO group name for irq_intercept_in, so
> we apply the intercept to every input GPIO group the device
> has rather than only to the unnamed GPIO inputs.
>
> I haven't bothered to cc:stable on these because we don't
> trip over the limit for any of our existing qtests, though
> I don't anticipate there being any issues with the backport.
>
> thanks
> -- PMM
>
> Peter Maydell (3):
> system/qtest: Avoid fixed-size irq_levels array for IRQ intercept
> system/qtest: Check ngl->name for irq_intercept_in
> tests/qtest/libqtest: Use a GArray for QTestState::irq_level[]
>
> system/qtest.c | 47 +++++++++++++++++++++++++++++-------------
> tests/qtest/libqtest.c | 28 ++++++++++++-------------
> 2 files changed, 47 insertions(+), 28 deletions(-)
Queued, thanks.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-27 12:30 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-26 12:56 [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Peter Maydell
2026-10-26 12:56 ` [PATCH 1/3] system/qtest: Avoid fixed-size irq_levels array for IRQ intercept Peter Maydell
2026-10-27 12:21 ` Fabiano Rosas
2026-10-26 12:56 ` [PATCH 2/3] system/qtest: Check ngl->name for irq_intercept_in Peter Maydell
2026-10-27 12:24 ` Fabiano Rosas
2026-10-26 12:56 ` [PATCH 3/3] tests/qtest/libqtest: Use a GArray for QTestState::irq_level[] Peter Maydell
2026-10-27 12:30 ` Fabiano Rosas
2026-10-27 12:30 ` [PATCH 0/3] qtest: Remove 256 IRQ limit on irq intercepts Fabiano Rosas
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.