* [PULL 01/23] docs: Document TIMEOUT_MULTIPLIER for raising test timeouts
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 02/23] hw/arm: Build ARM/HVF GICv3 stub once Peter Maydell
` (22 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
Our test infrastructure allows you to set the TIMEOUT_MULTIPLIER
environment variable to raise the test timeouts if you're building
for a slow environment. (scripts/mtest2make.py reads it and sets the
meson test -t argument accordingly.)
Document this so it's not a secret feature only known to a select
few.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-id: 20260427161132.1463385-1-peter.maydell@linaro.org
---
docs/devel/testing/main.rst | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/docs/devel/testing/main.rst b/docs/devel/testing/main.rst
index 0662766b5c..b01a374865 100644
--- a/docs/devel/testing/main.rst
+++ b/docs/devel/testing/main.rst
@@ -52,6 +52,21 @@ Before running tests, it is best to build QEMU programs first. Some tests
expect the executables to exist and will fail with obscure messages if they
cannot find them.
+The timeouts for QEMU tests are set conservatively so you should not
+in general find that tests time out. However, if you are running on a
+particularly slow host or with a slow configuration (such as a build
+with the clang address-sanitizer enabled) you can globally raise all
+the timeouts, by setting the ``TIMEOUT_MULTIPLIER`` environment
+variable. For instance:
+
+.. code::
+
+ TIMEOUT_MULTIPLIER=3 make check
+
+will run with all the default timeouts multiplied by three. You can
+also disable timeouts entirely by setting the environment variable to
+``0``.
+
.. _unit-tests:
Unit tests
@@ -959,6 +974,9 @@ Python. You can run the functional tests simply by executing:
See :ref:`checkfunctional-ref` for more details.
+The harness for the functional tests also honours the
+``TIMEOUT_MULTIPLIER`` environment variable.
+
.. _checktcg-ref:
Testing with "make check-tcg"
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 02/23] hw/arm: Build ARM/HVF GICv3 stub once
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
2026-05-15 10:49 ` [PULL 01/23] docs: Document TIMEOUT_MULTIPLIER for raising test timeouts Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 03/23] hw/arm: fsl-imx8mm: Don't call qdev_get_machine in init Peter Maydell
` (21 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
From: Philippe Mathieu-Daudé <philmd@linaro.org>
Move arm_gicv3_hvf_stub.c, introduced in commit 48396ad6ce9
("hw/intc: arm_gicv3_hvf: save/restore Apple GIC state"), to
the global stub_ss[] source set which holds stub files being
built once for all binaries, instead of one time per system
binary. This prevents symbol clash when trying to build a
single QEMU system binary:
clang: error: linker command failed with exit code 1 (use -v to see invocation)
duplicate symbol '_vmstate_gicv3_hvf' in:
libqemu-aarch64-softmmu.a.p/hw_intc_arm_gicv3_hvf_stub.c.o
libqemu-arm-softmmu.a.p/hw_intc_arm_gicv3_hvf_stub.c.o
ld: 1 duplicate symbols
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Message-id: 20260507135816.71171-1-philmd@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/intc/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index d7db99ce35..fac2d228f9 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -47,7 +47,7 @@ arm_common_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files('arm_gicv3_cpuif.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
specific_ss.add(when: ['CONFIG_WHPX', 'TARGET_AARCH64'], if_true: files('arm_gicv3_whpx.c'))
specific_ss.add(when: ['CONFIG_HVF', 'CONFIG_ARM_GICV3'], if_true: files('arm_gicv3_hvf.c'))
-specific_ss.add(when: ['CONFIG_HVF', 'CONFIG_ARM_GICV3'], if_false: files('arm_gicv3_hvf_stub.c'))
+stub_ss.add(files('arm_gicv3_hvf_stub.c'))
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c'))
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 03/23] hw/arm: fsl-imx8mm: Don't call qdev_get_machine in init
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
2026-05-15 10:49 ` [PULL 01/23] docs: Document TIMEOUT_MULTIPLIER for raising test timeouts Peter Maydell
2026-05-15 10:49 ` [PULL 02/23] hw/arm: Build ARM/HVF GICv3 stub once Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 04/23] target/arm: Rename Aarch64-specific methods Peter Maydell
` (20 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
From: Vineet Agarwal <agarwal.vineet2006@gmail.com>
Calling qdev_get_machine() from fsl_imx8mm_init() can trigger
an assertion failure because the machine may not be created yet.
Reproducer:
./qemu-system-aarch64 -S -display none \
-M virt -device fsl-imx8mm,help
This hits:
../hw/core/qdev.c:844: Object *qdev_get_machine(void):
Assertion `dev' failed.
Move the CPU initialization into realize(), where accessing the
machine state is safe.
(This is the same issue we fixed in the fsl-imx8mp machine
in commit b67d0bcdd41c; we apply the same fix here.)
Signed-off-by: Vineet Agarwal <agarwal.vineet2006@gmail.com>
Message-id: 20260511115918.32765-1-agarwal.vineet2006@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/fsl-imx8mm.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c
index 97c3f8542c..875e92bb34 100644
--- a/hw/arm/fsl-imx8mm.c
+++ b/hw/arm/fsl-imx8mm.c
@@ -157,16 +157,9 @@ static const struct {
static void fsl_imx8mm_init(Object *obj)
{
- MachineState *ms = MACHINE(qdev_get_machine());
FslImx8mmState *s = FSL_IMX8MM(obj);
- const char *cpu_type = ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53");
int i;
- for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MM_NUM_CPUS); i++) {
- g_autofree char *name = g_strdup_printf("cpu%d", i);
- object_initialize_child(obj, name, &s->cpu[i], cpu_type);
- }
-
object_initialize_child(obj, "gic", &s->gic, gicv3_class_name());
object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM);
@@ -229,6 +222,8 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
MachineState *ms = MACHINE(qdev_get_machine());
FslImx8mmState *s = FSL_IMX8MM(dev);
DeviceState *gicdev = DEVICE(&s->gic);
+ const char *cpu_type =
+ ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53");
int i;
if (ms->smp.cpus > FSL_IMX8MM_NUM_CPUS) {
@@ -237,6 +232,12 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
return;
}
+ for (i = 0; i < ms->smp.cpus; i++) {
+ g_autofree char *name = g_strdup_printf("cpu%d", i);
+ object_initialize_child(OBJECT(dev), name,
+ &s->cpu[i], cpu_type);
+ }
+
/* CPUs */
for (i = 0; i < ms->smp.cpus; i++) {
/* On uniprocessor, the CBAR is set to 0 */
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 04/23] target/arm: Rename Aarch64-specific methods
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (2 preceding siblings ...)
2026-05-15 10:49 ` [PULL 03/23] hw/arm: fsl-imx8mm: Don't call qdev_get_machine in init Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 05/23] target/arm: Extract IDAU interface to its own unit Peter Maydell
` (19 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
From: Philippe Mathieu-Daudé <philmd@linaro.org>
Various Aarch64 specific methods start with the 'aarch64_'
prefix. Rename few more emphasizing Aarch64 specific features.
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-id: 20260507134709.70507-2-philmd@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/arm/cpu.c | 8 ++++----
target/arm/cpu32-stubs.c | 8 ++++----
target/arm/cpu64.c | 12 ++++++------
target/arm/internals.h | 8 ++++----
4 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 31e0a12a98..1462e1f501 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1707,25 +1707,25 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
Error *local_err = NULL;
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
- arm_cpu_sve_finalize(cpu, &local_err);
+ aarch64_cpu_sve_finalize(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
- arm_cpu_sme_finalize(cpu, &local_err);
+ aarch64_cpu_sme_finalize(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
- arm_cpu_pauth_finalize(cpu, &local_err);
+ aarch64_cpu_pauth_finalize(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
- arm_cpu_lpa2_finalize(cpu, &local_err);
+ aarch64_cpu_lpa2_finalize(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
diff --git a/target/arm/cpu32-stubs.c b/target/arm/cpu32-stubs.c
index 9e50bb1b0b..d42b1a5d6a 100644
--- a/target/arm/cpu32-stubs.c
+++ b/target/arm/cpu32-stubs.c
@@ -4,22 +4,22 @@
#include "target/arm/cpu.h"
#include "target/arm/internals.h"
-void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_sme_finalize(ARMCPU *cpu, Error **errp)
{
g_assert_not_reached();
}
-void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
{
g_assert_not_reached();
}
-void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
{
g_assert_not_reached();
}
-void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
{
g_assert_not_reached();
}
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a93ad2da5a..b38a78aac3 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -60,7 +60,7 @@ int get_sysreg_idx(ARMSysRegs sysreg)
#undef DEF
-void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
{
/*
* If any vector lengths are explicitly enabled with sve<N> properties,
@@ -121,7 +121,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
* Disable all SVE extensions as well. Note that some ZFR0
* fields are used also by SME so must not be wiped in
* an SME-no-SVE config. We will clear the rest in
- * arm_cpu_sme_finalize() if necessary.
+ * aarch_cpu_sme_finalize() if necessary.
*/
FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, F64MM, 0);
FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, F32MM, 0);
@@ -336,7 +336,7 @@ static void cpu_arm_set_sve(Object *obj, bool value, Error **errp)
FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR0, SVE, value);
}
-void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_sme_finalize(ARMCPU *cpu, Error **errp)
{
uint32_t vq_map = cpu->sme_vq.map;
uint32_t vq_init = cpu->sme_vq.init;
@@ -408,7 +408,7 @@ static void cpu_arm_set_sme(Object *obj, bool value, Error **errp)
/*
* For now, write 0 for "off" and 1 for "on" into the PFR1 field.
* We will correct this value to report the right SME
- * level (SME vs SME2) in arm_cpu_sme_finalize() later.
+ * level (SME vs SME2) in aarch_cpu_sme_finalize() later.
*/
FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR1, SME, value);
}
@@ -548,7 +548,7 @@ void aarch64_add_sme_properties(Object *obj)
#endif
}
-void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
{
ARMPauthFeature features = cpu_isar_feature(pauth_feature, cpu);
ARMISARegisters *isar = &cpu->isar;
@@ -666,7 +666,7 @@ void aarch64_add_pauth_properties(Object *obj)
}
}
-void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
+void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
{
uint64_t t;
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 3edc15c7b4..00830b1724 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1750,10 +1750,10 @@ int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg);
int aarch64_gdb_set_tag_ctl_reg(CPUState *cs, uint8_t *buf, int reg);
int aarch64_gdb_get_tls_reg(CPUState *cs, GByteArray *buf, int reg);
int aarch64_gdb_set_tls_reg(CPUState *cs, uint8_t *buf, int reg);
-void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
-void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp);
-void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
-void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp);
+void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
+void aarch64_cpu_sme_finalize(ARMCPU *cpu, Error **errp);
+void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
+void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp);
void aarch64_max_tcg_initfn(Object *obj);
void aarch64_add_pauth_properties(Object *obj);
void aarch64_add_sve_properties(Object *obj);
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 05/23] target/arm: Extract IDAU interface to its own unit
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (3 preceding siblings ...)
2026-05-15 10:49 ` [PULL 04/23] target/arm: Rename Aarch64-specific methods Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 06/23] target/arm/hvf: Stop pre-allocating cpreg_vmstate arrays Peter Maydell
` (18 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
From: Philippe Mathieu-Daudé <philmd@linaro.org>
Move IDAU TypeInfo structure to its own source file and
build it once as common ARM object.
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-id: 20260507134709.70507-3-philmd@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/armv7m.c | 2 +-
include/hw/arm/armv7m.h | 2 +-
include/hw/misc/tz-msc.h | 2 +-
target/arm/cpu.c | 2 +-
target/arm/ptw.c | 2 +-
target/arm/tcg/cpu32.c | 8 --------
target/arm/tcg/idau.c | 20 ++++++++++++++++++++
target/arm/{ => tcg}/idau.h | 0
target/arm/tcg/meson.build | 1 +
9 files changed, 26 insertions(+), 13 deletions(-)
create mode 100644 target/arm/tcg/idau.c
rename target/arm/{ => tcg}/idau.h (100%)
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index a29eab6c91..68a1cbd631 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -20,7 +20,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/log.h"
-#include "target/arm/idau.h"
+#include "target/arm/tcg/idau.h"
#include "target/arm/cpu.h"
#include "target/arm/cpu-features.h"
#include "target/arm/cpu-qom.h"
diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h
index 98ad08db03..70555962bb 100644
--- a/include/hw/arm/armv7m.h
+++ b/include/hw/arm/armv7m.h
@@ -13,7 +13,7 @@
#include "hw/core/sysbus.h"
#include "hw/intc/armv7m_nvic.h"
#include "hw/misc/armv7m_ras.h"
-#include "target/arm/idau.h"
+#include "target/arm/tcg/idau.h"
#include "qom/object.h"
#include "hw/core/clock.h"
diff --git a/include/hw/misc/tz-msc.h b/include/hw/misc/tz-msc.h
index 07112d8caa..6cf4c6b09e 100644
--- a/include/hw/misc/tz-msc.h
+++ b/include/hw/misc/tz-msc.h
@@ -51,7 +51,7 @@
#define TZ_MSC_H
#include "hw/core/sysbus.h"
-#include "target/arm/idau.h"
+#include "target/arm/tcg/idau.h"
#include "qom/object.h"
#define TYPE_TZ_MSC "tz-msc"
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 1462e1f501..c47b70ac69 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -24,7 +24,7 @@
#include "qemu/log.h"
#include "exec/page-vary.h"
#include "system/whpx.h"
-#include "target/arm/idau.h"
+#include "target/arm/tcg/idau.h"
#include "qemu/module.h"
#include "qapi/error.h"
#include "cpu.h"
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 8706dd59dd..a4842a4b62 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -17,7 +17,7 @@
#include "cpu.h"
#include "internals.h"
#include "cpu-features.h"
-#include "idau.h"
+#include "target/arm/tcg/idau.h"
typedef struct S1Translate {
/*
diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c
index 2127d456ad..73d21c6cf7 100644
--- a/target/arm/tcg/cpu32.c
+++ b/target/arm/tcg/cpu32.c
@@ -12,7 +12,6 @@
#include "cpu.h"
#include "accel/tcg/cpu-ops.h"
#include "internals.h"
-#include "target/arm/idau.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/core/boards.h"
#endif
@@ -899,17 +898,10 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
#endif
};
-static const TypeInfo idau_interface_type_info = {
- .name = TYPE_IDAU_INTERFACE,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(IDAUInterfaceClass),
-};
-
static void arm_tcg_cpu_register_types(void)
{
size_t i;
- type_register_static(&idau_interface_type_info);
for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) {
arm_cpu_register(&arm_tcg_cpus[i]);
}
diff --git a/target/arm/tcg/idau.c b/target/arm/tcg/idau.c
new file mode 100644
index 0000000000..57e5c658e9
--- /dev/null
+++ b/target/arm/tcg/idau.c
@@ -0,0 +1,20 @@
+/*
+ * QEMU ARM CPU -- interface for the Arm v8M IDAU
+ *
+ * Copyright (c) 2018 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "target/arm/tcg/idau.h"
+
+static const TypeInfo idau_types[] = {
+ {
+ .name = TYPE_IDAU_INTERFACE,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(IDAUInterfaceClass),
+ }
+};
+
+DEFINE_TYPES(idau_types)
diff --git a/target/arm/idau.h b/target/arm/tcg/idau.h
similarity index 100%
rename from target/arm/idau.h
rename to target/arm/tcg/idau.h
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
index 4fb2c15f7e..1b751d5918 100644
--- a/target/arm/tcg/meson.build
+++ b/target/arm/tcg/meson.build
@@ -56,6 +56,7 @@ arm_common_ss.add(zlib)
arm_common_ss.add(files(
'arith_helper.c',
'crypto_helper.c',
+ 'idau.c',
))
arm_common_system_ss.add(
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 06/23] target/arm/hvf: Stop pre-allocating cpreg_vmstate arrays
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (4 preceding siblings ...)
2026-05-15 10:49 ` [PULL 05/23] target/arm: Extract IDAU interface to its own unit Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 07/23] target/arm: GICv5 cpuif: Fix overflow in left shift Peter Maydell
` (17 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
From: "Scott J. Goldman" <scottjgo@gmail.com>
Commit ab2ddc7b66 ("target/arm/machine: Use VMSTATE_VARRAY_INT32_ALLOC
for cpreg arrays") moved cpreg_vmstate_indexes / cpreg_vmstate_values
to be allocated by VMSTATE_VARRAY_INT32_ALLOC and added an assertion
in cpu_pre_load() that they are NULL on entry. The same commit dropped
the redundant g_renew()/array_len assignments from the kvm, whpx and
helper.c cpu init paths, but the hvf cpu init path still pre-allocates
them.
The result is that loading a snapshot or migration stream into an HVF
guest immediately aborts:
ERROR:target/arm/machine.c:1043:cpu_pre_load:
assertion failed: (!cpu->cpreg_vmstate_indexes)
Drop the leftover cpreg_vmstate_indexes / cpreg_vmstate_values
allocations and the cpreg_vmstate_array_len assignment from
hvf_arch_init_vcpu(), matching what was already done for the other
arm accelerators.
Signed-off-by: Scott J. Goldman <scottjgo@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/arm/hvf/hvf.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 5a1718f7f9..9312607001 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1412,12 +1412,6 @@ int hvf_arch_init_vcpu(CPUState *cpu)
sregs_match_len);
arm_cpu->cpreg_values = g_renew(uint64_t, arm_cpu->cpreg_values,
sregs_match_len);
- arm_cpu->cpreg_vmstate_indexes = g_renew(uint64_t,
- arm_cpu->cpreg_vmstate_indexes,
- sregs_match_len);
- arm_cpu->cpreg_vmstate_values = g_renew(uint64_t,
- arm_cpu->cpreg_vmstate_values,
- sregs_match_len);
memset(arm_cpu->cpreg_values, 0, sregs_match_len * sizeof(uint64_t));
@@ -1462,7 +1456,6 @@ int hvf_arch_init_vcpu(CPUState *cpu)
}
}
arm_cpu->cpreg_array_len = sregs_cnt;
- arm_cpu->cpreg_vmstate_array_len = sregs_cnt;
/* cpreg tuples must be in strictly ascending order */
qsort(arm_cpu->cpreg_indexes, sregs_cnt, sizeof(uint64_t), compare_u64);
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 07/23] target/arm: GICv5 cpuif: Fix overflow in left shift
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (5 preceding siblings ...)
2026-05-15 10:49 ` [PULL 06/23] target/arm/hvf: Stop pre-allocating cpreg_vmstate arrays Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 08/23] target/arm: GICv5 cpuif: Don't set HPPIV bit in GICv5PendingIrq::intid Peter Maydell
` (16 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
Coverity points out that we forgot the "ULL" suffix when shifting 1
right by a bitcount in various places, so for bit counts above 31 we
end up shifting off the end of the word. Fix the three problems
Coverity noticed and one more of the same kind that it didn't.
CID: 1659588, 1659591, 1659559
Fixes: ce245ac6957 ("target/arm: GICv5 cpuif: Calculate the highest priority PPI")
Fixes: 3f79212abae ("target/arm: GICv5 cpuif: Implement GICR CDIA command")
Fixes: 49f4c98648c ("target/arm: GICv5 cpuif: Implement GIC CDDI")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260512093856.3197700-2-peter.maydell@linaro.org
---
target/arm/tcg/gicv5-cpuif.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index bc44a7fc11..98238ada19 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -275,7 +275,7 @@ static void gic_recalc_ppi_hppi(CPUARMState *env)
int ppi;
int bit = ctz64(en_pend_nact);
- en_pend_nact &= ~(1 << bit);
+ en_pend_nact &= ~(1ULL << bit);
ppi = i * 64 + bit;
prio = extract64(env->gicv5_cpuif.ppi_priority[ppi / 8],
@@ -631,7 +631,7 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const ARMCPRegInfo *ri)
* gicv5_activate() cause a re-evaluation of HPPIs they use the
* right (new) running priority.
*/
- env->gicv5_cpuif.icc_apr[domain] |= (1 << hppi.prio);
+ env->gicv5_cpuif.icc_apr[domain] |= (1ULL << hppi.prio);
switch (type) {
case GICV5_PPI:
{
@@ -639,7 +639,7 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const ARMCPRegInfo *ri)
assert(id < GICV5_NUM_PPIS);
ppireg = id / 64;
- ppibit = 1 << (id % 64);
+ ppibit = 1ULL << (id % 64);
env->gicv5_cpuif.ppi_active[ppireg] |= ppibit;
if (!(env->gicv5_cpuif.ppi_hm[ppireg] & ppibit)) {
@@ -707,7 +707,7 @@ static void gic_cddi_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
ppireg = id / 64;
- ppibit = 1 << (id % 64);
+ ppibit = 1ULL << (id % 64);
env->gicv5_cpuif.ppi_active[ppireg] &= ~ppibit;
gic_recalc_ppi_hppi(env);
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 08/23] target/arm: GICv5 cpuif: Don't set HPPIV bit in GICv5PendingIrq::intid
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (6 preceding siblings ...)
2026-05-15 10:49 ` [PULL 07/23] target/arm: GICv5 cpuif: Fix overflow in left shift Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 09/23] hw/intc/arm_gicv5: Avoid NULL dereference in trace line Peter Maydell
` (15 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
In gic_hppi() we return the current highest priority pending
interrupt in a GICv5PendingIrq struct. We try to set up the intid
field of that struct to be the form that is used by the ICC_HPPIR
register, which has a "valid" bit in bit 33. Unfortunately the
GICv5PendingIrq defines the intid field as a uint32_t, so Coverity
points out that the bit doesn't actually fit. Move the handling of
the valid bit to the callsite, and make this function report "no
pending interrupt" with GICv5PendingIrq::prio == PRIO_IDLE,
consistently with how we use this struct in other places.
CID: 1659594
Fixes: 9edad4ff3 ("target/arm: GICv5 cpuif: Implement ICC_HPPIR_EL1")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260512093856.3197700-3-peter.maydell@linaro.org
---
include/hw/intc/arm_gicv5_types.h | 2 ++
target/arm/tcg/gicv5-cpuif.c | 18 ++++++++++--------
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/include/hw/intc/arm_gicv5_types.h b/include/hw/intc/arm_gicv5_types.h
index eaed42f49f..de4f78a149 100644
--- a/include/hw/intc/arm_gicv5_types.h
+++ b/include/hw/intc/arm_gicv5_types.h
@@ -97,6 +97,8 @@ typedef enum GICv5TriggerMode {
*
* In this struct the intid includes the interrupt type in bits
* [31:29] (i.e. it is in the form defined by R_TJPHS).
+ *
+ * "No pending interrupt" is represented by @prio == PRIO_IDLE.
*/
typedef struct GICv5PendingIrq {
uint32_t intid;
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index 98238ada19..dd2f696511 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -129,10 +129,9 @@ static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain)
{
/*
* Return the current highest priority pending interrupt for the
- * specified domain, if it has sufficient priority to preempt. The
- * intid field of the return value will be in the format of the
- * ICC_HPPIR register (and will be zero if and only if there is no
- * interrupt that can preempt).
+ * specified domain, if it has sufficient priority to preempt.
+ * If there is no interrupt that can preempt we signal this by
+ * returning a struct with prio == PRIO_IDLE.
*/
GICv5Common *gic = gicv5_get_gic(env);
@@ -166,7 +165,6 @@ static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain)
best.prio >= gic_running_prio(env, domain)) {
return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE };
}
- best.intid |= R_ICC_HPPIR_EL1_HPPIV_MASK;
return best;
}
@@ -575,7 +573,12 @@ static uint64_t gic_icc_hppir_el1_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv5Domain domain = gicv5_logical_domain(env);
GICv5PendingIrq hppi = gic_hppi(env, domain);
- return hppi.intid;
+
+ if (hppi.prio == PRIO_IDLE) {
+ /* No valid interrupt */
+ return 0;
+ }
+ return hppi.intid | R_ICC_HPPIR_EL1_HPPIV_MASK;
}
static bool gic_hppi_is_nmi(CPUARMState *env, GICv5PendingIrq hppi,
@@ -602,13 +605,12 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const ARMCPRegInfo *ri)
bool cdnmia = ri->opc2 == 1;
- if (!hppi.intid) {
+ if (hppi.prio == PRIO_IDLE) {
/* No interrupt available to acknowledge */
trace_gicv5_gicr_cdia_fail(domain,
"no available interrupt to acknowledge");
return 0;
}
- assert(hppi.prio != PRIO_IDLE);
if (gic_hppi_is_nmi(env, hppi, domain) != cdnmia) {
/* GICR CDIA only acknowledges non-NMI; GICR CDNMIA only NMI */
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 09/23] hw/intc/arm_gicv5: Avoid NULL dereference in trace line
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (7 preceding siblings ...)
2026-05-15 10:49 ` [PULL 08/23] target/arm: GICv5 cpuif: Don't set HPPIV bit in GICv5PendingIrq::intid Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 10/23] hw/intc/arm_gicv5: Add missing early return in gicv5_set_handling() Peter Maydell
` (14 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
In the handling of writes to the IRS_SPI_RESAMPLER register,
we call a trace function, passing it information about the SPI
being resampled. However, spi could be NULL if the guest tried
to resample a nonexistent SPI or one configured for a different
domain. Move the trace statement inside the "if (spi)" block,
as it's only interesting trace if we actually did a resample
and potentially changed the state of the SPI.
CID: 1959593
Fixes: 33185e1d64e ("hw/intc/arm_gicv5: Update SPI state for CLEAR/SET events")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260512093856.3197700-4-peter.maydell@linaro.org
---
hw/intc/arm_gicv5.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 493d664625..7ad274e369 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -1643,8 +1643,8 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
if (spi) {
spi_sample(spi);
irs_recalc_hppi(s, spi->domain, spi->iaffid);
+ trace_gicv5_spi_state(id, spi->level, spi->pending, spi->active);
}
- trace_gicv5_spi_state(id, spi->level, spi->pending, spi->active);
return true;
}
case A_IRS_CR0:
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 10/23] hw/intc/arm_gicv5: Add missing early return in gicv5_set_handling()
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (8 preceding siblings ...)
2026-05-15 10:49 ` [PULL 09/23] hw/intc/arm_gicv5: Avoid NULL dereference in trace line Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 11/23] meson.build: Add -fzero-init-padding-bits=all Peter Maydell
` (13 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
In gicv5_set_handling(), if the guest tried to set the handling mode
on a nonexistent SPI then we print a GUEST_ERROR log message.
However, we forgot to then return, so execution continues into a NULL
pointer dereference.
Add the missing "return", bringing the code structure in to line with
the equivalent parts in other functions like gicv5_set_pending() and
gicv5_set_target().
CID: 1659596
Fixes: 5beb48ab53d ("hw/intc/arm_gicv5: Make gicv5_set_* update SPI state")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260512093856.3197700-5-peter.maydell@linaro.org
---
hw/intc/arm_gicv5.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 7ad274e369..6b1dd04991 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -926,6 +926,7 @@ void gicv5_set_handling(GICv5Common *cs, uint32_t id,
if (!spi) {
qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set "
"priority of unreachable SPI %d\n", id);
+ return;
}
spi->hm = handling;
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 11/23] meson.build: Add -fzero-init-padding-bits=all
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (9 preceding siblings ...)
2026-05-15 10:49 ` [PULL 10/23] hw/intc/arm_gicv5: Add missing early return in gicv5_set_handling() Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 12/23] hw/misc/bcm2835_control.c: Don't assert on local timer zero reload value Peter Maydell
` (12 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The C standard doesn't always guarantee that struct and union padding
bits are zero initialized, even if the code initializes a struct.
For QEMU, this is potentially problematic, because we often have
structs that match data structures in guest memory, where we
initialize them and then bulk copy them into the guest. If the
compiler didn't zero init the whole of the memory containing the
struct, we could potentially leak random data from the host into the
guest via the padding bytes.
We already use -ftrivial-auto-var-init=zero, which will zero out
padding in many of these cases, but -fzero-init-padding-bits=all
closes some gaps, for example cases where we initialize a
variable with a struct initializer, and cases involving unions.
Follow the Linux kernel in using both options. Compare kernel
commit dce4aab8441 ("kbuild: Use -fzero-init-padding-bits=all").
This option exists in gcc-15 and above; it's not supported
by clang, but clang documents that it guarantees zero init
of these cases always:
https://clang.llvm.org/docs/LanguageExtensions.html#union-and-aggregate-initialization-in-c
Older gcc which don't have the option behave as if it were set.
(These options are passed through the cc.get_supported_arguments()
filter, so we don't need to do anything extra to avoid passing it to
a compiler that doesn't recognize it.)
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-id: 20260508104723.2144051-1-peter.maydell@linaro.org
---
meson.build | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/meson.build b/meson.build
index 90c149b10d..37060c030e 100644
--- a/meson.build
+++ b/meson.build
@@ -684,6 +684,12 @@ hardening_flags = [
# it harder to take advantage of uninitialized stack
# data to drive exploits
'-ftrivial-auto-var-init=zero',
+ # Ensure GCC zero-initializes padding bits and trailing fields in
+ # unions. This avoids potentially leaking host data into the guest
+ # when we init a struct and copy it into guest memory. GCC prior
+ # to GCC 15 and clang don't have this, but they zero the padding
+ # and trailing portions of a union by default.
+ '-fzero-init-padding-bits=all',
]
# Zero out registers used during a function call
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 12/23] hw/misc/bcm2835_control.c: Don't assert on local timer zero reload value
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (10 preceding siblings ...)
2026-05-15 10:49 ` [PULL 11/23] meson.build: Add -fzero-init-padding-bits=all Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 13/23] hw/arm/integratorcp: Use LOG_UNIMP rather than hw_error() Peter Maydell
` (11 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The bcm2836 local timer has a basic "counts down, fires at zero,
and reloads to programmed value to count down again" functionality,
as documented in
https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
The documentation is very sparse and doesn't say what actually
happens if the guest programs the reload value to zero. Currently we
trip an assert in this case.
Instead, log this as a guest error and disable the timer (which seems
a reasonable guess -- effectively the timer will stop counting).
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3395
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260508162013.2751001-2-peter.maydell@linaro.org
---
hw/intc/bcm2836_control.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
index f1deafaf7a..d6c6057cd2 100644
--- a/hw/intc/bcm2836_control.c
+++ b/hw/intc/bcm2836_control.c
@@ -197,12 +197,21 @@ static void bcm2836_control_local_timer_set_next(void *opaque)
{
BCM2836ControlState *s = opaque;
uint64_t next_event;
+ uint64_t reload_value = LOCALTIMER_VALUE(s->local_timer_control);
- assert(LOCALTIMER_VALUE(s->local_timer_control) > 0);
+ if (reload_value == 0) {
+ /*
+ * Spec doesn't say what happens in this case; treat as a
+ * guest error and stop the timer running.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: local timer reload value is 0\n",
+ __func__);
+ timer_del(&s->timer);
+ return;
+ }
next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(LOCALTIMER_VALUE(s->local_timer_control),
- NANOSECONDS_PER_SECOND, LOCALTIMER_FREQ);
+ muldiv64(reload_value, NANOSECONDS_PER_SECOND, LOCALTIMER_FREQ);
timer_mod(&s->timer, next_event);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 13/23] hw/arm/integratorcp: Use LOG_UNIMP rather than hw_error()
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (11 preceding siblings ...)
2026-05-15 10:49 ` [PULL 12/23] hw/misc/bcm2835_control.c: Don't assert on local timer zero reload value Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 14/23] hw/display/exynos4210_fimd: Use LOG_GUEST_ERROR instead of hw_error() Peter Maydell
` (10 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The integratorcp board has some onboard registers which can be used
to raise IRQ and FIQ to the CPU; these outputs are supposed to be
ORed together with the main ones from the PIC. We've never
implemented this obscure bit of functionality, and instead call
hw_error() if the guest does try to raise an interrupt this way.
Replace the hw_error() call with the more modern way to note
unimplemented QEMU behaviour, a LOG_UNIMP log.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3406
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260508162013.2751001-3-peter.maydell@linaro.org
---
hw/arm/integratorcp.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 164af03f7b..c25bbf3c82 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -23,7 +23,6 @@
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/char/pl011.h"
-#include "hw/core/hw-error.h"
#include "hw/core/irq.h"
#include "hw/sd/sd.h"
#include "qom/object.h"
@@ -178,10 +177,17 @@ static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
static void integratorcm_update(IntegratorCMState *s)
{
- /* ??? The CPU irq/fiq is raised when either the core module or base PIC
- are active. */
- if (s->int_level & (s->irq_enabled | s->fiq_enabled))
- hw_error("Core module interrupt\n");
+ /*
+ * ??? The CPU irq/fiq is raised when either the core module or base PIC
+ * are active. To implement this we would need to run these signals
+ * through an OR gate with the PIC outputs. In practice guests don't
+ * use this, which is intended for an external debugger.
+ */
+ if (s->int_level & (s->irq_enabled | s->fiq_enabled)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: raising IRQ/FIQ via core module registers is not implemented\n",
+ __func__);
+ }
}
static void integratorcm_write(void *opaque, hwaddr offset,
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 14/23] hw/display/exynos4210_fimd: Use LOG_GUEST_ERROR instead of hw_error()
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (12 preceding siblings ...)
2026-05-15 10:49 ` [PULL 13/23] hw/arm/integratorcp: Use LOG_UNIMP rather than hw_error() Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 15/23] hw/display/exynos4210_fimd: Assume display surface is 32bpp Peter Maydell
` (9 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The exynos4210_fimd device model uses hw_error() in several places
for "the guest set this register field to something out of range";
update to the more modern LOG_GUEST_ERROR.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3405
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260508162013.2751001-4-peter.maydell@linaro.org
---
hw/display/exynos4210_fimd.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 5133623ee2..aa94b29971 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -533,7 +533,8 @@ exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
break;
default:
- hw_error("exynos4210.fimd: incorrect window number %d\n", window);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.fimd: incorrect window number %d\n", window);
ret = 0;
break;
}
@@ -757,7 +758,9 @@ exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
break;
default:
- hw_error("exynos4210.fimd: blend equation coef illegal value\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.fimd: blend equation coef illegal value\n");
+ blend_param[i] = 0;
break;
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 15/23] hw/display/exynos4210_fimd: Assume display surface is 32bpp
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (13 preceding siblings ...)
2026-05-15 10:49 ` [PULL 14/23] hw/display/exynos4210_fimd: Use LOG_GUEST_ERROR instead of hw_error() Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 16/23] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32 Peter Maydell
` (8 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
For a long time QEMU has guaranteed that the console surface is 32bpp
and not anything else. This old display device still has code
assuming it might be something else. Remove the code that made
put_pixel_toqemu a function pointer indirection, and use
put_to_qemufb_pixel32() directly.
This removes the last hw_error() in this file.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260508162013.2751001-5-peter.maydell@linaro.org
---
hw/display/exynos4210_fimd.c | 62 ++----------------------------------
1 file changed, 2 insertions(+), 60 deletions(-)
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index aa94b29971..e715183ad5 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "hw/core/qdev-properties.h"
-#include "hw/core/hw-error.h"
#include "hw/core/irq.h"
#include "hw/core/sysbus.h"
#include "exec/cpu-common.h"
@@ -867,37 +866,6 @@ static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
}
/* Write RGB to QEMU's GraphicConsole framebuffer */
-
-static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
- *(uint8_t *)d = pixel;
- return 1;
-}
-
-static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
- *(uint16_t *)d = pixel;
- return 2;
-}
-
-static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
- *(uint16_t *)d = pixel;
- return 2;
-}
-
-static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
-{
- uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
- *(uint8_t *)d++ = (pixel >> 0) & 0xFF;
- *(uint8_t *)d++ = (pixel >> 8) & 0xFF;
- *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
- return 3;
-}
-
static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
{
uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
@@ -905,32 +873,6 @@ static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
return 4;
}
-/* Routine to copy pixel from internal buffer to QEMU buffer */
-static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
-static inline void fimd_update_putpix_qemu(int bpp)
-{
- switch (bpp) {
- case 8:
- put_pixel_toqemu = put_to_qemufb_pixel8;
- break;
- case 15:
- put_pixel_toqemu = put_to_qemufb_pixel15;
- break;
- case 16:
- put_pixel_toqemu = put_to_qemufb_pixel16;
- break;
- case 24:
- put_pixel_toqemu = put_to_qemufb_pixel24;
- break;
- case 32:
- put_pixel_toqemu = put_to_qemufb_pixel32;
- break;
- default:
- hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
- break;
- }
-}
-
/* Routine to copy a line from internal frame buffer to QEMU display */
static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
{
@@ -938,7 +880,7 @@ static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
do {
src += get_pixel_ifb(src, &p);
- dst += put_pixel_toqemu(p, dst);
+ dst += put_to_qemufb_pixel32(p, dst);
} while (--width);
}
@@ -1336,7 +1278,7 @@ static bool exynos4210_fimd_update(void *opaque)
int bpp;
bpp = surface_bits_per_pixel(surface);
- fimd_update_putpix_qemu(bpp);
+ assert(bpp == 32);
bpp = (bpp + 1) >> 3;
d = surface_data(surface);
for (line = first_line; line <= last_line; line++) {
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 16/23] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (14 preceding siblings ...)
2026-05-15 10:49 ` [PULL 15/23] hw/display/exynos4210_fimd: Assume display surface is 32bpp Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 17/23] tests/functional/test_virt_vbsa: Skip UEFI test if virtualization not supported Peter Maydell
` (7 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
When we updated Arm and AArch64 board types to mark them for the
target_machine_typename() filter, we forgot about the "x-remote"
machine type, which meant that it disappeared from the set of board
types exposed on the qemu-system-arm and qemu-system-aarch64
binaries. We didn't notice this, because although we have a
functional test for it, it requires the KVM accelerator and we don't
run the functional tests on an AArch64 host in CI.
Mark the machine as being OK to expose in qemu-system-arm and
qemu-system-aarch64, in the same way we do for the "none" machine
type. This fixes a check-functional failure on aarch64 host, where
it would otherwise fail with:
qemu-system-aarch64: unsupported machine type: "x-remote"
Cc: qemu-stable@nongnu.org
Fixes: eb796c55513d9d39 ("hw/core: Allow ARM/Aarch64 binaries to use the 'none' machine")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260507194728.2034696-2-peter.maydell@linaro.org
---
hw/remote/machine.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/remote/machine.c b/hw/remote/machine.c
index ced782f6a9..df08f64019 100644
--- a/hw/remote/machine.c
+++ b/hw/remote/machine.c
@@ -24,6 +24,7 @@
#include "hw/core/qdev.h"
#include "hw/remote/vfio-user-obj.h"
#include "hw/pci/msi.h"
+#include "hw/arm/machines-qom.h"
static void remote_machine_init(MachineState *machine)
{
@@ -148,6 +149,8 @@ static const TypeInfo remote_machine = {
.class_init = remote_machine_class_init,
.interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
+ { TYPE_TARGET_AARCH64_MACHINE },
+ { TYPE_TARGET_ARM_MACHINE },
{ }
}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 17/23] tests/functional/test_virt_vbsa: Skip UEFI test if virtualization not supported
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (15 preceding siblings ...)
2026-05-15 10:49 ` [PULL 16/23] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32 Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 18/23] tests/functional/test_kvm.py: Use -cpu max, not cortex-a72 Peter Maydell
` (6 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
If you try to run the functional tests on an AArch64 host which doesn't
support nested virtualization in KVM, the UEFI test fails with:
Output: qemu-system-aarch64: mach-virt: host kernel KVM does
not support providing Virtualization extensions to the guest CPU
Catch the VMLaunchFailure exception and if it matches the error
messages the virt board puts out for virtualization not being
supported, skip the test.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260507194728.2034696-3-peter.maydell@linaro.org
---
tests/functional/aarch64/test_virt_vbsa.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/tests/functional/aarch64/test_virt_vbsa.py b/tests/functional/aarch64/test_virt_vbsa.py
index 57bfe5d7af..04b5ff0f9e 100755
--- a/tests/functional/aarch64/test_virt_vbsa.py
+++ b/tests/functional/aarch64/test_virt_vbsa.py
@@ -17,6 +17,7 @@
from qemu_test import get_qemu_img, skipIfMissingCommands
from qemu_test import wait_for_console_pattern
from qemu_test import exec_command_and_wait_for_pattern as ec_and_wait
+from qemu.machine.machine import VMLaunchFailure
@skipIfMissingCommands("mformat", "mcopy", "mmd")
@@ -96,7 +97,14 @@ def test_aarch64_vbsa_uefi_tests(self):
f'file={img_path},format=raw,if=none,id=drive0')
self.vm.add_args('-device', 'virtio-blk-pci,drive=drive0')
- self.vm.launch()
+ try:
+ self.vm.launch()
+ except VMLaunchFailure as excp:
+ if "does not support providing Virtualization" in excp.output:
+ self.skipTest("accelerator has no virtualization support")
+ else:
+ self.log.info("unhandled launch failure: %s", excp.output)
+ raise excp
# wait for EFI prompt
self.wait_for_console_pattern('Shell>')
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 18/23] tests/functional/test_kvm.py: Use -cpu max, not cortex-a72
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (16 preceding siblings ...)
2026-05-15 10:49 ` [PULL 17/23] tests/functional/test_virt_vbsa: Skip UEFI test if virtualization not supported Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 19/23] tests/functional/test_kvm.py: Skip if virtualization not supported Peter Maydell
` (5 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The test_kvm test claims to run on any accelerator supporting
nested virtualization, but it specifies the cortex-a72 CPU.
This doesn't exist for KVM-only builds. Use max instead.
This fixes a failure like
Output: qemu-system-aarch64: unable to find CPU model 'cortex-a72'
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260507194728.2034696-4-peter.maydell@linaro.org
---
tests/functional/aarch64/test_kvm.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/functional/aarch64/test_kvm.py b/tests/functional/aarch64/test_kvm.py
index 7545f5ed55..fed18aba60 100755
--- a/tests/functional/aarch64/test_kvm.py
+++ b/tests/functional/aarch64/test_kvm.py
@@ -38,7 +38,7 @@ def _launch_guest(self, kvm_mode="nvhe"):
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
f"console=ttyAMA0 kvm-arm.mode={kvm_mode}")
- self.vm.add_args("-cpu", "cortex-a72")
+ self.vm.add_args("-cpu", "max")
self.vm.add_args("-machine", "virt,gic-version=3,virtualization=on",
'-kernel', kernel_path,
'-append', kernel_command_line)
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 19/23] tests/functional/test_kvm.py: Skip if virtualization not supported
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (17 preceding siblings ...)
2026-05-15 10:49 ` [PULL 18/23] tests/functional/test_kvm.py: Use -cpu max, not cortex-a72 Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 20/23] tests/functional/test_hotplug_pci.py: Require TCG Peter Maydell
` (4 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The test_kvm test runs the virt board with virtualization=on,
which will fail if run with an accelerator that doesn't
support nested virtualization. Catch the VMLaunchFailure
exception and skip the test if startup failed because
the accelerator can't support virtualization.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260507194728.2034696-5-peter.maydell@linaro.org
---
tests/functional/aarch64/test_kvm.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/tests/functional/aarch64/test_kvm.py b/tests/functional/aarch64/test_kvm.py
index fed18aba60..c977e8c6d2 100755
--- a/tests/functional/aarch64/test_kvm.py
+++ b/tests/functional/aarch64/test_kvm.py
@@ -14,6 +14,7 @@
from qemu_test import Asset
from qemu_test import exec_command_and_wait_for_pattern as ec_and_wait
from qemu_test.linuxkernel import LinuxKernelTest
+from qemu.machine.machine import VMLaunchFailure
class Aarch64VirtKVMTests(LinuxKernelTest):
@@ -44,7 +45,14 @@ def _launch_guest(self, kvm_mode="nvhe"):
'-append', kernel_command_line)
self.vm.add_args("-smp", "2", "-m", "320")
- self.vm.launch()
+ try:
+ self.vm.launch()
+ except VMLaunchFailure as excp:
+ if "does not support providing Virtualization" in excp.output:
+ self.skipTest("accelerator has no virtualization support")
+ else:
+ self.log.info("unhandled launch failure: %s", excp.output)
+ raise excp
self.wait_for_console_pattern('buildroot login:')
ec_and_wait(self, 'root', '#')
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 20/23] tests/functional/test_hotplug_pci.py: Require TCG
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (18 preceding siblings ...)
2026-05-15 10:49 ` [PULL 19/23] tests/functional/test_kvm.py: Skip if virtualization not supported Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 21/23] tests/functional/test_tuxrun: Restrict to TCG Peter Maydell
` (3 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The hotplug test asks for the cortex-a57 CPU type, so it will
fail on an AArch64 system using KVM where TCG is not compiled
into QEMU and the default accelerator is KVM:
Output: qemu-system-aarch64: kvm_init_vcpu: kvm_arch_init_vcpu failed (0): Invalid argument
Restrict it to the TCG accelerator.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260507194728.2034696-6-peter.maydell@linaro.org
---
tests/functional/aarch64/test_hotplug_pci.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/functional/aarch64/test_hotplug_pci.py b/tests/functional/aarch64/test_hotplug_pci.py
index bf67720431..9ee1446a83 100755
--- a/tests/functional/aarch64/test_hotplug_pci.py
+++ b/tests/functional/aarch64/test_hotplug_pci.py
@@ -27,6 +27,7 @@ class HotplugPCI(LinuxKernelTest):
def test_hotplug_pci(self):
self.set_machine('virt')
+ self.require_accelerator('tcg')
self.vm.add_args('-m', '512M',
'-cpu', 'cortex-a57',
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 21/23] tests/functional/test_tuxrun: Restrict to TCG
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (19 preceding siblings ...)
2026-05-15 10:49 ` [PULL 20/23] tests/functional/test_hotplug_pci.py: Require TCG Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 22/23] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist Peter Maydell
` (2 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The tuxrun tests specify the cortex-a57 CPU; this doesn't work on a
KVM-only QEMU build, where the default accelerator is KVM but KVM
doesn't support that CPU type. Restrict the test to TCG, to avoid
failures on KVM-only AArch64 builds:
Output: qemu-system-aarch64: kvm_init_vcpu: kvm_arch_init_vcpu failed (0): Invalid argument
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260507194728.2034696-7-peter.maydell@linaro.org
---
tests/functional/aarch64/test_tuxrun.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tests/functional/aarch64/test_tuxrun.py b/tests/functional/aarch64/test_tuxrun.py
index 75adc8acb8..7dd50c3de1 100755
--- a/tests/functional/aarch64/test_tuxrun.py
+++ b/tests/functional/aarch64/test_tuxrun.py
@@ -25,6 +25,7 @@ class TuxRunAarch64Test(TuxRunBaselineTest):
def test_arm64(self):
self.set_machine('virt')
+ self.require_accelerator('tcg')
self.cpu='cortex-a57'
self.console='ttyAMA0'
self.wait_for_shutdown=False
@@ -40,6 +41,7 @@ def test_arm64(self):
def test_arm64be(self):
self.set_machine('virt')
+ self.require_accelerator('tcg')
self.cpu='cortex-a57'
self.console='ttyAMA0'
self.wait_for_shutdown=False
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 22/23] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (20 preceding siblings ...)
2026-05-15 10:49 ` [PULL 21/23] tests/functional/test_tuxrun: Restrict to TCG Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-15 10:49 ` [PULL 23/23] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Peter Maydell
2026-05-16 23:25 ` [PULL 00/23] target-arm queue Stefan Hajnoczi
23 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
The Python os.setxattr() API is Linux-specific, so trying to use
it on other OSes triggers a failure:
File "/Users/pm215/src/qemu/tests/functional/qemu_test/asset.py",
line 227, in fetch
os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
^^^^^^^^^^^
AttributeError: module 'os' has no attribute 'setxattr'
Since we only set the attributes here for informational
purposes, skip them when os.setxattr() isn't available.
Cc: qemu-stable@nongnu.org
Fixes: 9903217a4ed013 ("tests/functional: add a module for handling asset download & caching")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Thomas Huth <th.huth+qemu@posteo.eu>
Message-id: 20260501115506.3792110-1-peter.maydell@linaro.org
---
tests/functional/qemu_test/asset.py | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py
index 51a434b2b7..0abd89e0a3 100644
--- a/tests/functional/qemu_test/asset.py
+++ b/tests/functional/qemu_test/asset.py
@@ -223,11 +223,14 @@ def fetch(self):
raise AssetError(self, "Download retries exceeded", transient=True)
try:
- # Set these just for informational purposes
- os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
- self.url.encode('utf8'))
- os.setxattr(str(tmp_cache_file), "user.qemu-asset-hash",
- self.hash.encode('utf8'))
+ # Set these just for informational purposes. Note that
+ # setxattr is Linux-only; as this is only informational
+ # we can simply skip it on other platforms.
+ if hasattr(os, "setxattr"):
+ os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
+ self.url.encode('utf8'))
+ os.setxattr(str(tmp_cache_file), "user.qemu-asset-hash",
+ self.hash.encode('utf8'))
except OSError as e:
self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e)
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PULL 23/23] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (21 preceding siblings ...)
2026-05-15 10:49 ` [PULL 22/23] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist Peter Maydell
@ 2026-05-15 10:49 ` Peter Maydell
2026-05-17 6:17 ` Michael Tokarev
2026-05-16 23:25 ` [PULL 00/23] target-arm queue Stefan Hajnoczi
23 siblings, 1 reply; 35+ messages in thread
From: Peter Maydell @ 2026-05-15 10:49 UTC (permalink / raw)
To: qemu-devel
From: "Scott J. Goldman" <scottjgo@gmail.com>
Commit b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
changed hvf_wfi() from blocking the vCPU thread with pselect() to
returning EXCP_HLT, intending QEMU's main event loop to handle the
idle wait. However, cpu->halted was never set, so cpu_thread_is_idle()
always returns false and the vCPU thread spins at 100% CPU per core
while the guest is idle.
Fix this by:
1. Setting cpu->halted = 1 in hvf_wfi() so the vCPU thread sleeps on
halt_cond in qemu_process_cpu_events().
2. Arming a per-vCPU QEMU_CLOCK_VIRTUAL timer to fire when the guest's
virtual timer (CNTV_CVAL_EL0) would expire. This is necessary
because HVF only delivers HV_EXIT_REASON_VTIMER_ACTIVATED during
hv_vcpu_run(), which is not called while the CPU is halted. The
timer callback mirrors the VTIMER_ACTIVATED handler: it raises the
vtimer IRQ through the GIC and marks vtimer_masked, causing the
interrupt delivery chain to wake the vCPU via qemu_cpu_kick().
3. Clearing cpu->halted in hvf_arch_vcpu_exec() when cpu_has_work()
indicates a pending interrupt, and cancelling the WFI timer.
4. Re-arming the WFI timer from hvf_vm_state_change() on the resume
transition for any halted vCPU, since the QEMUTimer is per-instance
state and is not migrated. After cpu_synchronize_all_states() the
migrated vtimer state is mirrored in env, so we can read CNTV_CTL
and CNTV_CVAL from there. If the vtimer has already expired by the
time the destination resumes, hvf_wfi_timer_cb() is invoked
directly so the halted vCPU is woken up.
All wfi_timer handling (allocation, arming, deletion, and the resume
re-arm) is gated on !hvf_irqchip_in_kernel(): with the Apple in-kernel
vGIC, HVF owns the vtimer and delivers wake-ups itself.
Note for stable backports: this commit won't apply to 11.0 as
it has changes to handle the hvf in-kernel irqchip support that
landed after the 11.0 release. The v3 version of this commit:
https://patchew.org/QEMU/20260427195516.46256-1-scottjgo@gmail.com/
should be suitable for 11.0 backporting (it is essentially
identical except that it doesn't make the changes conditional
on !hvf_irqchip_in_kernel()).
Cc: qemu-stable@nongnu.org
Fixes: b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
Signed-off-by: Scott J. Goldman <scottjgo@gmail.com>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
[PMM: added note about stable backports to commit message]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
include/system/hvf_int.h | 1 +
target/arm/hvf/hvf.c | 140 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index ad7d375109..d5eaf26dda 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -48,6 +48,7 @@ struct AccelCPUState {
hv_vcpu_exit_t *exit;
bool vtimer_masked;
bool guest_debug_enabled;
+ struct QEMUTimer *wfi_timer;
#endif
};
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 9312607001..d88cbe7c82 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -29,6 +29,7 @@
#include "hw/core/irq.h"
#include "hw/arm/virt.h"
#include "qemu/main-loop.h"
+#include "qemu/timer.h"
#include "system/cpus.h"
#include "arm-powerctl.h"
#include "target/arm/cpu.h"
@@ -308,6 +309,8 @@ void hvf_arm_init_debug(void)
#define TMR_CTL_IMASK (1 << 1)
#define TMR_CTL_ISTATUS (1 << 2)
+static void hvf_wfi_timer_cb(void *opaque);
+
static uint32_t chosen_ipa_bit_size;
typedef struct HVFVTimer {
@@ -1296,6 +1299,11 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
{
hv_return_t ret;
+ if (!hvf_irqchip_in_kernel()) {
+ timer_free(cpu->accel->wfi_timer);
+ cpu->accel->wfi_timer = NULL;
+ }
+
ret = hv_vcpu_destroy(cpu->accel->fd);
assert_hvf_ok(ret);
}
@@ -1487,6 +1495,11 @@ int hvf_arch_init_vcpu(CPUState *cpu)
arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]);
assert_hvf_ok(ret);
+ if (!hvf_irqchip_in_kernel()) {
+ cpu->accel->wfi_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ hvf_wfi_timer_cb, cpu);
+ }
+
aarch64_add_sme_properties(OBJECT(cpu));
return 0;
}
@@ -2194,6 +2207,62 @@ static uint64_t hvf_vtimer_val_raw(void)
return mach_absolute_time() - hvf_state->vtimer_offset;
}
+static void hvf_wfi_timer_cb(void *opaque)
+{
+ CPUState *cpu = opaque;
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+
+ /*
+ * vtimer expired while the CPU was halted for WFI.
+ * Mirror HV_EXIT_REASON_VTIMER_ACTIVATED: raise the vtimer
+ * interrupt and mark as masked so hvf_sync_vtimer() will
+ * check and unmask when the guest handles it.
+ *
+ * The interrupt delivery chain (GIC -> cpu_interrupt ->
+ * qemu_cpu_kick) wakes the vCPU thread from halt_cond.
+ */
+ qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1);
+ cpu->accel->vtimer_masked = true;
+}
+
+/*
+ * Arm a host-side QEMU_CLOCK_VIRTUAL timer to fire when the guest's
+ * vtimer (CNTV_CVAL_EL0) is scheduled to expire. HVF only delivers
+ * HV_EXIT_REASON_VTIMER_ACTIVATED during hv_vcpu_run(), which we won't
+ * call while the vCPU is halted, so we need this to wake the vCPU.
+ *
+ * QEMU_CLOCK_VIRTUAL pauses while the VM is stopped, which keeps the
+ * timer in lockstep with the guest's view of vtime across pause/resume.
+ *
+ * Caller must supply the current CNTV_CTL_EL0 and CNTV_CVAL_EL0 values,
+ * since the appropriate source (HVF vs. env) depends on context.
+ *
+ * Returns 0 if the timer was armed (or if the vtimer is disabled/masked
+ * and the vCPU should still halt waiting on another event), or -1 if
+ * the vtimer has already expired.
+ */
+static int hvf_arm_wfi_timer(CPUState *cpu, uint64_t ctl, uint64_t cval)
+{
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ uint64_t now;
+ int64_t delta_ns;
+
+ if (!(ctl & TMR_CTL_ENABLE) || (ctl & TMR_CTL_IMASK)) {
+ return 0;
+ }
+
+ now = hvf_vtimer_val_raw();
+ if (cval <= now) {
+ return -1;
+ }
+
+ delta_ns = muldiv64(cval - now, NANOSECONDS_PER_SECOND,
+ arm_cpu->gt_cntfrq_hz);
+ timer_mod(cpu->accel->wfi_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delta_ns);
+ return 0;
+}
+
static int hvf_wfi(CPUState *cpu)
{
if (cpu_has_work(cpu)) {
@@ -2204,6 +2273,29 @@ static int hvf_wfi(CPUState *cpu)
return 0;
}
+ if (!hvf_irqchip_in_kernel()) {
+ uint64_t ctl, cval;
+ hv_return_t r;
+
+ /*
+ * Read the vtimer state directly from HVF. We're on the vCPU
+ * thread, just exited from hv_vcpu_run(), so HVF holds the
+ * authoritative values and env may be stale.
+ */
+ r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CTL_EL0,
+ &ctl);
+ assert_hvf_ok(r);
+ r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CVAL_EL0,
+ &cval);
+ assert_hvf_ok(r);
+
+ if (hvf_arm_wfi_timer(cpu, ctl, cval) < 0) {
+ /* vtimer already expired, don't halt */
+ return 0;
+ }
+ }
+
+ cpu->halted = 1;
return EXCP_HLT;
}
@@ -2502,7 +2594,13 @@ int hvf_arch_vcpu_exec(CPUState *cpu)
hv_return_t r;
if (cpu->halted) {
- return EXCP_HLT;
+ if (!cpu_has_work(cpu)) {
+ return EXCP_HLT;
+ }
+ cpu->halted = 0;
+ if (!hvf_irqchip_in_kernel()) {
+ timer_del(cpu->accel->wfi_timer);
+ }
}
flush_cpu_state(cpu);
@@ -2551,6 +2649,46 @@ static void hvf_vm_state_change(void *opaque, bool running, RunState state)
/* Update vtimer offset on all CPUs */
hvf_state->vtimer_offset = mach_absolute_time() - s->vtimer_val;
cpu_synchronize_all_states();
+
+ /*
+ * After migration restore (or any resume), the wfi_timer is not
+ * scheduled on this QEMU instance, so re-arm it for any halted
+ * vCPU with a pending vtimer. For a non-migration resume the
+ * QEMU_CLOCK_VIRTUAL timer was already scheduled; recomputing the
+ * deadline produces the same value and is a harmless no-op.
+ *
+ * cpu_synchronize_all_states() above ensures env mirrors the
+ * authoritative vtimer state (whether that came from HVF or from
+ * the migration stream), so we can safely read it here from the
+ * iothread.
+ *
+ * Only applies when we own the wfi_timer; with an in-kernel vGIC
+ * the timer is never allocated and HVF handles vtimer wake-ups.
+ */
+ if (!hvf_irqchip_in_kernel()) {
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ ARMCPU *arm_cpu;
+ uint64_t ctl, cval;
+
+ if (!cpu->accel || !cpu->halted) {
+ continue;
+ }
+
+ arm_cpu = ARM_CPU(cpu);
+ ctl = arm_cpu->env.cp15.c14_timer[GTIMER_VIRT].ctl;
+ cval = arm_cpu->env.cp15.c14_timer[GTIMER_VIRT].cval;
+
+ if (hvf_arm_wfi_timer(cpu, ctl, cval) < 0) {
+ /*
+ * vtimer already expired while we were paused; raise
+ * the IRQ now so the halted vCPU wakes up.
+ */
+ hvf_wfi_timer_cb(cpu);
+ }
+ }
+ }
} else {
/* Remember vtimer value on every pause */
s->vtimer_val = hvf_vtimer_val_raw();
--
2.43.0
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [PULL 23/23] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning
2026-05-15 10:49 ` [PULL 23/23] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Peter Maydell
@ 2026-05-17 6:17 ` Michael Tokarev
0 siblings, 0 replies; 35+ messages in thread
From: Michael Tokarev @ 2026-05-17 6:17 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
On 15.05.2026 13:49, Peter Maydell wrote:
> From: "Scott J. Goldman" <scottjgo@gmail.com>
>
> Commit b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
> changed hvf_wfi() from blocking the vCPU thread with pselect() to
> returning EXCP_HLT, intending QEMU's main event loop to handle the
> idle wait. However, cpu->halted was never set, so cpu_thread_is_idle()
> always returns false and the vCPU thread spins at 100% CPU per core
> while the guest is idle.
>
> Fix this by:
>
> 1. Setting cpu->halted = 1 in hvf_wfi() so the vCPU thread sleeps on
> halt_cond in qemu_process_cpu_events().
>
> 2. Arming a per-vCPU QEMU_CLOCK_VIRTUAL timer to fire when the guest's
> virtual timer (CNTV_CVAL_EL0) would expire. This is necessary
> because HVF only delivers HV_EXIT_REASON_VTIMER_ACTIVATED during
> hv_vcpu_run(), which is not called while the CPU is halted. The
> timer callback mirrors the VTIMER_ACTIVATED handler: it raises the
> vtimer IRQ through the GIC and marks vtimer_masked, causing the
> interrupt delivery chain to wake the vCPU via qemu_cpu_kick().
>
> 3. Clearing cpu->halted in hvf_arch_vcpu_exec() when cpu_has_work()
> indicates a pending interrupt, and cancelling the WFI timer.
>
> 4. Re-arming the WFI timer from hvf_vm_state_change() on the resume
> transition for any halted vCPU, since the QEMUTimer is per-instance
> state and is not migrated. After cpu_synchronize_all_states() the
> migrated vtimer state is mirrored in env, so we can read CNTV_CTL
> and CNTV_CVAL from there. If the vtimer has already expired by the
> time the destination resumes, hvf_wfi_timer_cb() is invoked
> directly so the halted vCPU is woken up.
>
> All wfi_timer handling (allocation, arming, deletion, and the resume
> re-arm) is gated on !hvf_irqchip_in_kernel(): with the Apple in-kernel
> vGIC, HVF owns the vtimer and delivers wake-ups itself.
>
> Note for stable backports: this commit won't apply to 11.0 as
> it has changes to handle the hvf in-kernel irqchip support that
> landed after the 11.0 release. The v3 version of this commit:
> https://patchew.org/QEMU/20260427195516.46256-1-scottjgo@gmail.com/
> should be suitable for 11.0 backporting (it is essentially
> identical except that it doesn't make the changes conditional
> on !hvf_irqchip_in_kernel()).
Hi!
How about I pick up this patch instead, but add a one-line on top
of target/arm/hvf/hvf.c (or to include/system/hvf_int.h):
#define hvf_irqchip_in_kernel() 0
with a comment saying why it's here? I think it will be cleaner
this way, with better traceable roots.
Thanks,
/mjt
> Cc: qemu-stable@nongnu.org
> Fixes: b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
> Signed-off-by: Scott J. Goldman <scottjgo@gmail.com>
> Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> [PMM: added note about stable backports to commit message]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> include/system/hvf_int.h | 1 +
> target/arm/hvf/hvf.c | 140 ++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 140 insertions(+), 1 deletion(-)
>
> diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
> index ad7d375109..d5eaf26dda 100644
> --- a/include/system/hvf_int.h
> +++ b/include/system/hvf_int.h
> @@ -48,6 +48,7 @@ struct AccelCPUState {
> hv_vcpu_exit_t *exit;
> bool vtimer_masked;
> bool guest_debug_enabled;
> + struct QEMUTimer *wfi_timer;
> #endif
> };
>
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index 9312607001..d88cbe7c82 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -29,6 +29,7 @@
> #include "hw/core/irq.h"
> #include "hw/arm/virt.h"
> #include "qemu/main-loop.h"
> +#include "qemu/timer.h"
> #include "system/cpus.h"
> #include "arm-powerctl.h"
> #include "target/arm/cpu.h"
> @@ -308,6 +309,8 @@ void hvf_arm_init_debug(void)
> #define TMR_CTL_IMASK (1 << 1)
> #define TMR_CTL_ISTATUS (1 << 2)
>
> +static void hvf_wfi_timer_cb(void *opaque);
> +
> static uint32_t chosen_ipa_bit_size;
>
> typedef struct HVFVTimer {
> @@ -1296,6 +1299,11 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
> {
> hv_return_t ret;
>
> + if (!hvf_irqchip_in_kernel()) {
> + timer_free(cpu->accel->wfi_timer);
> + cpu->accel->wfi_timer = NULL;
> + }
> +
> ret = hv_vcpu_destroy(cpu->accel->fd);
> assert_hvf_ok(ret);
> }
> @@ -1487,6 +1495,11 @@ int hvf_arch_init_vcpu(CPUState *cpu)
> arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]);
> assert_hvf_ok(ret);
>
> + if (!hvf_irqchip_in_kernel()) {
> + cpu->accel->wfi_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> + hvf_wfi_timer_cb, cpu);
> + }
> +
> aarch64_add_sme_properties(OBJECT(cpu));
> return 0;
> }
> @@ -2194,6 +2207,62 @@ static uint64_t hvf_vtimer_val_raw(void)
> return mach_absolute_time() - hvf_state->vtimer_offset;
> }
>
> +static void hvf_wfi_timer_cb(void *opaque)
> +{
> + CPUState *cpu = opaque;
> + ARMCPU *arm_cpu = ARM_CPU(cpu);
> +
> + /*
> + * vtimer expired while the CPU was halted for WFI.
> + * Mirror HV_EXIT_REASON_VTIMER_ACTIVATED: raise the vtimer
> + * interrupt and mark as masked so hvf_sync_vtimer() will
> + * check and unmask when the guest handles it.
> + *
> + * The interrupt delivery chain (GIC -> cpu_interrupt ->
> + * qemu_cpu_kick) wakes the vCPU thread from halt_cond.
> + */
> + qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1);
> + cpu->accel->vtimer_masked = true;
> +}
> +
> +/*
> + * Arm a host-side QEMU_CLOCK_VIRTUAL timer to fire when the guest's
> + * vtimer (CNTV_CVAL_EL0) is scheduled to expire. HVF only delivers
> + * HV_EXIT_REASON_VTIMER_ACTIVATED during hv_vcpu_run(), which we won't
> + * call while the vCPU is halted, so we need this to wake the vCPU.
> + *
> + * QEMU_CLOCK_VIRTUAL pauses while the VM is stopped, which keeps the
> + * timer in lockstep with the guest's view of vtime across pause/resume.
> + *
> + * Caller must supply the current CNTV_CTL_EL0 and CNTV_CVAL_EL0 values,
> + * since the appropriate source (HVF vs. env) depends on context.
> + *
> + * Returns 0 if the timer was armed (or if the vtimer is disabled/masked
> + * and the vCPU should still halt waiting on another event), or -1 if
> + * the vtimer has already expired.
> + */
> +static int hvf_arm_wfi_timer(CPUState *cpu, uint64_t ctl, uint64_t cval)
> +{
> + ARMCPU *arm_cpu = ARM_CPU(cpu);
> + uint64_t now;
> + int64_t delta_ns;
> +
> + if (!(ctl & TMR_CTL_ENABLE) || (ctl & TMR_CTL_IMASK)) {
> + return 0;
> + }
> +
> + now = hvf_vtimer_val_raw();
> + if (cval <= now) {
> + return -1;
> + }
> +
> + delta_ns = muldiv64(cval - now, NANOSECONDS_PER_SECOND,
> + arm_cpu->gt_cntfrq_hz);
> + timer_mod(cpu->accel->wfi_timer,
> + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delta_ns);
> + return 0;
> +}
> +
> static int hvf_wfi(CPUState *cpu)
> {
> if (cpu_has_work(cpu)) {
> @@ -2204,6 +2273,29 @@ static int hvf_wfi(CPUState *cpu)
> return 0;
> }
>
> + if (!hvf_irqchip_in_kernel()) {
> + uint64_t ctl, cval;
> + hv_return_t r;
> +
> + /*
> + * Read the vtimer state directly from HVF. We're on the vCPU
> + * thread, just exited from hv_vcpu_run(), so HVF holds the
> + * authoritative values and env may be stale.
> + */
> + r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CTL_EL0,
> + &ctl);
> + assert_hvf_ok(r);
> + r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CVAL_EL0,
> + &cval);
> + assert_hvf_ok(r);
> +
> + if (hvf_arm_wfi_timer(cpu, ctl, cval) < 0) {
> + /* vtimer already expired, don't halt */
> + return 0;
> + }
> + }
> +
> + cpu->halted = 1;
> return EXCP_HLT;
> }
>
> @@ -2502,7 +2594,13 @@ int hvf_arch_vcpu_exec(CPUState *cpu)
> hv_return_t r;
>
> if (cpu->halted) {
> - return EXCP_HLT;
> + if (!cpu_has_work(cpu)) {
> + return EXCP_HLT;
> + }
> + cpu->halted = 0;
> + if (!hvf_irqchip_in_kernel()) {
> + timer_del(cpu->accel->wfi_timer);
> + }
> }
>
> flush_cpu_state(cpu);
> @@ -2551,6 +2649,46 @@ static void hvf_vm_state_change(void *opaque, bool running, RunState state)
> /* Update vtimer offset on all CPUs */
> hvf_state->vtimer_offset = mach_absolute_time() - s->vtimer_val;
> cpu_synchronize_all_states();
> +
> + /*
> + * After migration restore (or any resume), the wfi_timer is not
> + * scheduled on this QEMU instance, so re-arm it for any halted
> + * vCPU with a pending vtimer. For a non-migration resume the
> + * QEMU_CLOCK_VIRTUAL timer was already scheduled; recomputing the
> + * deadline produces the same value and is a harmless no-op.
> + *
> + * cpu_synchronize_all_states() above ensures env mirrors the
> + * authoritative vtimer state (whether that came from HVF or from
> + * the migration stream), so we can safely read it here from the
> + * iothread.
> + *
> + * Only applies when we own the wfi_timer; with an in-kernel vGIC
> + * the timer is never allocated and HVF handles vtimer wake-ups.
> + */
> + if (!hvf_irqchip_in_kernel()) {
> + CPUState *cpu;
> +
> + CPU_FOREACH(cpu) {
> + ARMCPU *arm_cpu;
> + uint64_t ctl, cval;
> +
> + if (!cpu->accel || !cpu->halted) {
> + continue;
> + }
> +
> + arm_cpu = ARM_CPU(cpu);
> + ctl = arm_cpu->env.cp15.c14_timer[GTIMER_VIRT].ctl;
> + cval = arm_cpu->env.cp15.c14_timer[GTIMER_VIRT].cval;
> +
> + if (hvf_arm_wfi_timer(cpu, ctl, cval) < 0) {
> + /*
> + * vtimer already expired while we were paused; raise
> + * the IRQ now so the halted vCPU wakes up.
> + */
> + hvf_wfi_timer_cb(cpu);
> + }
> + }
> + }
> } else {
> /* Remember vtimer value on every pause */
> s->vtimer_val = hvf_vtimer_val_raw();
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PULL 00/23] target-arm queue
2026-05-15 10:49 [PULL 00/23] target-arm queue Peter Maydell
` (22 preceding siblings ...)
2026-05-15 10:49 ` [PULL 23/23] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Peter Maydell
@ 2026-05-16 23:25 ` Stefan Hajnoczi
23 siblings, 0 replies; 35+ messages in thread
From: Stefan Hajnoczi @ 2026-05-16 23:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 35+ messages in thread