>
> > Pierrick Bouvier (14):
> > qom/object: add is_available callback to TypeInfo
>
Patches for is_available callback to TypeInfo, it's can be merged latter
The reason is for the following command to execute:
we need add target_info_select and pass TargetInfo to is_available
- Move target_info() into qom/object.c. Default to SYS_EMU_TARGET_NONE
until a real target is selected.
- Add target_info_select(); it may be called only once with a non-NULL
TargetInfo that is not SYS_EMU_TARGET_NONE.
- Invoke TypeInfo.is_available after select, passing target_info().
- Change target_* helpers to take const TargetInfo *.
- Select the sole TargetInfo in user-mode MODULE_INIT_TARGET_INFO.
With these changes, when `qemu-system` does not select TargetInfo, we can
still list all machines and devices for each target properly.
```
$ ./qemu-system.exe -machine ?
Supported machines are:
none:
amd-microblaze-v-generic AMD Microblaze-V generic platform
xlnx-versal-virt AMD Versal Virtual development board (alias of
amd-versal-virt)
amd-versal-virt AMD Versal Virtual development board
amd-versal2-virt AMD Versal Gen 2 Virtual development board
anacapa-bmc Facebook Anacapa BMC (Cortex-A7)
ast1030-evb Aspeed AST1030 MiniBMC (Cortex-M4)
ast1040-evb Aspeed AST1040 BIC EVB (Cortex-M4F)
ast1060-evb Aspeed AST1060 Platform Root of Trust (Cortex-M4)
ast2500-evb Aspeed AST2500 EVB (ARM1176)
ast2600-evb Aspeed AST2600 EVB (Cortex-A7)
axiado-scm3003 Axiado SCM3003 EVK Board
b-l475e-iot01a B-L475E-IOT01A Discovery Kit (Cortex-M4)
bletchley-bmc Facebook Bletchley BMC (Cortex-A7)
boston-aia MIPS Boston-aia
bpim2u Bananapi M2U (Cortex-A7)
canon-a1100 Canon PowerShot A1100 IS (ARM946)
catalina-bmc Facebook Catalina BMC (Cortex-A7)
collie Sharp SL-5500 (Collie) PDA (SA-1110)
cubieboard cubietech cubieboard (Cortex-A8)
emcraft-sf2 SmartFusion2 SOM kit from Emcraft (M2S010)
fby35-bmc Facebook fby35 BMC (Cortex-A7)
fuji-bmc Facebook Fuji BMC (Cortex-A7)
g220a-bmc Bytedance G220A BMC (ARM1176)
gb200nvl-bmc Nvidia GB200NVL BMC (Cortex-A7)
imx25-pdk ARM i.MX25 PDK board (ARM926)
imx8mm-evk NXP i.MX 8MM EVK Board
imx8mp-evk NXP i.MX 8M Plus EVK Board
integratorcp ARM Integrator/CP (ARM926EJ-S)
kudo-bmc Kudo BMC (Cortex-A9)
kzm ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb Stellaris LM3S6965EVB (Cortex-M3)
lm3s811evb Stellaris LM3S811EVB (Cortex-M3)
max78000fthr MAX78000FTHR Board (Cortex-M4 / (Unimplemented) RISC-V)
mcimx6ul-evk Freescale i.MX6UL Evaluation Kit (Cortex-A7)
mcimx7d-sabre Freescale i.MX7 DUAL SABRE (Cortex-A7)
microbit BBC micro:bit (Cortex-M0)
mori-bmc Mori BMC (Cortex-A9)
mps2-an385 ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an386 ARM MPS2 with AN386 FPGA image for Cortex-M4
mps2-an500 ARM MPS2 with AN500 FPGA image for Cortex-M7
mps2-an505 ARM MPS2 with AN505 FPGA image for Cortex-M33
mps2-an511 ARM MPS2 with AN511 DesignStart FPGA image for
Cortex-M3
mps2-an521 ARM MPS2 with AN521 FPGA image for dual Cortex-M33
mps3-an524 ARM MPS3 with AN524 FPGA image for dual Cortex-M33
mps3-an536 ARM MPS3 with AN536 FPGA image for Cortex-R52
mps3-an547 ARM MPS3 with AN547 FPGA image for Cortex-M55
mps3-an555 ARM MPS3 with AN555 FPGA image for Cortex-M85
musca-a ARM Musca-A board (dual Cortex-M33)
musca-b1 ARM Musca-B1 board (dual Cortex-M33)
netduino2 Netduino 2 Machine (Cortex-M3)
netduinoplus2 Netduino Plus 2 Machine (Cortex-M4)
none empty machine
npcm750-evb Nuvoton NPCM750 Evaluation Board (Cortex-A9)
npcm845-evb Nuvoton NPCM845 Evaluation Board (Cortex-A35)
nuri Samsung NURI board (Exynos4210)
olimex-stm32-h405 Olimex STM32-H405 (Cortex-M4)
orangepi-pc Orange Pi PC (Cortex-A7)
palmetto-bmc OpenPOWER Palmetto BMC (ARM926EJ-S)
quanta-gbs-bmc Quanta GBS (Cortex-A9)
quanta-gsj Quanta GSJ (Cortex-A9)
quanta-q71l-bmc Quanta-Q71l BMC (ARM926EJ-S)
rainier-bmc IBM Rainier BMC (Cortex-A7)
raspi0 Raspberry Pi Zero (revision 1.2)
raspi1ap Raspberry Pi A+ (revision 1.1)
raspi2b Raspberry Pi 2B (revision 1.1)
realview-eb ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8 ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9 ARM RealView Platform Baseboard Explore for Cortex-A9
romulus-bmc OpenPOWER Romulus BMC (ARM1176)
sabrelite Freescale i.MX6 Quad SABRE Lite Board (Cortex-A9)
sbsa-ref QEMU 'SBSA Reference' ARM Virtual Machine
smdkc210 Samsung SMDKC210 board (Exynos4210)
stm32vldiscovery ST STM32VLDISCOVERY (Cortex-M3)
supermicro-x11spi-bmc Supermicro X11 SPI BMC (ARM1176)
supermicrox11-bmc Supermicro X11 BMC (ARM926EJ-S)
sx1 Siemens SX1 (OMAP310) V2
sx1-v1 Siemens SX1 (OMAP310) V1
tiogapass-bmc Facebook Tiogapass BMC (ARM1176)
versatileab ARM Versatile/AB (ARM926EJ-S)
versatilepb ARM Versatile/PB (ARM926EJ-S)
vexpress-a15 ARM Versatile Express for Cortex-A15
vexpress-a9 ARM Versatile Express for Cortex-A9
virt-10.0 QEMU 10.0 ARM Virtual Machine
virt-10.1 QEMU 10.1 ARM Virtual Machine
virt-10.2 QEMU 10.2 ARM Virtual Machine
virt-11.0 QEMU 11.0 ARM Virtual Machine
virt-11.1 QEMU 11.1 ARM Virtual Machine
virt QEMU 11.2 ARM Virtual Machine (alias of virt-11.2)
virt-11.2 QEMU 11.2 ARM Virtual Machine
virt-6.0 QEMU 6.0 ARM Virtual Machine (deprecated)
virt-6.1 QEMU 6.1 ARM Virtual Machine (deprecated)
virt-6.2 QEMU 6.2 ARM Virtual Machine (deprecated)
virt-7.0 QEMU 7.0 ARM Virtual Machine (deprecated)
virt-7.1 QEMU 7.1 ARM Virtual Machine (deprecated)
virt-7.2 QEMU 7.2 ARM Virtual Machine (deprecated)
virt-8.0 QEMU 8.0 ARM Virtual Machine (deprecated)
virt-8.1 QEMU 8.1 ARM Virtual Machine (deprecated)
virt-8.2 QEMU 8.2 ARM Virtual Machine (deprecated)
virt-9.0 QEMU 9.0 ARM Virtual Machine
virt-9.1 QEMU 9.1 ARM Virtual Machine
virt-9.2 QEMU 9.2 ARM Virtual Machine
witherspoon-bmc OpenPOWER Witherspoon BMC (ARM1176)
xilinx-zynq-a9 Xilinx Zynq 7000 Platform Baseboard for Cortex-A9
xlnx-zcu102 Xilinx ZynqMP ZCU102 board with 4xA53s and 2xR5Fs
based on the value of smp
yosemitev2-bmc Facebook YosemiteV2 BMC (ARM1176)
aarch64:
ast2700a1-evb Aspeed AST2700 A1 EVB (Cortex-A35)
ast2700-evb Aspeed AST2700 A2 EVB (Cortex-A35) (alias of
ast2700a2-evb)
ast2700a2-evb Aspeed AST2700 A2 EVB (Cortex-A35)
ast2700fc ast2700 full core support
raspi3ap Raspberry Pi 3A+ (revision 1.0)
raspi3b Raspberry Pi 3B (revision 1.2)
raspi4b Raspberry Pi 4B (revision 1.5)
riscv32:
k230 RISC-V Board compatible with Kendryte K230 SDK
microchip-icicle-kit Microchip PolarFire SoC Icicle Kit
opentitan RISC-V Board compatible with OpenTitan
shakti_c RISC-V Board compatible with Shakti SDK (deprecated)
sifive_e RISC-V Board compatible with SiFive E SDK
sifive_u RISC-V Board compatible with SiFive U SDK
spike RISC-V Spike board
tt-atlantis Tenstorrent Atlantis RISC-V SoC (Experimental)
virt RISC-V VirtIO board
xiangshan-kunminghu RISC-V Board compatible with the Xiangshan Kunminghu
FPGA prototype platform
riscv64:
k230 RISC-V Board compatible with Kendryte K230 SDK
microchip-icicle-kit Microchip PolarFire SoC Icicle Kit
opentitan RISC-V Board compatible with OpenTitan
shakti_c RISC-V Board compatible with Shakti SDK (deprecated)
sifive_e RISC-V Board compatible with SiFive E SDK
sifive_u RISC-V Board compatible with SiFive U SDK
spike RISC-V Spike board
tt-atlantis Tenstorrent Atlantis RISC-V SoC (Experimental)
virt RISC-V VirtIO board
xiangshan-kunminghu RISC-V Board compatible with the Xiangshan Kunminghu
FPGA prototype platform
```
--
此致
礼
罗勇刚
Yours
sincerely,
Yonggang Luo
From 8afca178b69ebf38e0f0ed048a59883ac92308b3 Mon Sep 17 00:00:00 2001
From: Yonggang Luo <[email protected]>
Date: Thu, 3 Sep 2026 13:12:32 +0800
Subject: [PATCH 2/3] qom: add target_info_select and pass TargetInfo to
is_available
- Move target_info() into qom/object.c. Default to SYS_EMU_TARGET_NONE
until a real target is selected.
- Add target_info_select(); it may be called only once with a non-NULL
TargetInfo that is not SYS_EMU_TARGET_NONE.
- Invoke TypeInfo.is_available after select, passing target_info().
- Change target_* helpers to take const TargetInfo *.
- Select the sole TargetInfo in user-mode MODULE_INIT_TARGET_INFO.
---
bsd-user/main.c | 1 +
hw/arm/aspeed_ast27x0.c | 4 +--
hw/arm/virt.c | 4 +--
hw/nitro/machine.c | 2 +-
hw/pci/pci.c | 2 +-
hw/scsi/scsi-disk.c | 2 +-
hw/vfio/migration-multifd.c | 2 +-
hw/virtio/vhost-user.c | 2 +-
include/qemu/target-info-impl.h | 13 +++-----
include/qemu/target-info-init.h | 18 ++++++-----
include/qemu/target-info.h | 44 +++++++++++++++++----------
include/qom/object.h | 53 +++++++++++++++++++++++++++++++--
linux-user/main.c | 1 +
qom/object.c | 36 +++++++++++++++++++++-
target-info-qom.c | 9 +-----
target-info.c | 32 ++++++++++----------
target/arm/cpu-max.c | 2 +-
target/arm/tcg/cpu-max-v8.c | 2 +-
18 files changed, 157 insertions(+), 72 deletions(-)
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 694481ae3ec..592c04f1e79 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -285,6 +285,7 @@ int main(int argc, char **argv)
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qemu_init_cpu_list();
+ module_call_init(MODULE_INIT_TARGET_INFO);
module_call_init(MODULE_INIT_QOM);
envlist = envlist_create();
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 6365dbd638b..1703ac7d0ca 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -420,7 +420,7 @@ static void aspeed_soc_ast2700_init(Object *obj)
}
for (i = 0; i < sc->num_cpus; i++) {
- if (qtest_enabled() && !target_aarch64()) {
+ if (qtest_enabled() && !target_aarch64(target_info())) {
/*
* Introspection qtest just want to create this object
* without realizing it. ARM_CPU_TYPE_NAME("cortex-a35")
@@ -703,7 +703,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev,
Error **errp)
qemu_irq irq;
int uart;
- if (qtest_enabled() && !target_aarch64()) {
+ if (qtest_enabled() && !target_aarch64(target_info())) {
g_assert_not_reached();
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0871a35e11f..dbdf55dfea9 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4132,7 +4132,7 @@ static GPtrArray *virt_get_valid_cpu_types(const
MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a15")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("max-v8")));
}
- if (tcg_enabled() && target_aarch64()) {
+ if (tcg_enabled() && target_aarch64(target_info())) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a35")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a55")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a72")));
@@ -4144,7 +4144,7 @@ static GPtrArray *virt_get_valid_cpu_types(const
MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-n2")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("max-v9")));
}
- if (target_aarch64()) {
+ if (target_aarch64(target_info())) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a57")));
if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
diff --git a/hw/nitro/machine.c b/hw/nitro/machine.c
index 88d01960a01..2a924cab4f7 100644
--- a/hw/nitro/machine.c
+++ b/hw/nitro/machine.c
@@ -97,7 +97,7 @@ static char *build_eif(const char *kernel_data, gsize
kernel_size,
hdr = (EifHeader) {
.magic = EIF_MAGIC,
.version = cpu_to_be16(4),
- .flags = cpu_to_be16(target_aarch64() ? EIF_HDR_ARCH_ARM64 : 0),
+ .flags = cpu_to_be16(target_aarch64(target_info()) ?
EIF_HDR_ARCH_ARM64 : 0),
};
g_byte_array_append(buf, (const uint8_t *)&hdr, sizeof(hdr));
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index c15f2b9f084..26003f2b4df 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2888,7 +2888,7 @@ void pci_qdev_property_add_specifics(DeviceClass *dc)
ObjectClass *oc = OBJECT_CLASS(dc);
/* The loadparm property is only supported on s390x */
- if (target_s390x()) {
+ if (target_s390x(target_info())) {
object_class_property_add_str(oc, "loadparm",
pci_qdev_property_get_loadparm,
pci_qdev_property_set_loadparm);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index a42f7d8e77d..31170e87a33 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -3190,7 +3190,7 @@ static void scsi_property_add_specifics(DeviceClass *dc)
ObjectClass *oc = OBJECT_CLASS(dc);
/* The loadparm property is only supported on s390x */
- if (target_s390x()) {
+ if (target_s390x(target_info())) {
object_class_property_add_str(oc, "loadparm",
scsi_property_get_loadparm,
scsi_property_set_loadparm);
diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c
index a06cbf3c646..3d747b470cc 100644
--- a/hw/vfio/migration-multifd.c
+++ b/hw/vfio/migration-multifd.c
@@ -54,7 +54,7 @@ bool vfio_load_config_after_iter(VFIODevice *vbasedev)
* See commit d329f5032e17 ("vfio: Move the saving of the config space to
* the right place in VFIO migration").
*/
- return target_base_arm();
+ return target_base_arm(target_info());
}
/* type safety */
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 2881cec72d9..3383af64859 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -2631,7 +2631,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev,
void *opaque,
return -EINVAL;
}
- const uint64_t vhost_user_max_ram_slots = target_base_ppc() ?
+ const uint64_t vhost_user_max_ram_slots =
target_base_ppc(target_info()) ?
SPAPR_MAX_RAM_SLOTS : VHOST_USER_MAX_RAM_SLOTS;
u->user->memory_slots = MIN(ram_slots, vhost_user_max_ram_slots);
}
diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h
index cf42aabbc8b..61404baa4b5 100644
--- a/include/qemu/target-info-impl.h
+++ b/include/qemu/target-info-impl.h
@@ -9,10 +9,12 @@
#ifndef QEMU_TARGET_INFO_IMPL_H
#define QEMU_TARGET_INFO_IMPL_H
+#include "qemu/target-info.h"
+#include "qom/object.h"
#include "qapi/qapi-types-common.h"
#include "qapi/qapi-types-machine.h"
-typedef struct TargetInfo {
+struct TargetInfo {
/* runtime equivalent of TARGET_NAME definition */
const char *target_name;
/* related to TARGET_ARCH definition */
@@ -30,13 +32,6 @@ typedef struct TargetInfo {
unsigned page_bits_init;
/* runtime equivalent of TARGET_PAGE_BITS_VARY definition */
bool page_bits_vary;
-} TargetInfo;
-
-/**
- * target_info:
- *
- * Returns: The TargetInfo structure definition for this target binary.
- */
-const TargetInfo *target_info(void);
+};
#endif
diff --git a/include/qemu/target-info-init.h b/include/qemu/target-info-init.h
index b7024c9faef..2a19918ae08 100644
--- a/include/qemu/target-info-init.h
+++ b/include/qemu/target-info-init.h
@@ -12,6 +12,8 @@
#ifndef QEMU_TARGET_INFO_INIT_H
#define QEMU_TARGET_INFO_INIT_H
+#include "qom/object.h"
+
#define DEFINE_TARGET_INFO_TYPE(info) \
static void do_qemu_init_target_info(void) \
{ \
@@ -23,19 +25,19 @@ module_init(do_qemu_init_target_info,
MODULE_INIT_TARGET_INFO)
#ifdef CONFIG_USER_ONLY
/*
- * User mode does not support multiple targets in the same binary, so just
- * define target_info().
+ * User mode does not support multiple targets in the same binary.
+ * Install the sole TargetInfo before MODULE_INIT_QOM.
*/
-#define target_info_init(ti_var) \
-const TargetInfo *target_info(void) \
-{ \
- return &ti_var; \
-}
+#define target_info_init(ti_var) \
+static void do_qemu_init_target_info(void) \
+{ \
+ target_info_select(&ti_var); \
+} \
+module_init(do_qemu_init_target_info, MODULE_INIT_TARGET_INFO)
#else /* CONFIG_USER_ONLY */
#include "qemu/target-info-qom.h"
-#include "qom/object.h"
#define target_info_init(ti_var) \
static const TypeInfo target_info_qom_target_type_info = { \
diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h
index b23e5bc5865..f6a82be6290 100644
--- a/include/qemu/target-info.h
+++ b/include/qemu/target-info.h
@@ -9,6 +9,10 @@
#ifndef QEMU_TARGET_INFO_H
#define QEMU_TARGET_INFO_H
+#include <stdbool.h>
+
+typedef struct TargetInfo TargetInfo;
+
/**
* target_name:
*
@@ -44,58 +48,66 @@ bool target_big_endian(void);
/**
* target_base_arm:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is ARM or Aarch64.
+ * Returns whether @ti is ARM or AArch64.
*/
-bool target_base_arm(void);
+bool target_base_arm(const TargetInfo *ti);
/**
* target_arm:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is ARM (32-bit, not Aarch64).
+ * Returns whether @ti is ARM (32-bit, not AArch64).
*/
-bool target_arm(void);
+bool target_arm(const TargetInfo *ti);
/**
* target_aarch64:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is Aarch64.
+ * Returns whether @ti is AArch64.
*/
-bool target_aarch64(void);
+bool target_aarch64(const TargetInfo *ti);
/**
* target_base_ppc:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is PowerPC 32-bit or 64-bit.
+ * Returns whether @ti is PowerPC 32-bit or 64-bit.
*/
-bool target_base_ppc(void);
+bool target_base_ppc(const TargetInfo *ti);
/**
* target_ppc:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is PowerPC 32-bit.
+ * Returns whether @ti is PowerPC 32-bit.
*/
-bool target_ppc(void);
+bool target_ppc(const TargetInfo *ti);
/**
* target_ppc64:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is PowerPC 64-bit.
+ * Returns whether @ti is PowerPC 64-bit.
*/
-bool target_ppc64(void);
+bool target_ppc64(const TargetInfo *ti);
/**
* target_s390x:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is S390x.
+ * Returns whether @ti is S390x.
*/
-bool target_s390x(void);
+bool target_s390x(const TargetInfo *ti);
/**
* target_riscv64:
+ * @ti: TargetInfo to test.
*
- * Returns whether the target architecture is riscv64
+ * Returns whether @ti is RISC-V 64-bit.
*/
-bool target_riscv64(void);
+bool target_riscv64(const TargetInfo *ti);
#endif
diff --git a/include/qom/object.h b/include/qom/object.h
index 7ecd0f210fb..aeb1871146b 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -117,6 +117,42 @@ typedef void (ObjectUnparent)(Object *obj);
*/
typedef void (ObjectFree)(void *obj);
+typedef struct TargetInfo TargetInfo;
+
+/**
+ * target_info:
+ *
+ * Returns: The current TargetInfo. Before target_info_select(), the
+ * default uses SYS_EMU_TARGET_NONE.
+ */
+const TargetInfo *target_info(void);
+
+/**
+ * target_info_select:
+ * @ti: TargetInfo to select
+ *
+ * Sets the TargetInfo returned by target_info(). Must be called only
+ * once. @ti must not be NULL and must not use SYS_EMU_TARGET_NONE.
+ */
+void target_info_select(const TargetInfo *ti);
+
+/**
+ * typedef TypeIsAvailable:
+ * @ti: TargetInfo to test.
+ *
+ * Returns whether a type is available for @ti. Typical implementations
+ * are target_*().
+ *
+ * At registration, QOM calls this with target_info() after
+ * target_info_select(). It is skipped until a TargetInfo is selected.
+ *
+ * Before a TargetInfo is selected, callers may invoke this with a
+ * custom TargetInfo to list whether a type belongs to that target.
+ * For example, a machine type may match a specific list of target
+ * names.
+ */
+typedef bool (TypeIsAvailable)(const TargetInfo *ti);
+
#define OBJECT_CLASS_CAST_CACHE 4
/**
@@ -469,8 +505,10 @@ struct Object
* @class_data: Data to pass to the @class_init,
* @class_base_init. This can be useful when building dynamic
* classes.
- * @is_available: callback invoked at registration time, to dynamically check
if
- * this type should be available or not.
+ * @is_available: callback invoked at registration time with
+ * target_info() after target_info_select(), to dynamically check if
+ * this type should be available. Skipped until a TargetInfo is
+ * selected. Listing code may call it with a specific TargetInfo.
* @interfaces: The list of interfaces associated with this type. This
* should point to a static array that's terminated with a zero filled
* element.
@@ -493,7 +531,7 @@ struct TypeInfo
void (*class_base_init)(ObjectClass *klass, const void *data);
const void *class_data;
- bool (*is_available)(void);
+ TypeIsAvailable *is_available;
const InterfaceInfo *interfaces;
};
@@ -1066,6 +1104,15 @@ ObjectClass *object_class_get_parent(ObjectClass *klass);
*/
const char *object_class_get_name(ObjectClass *klass);
+/**
+ * object_class_get_is_available:
+ * @klass: The class to obtain TypeInfo.is_available for.
+ *
+ * Returns: The availability callback, or %NULL if the type is always
+ * available.
+ */
+TypeIsAvailable *object_class_get_is_available(ObjectClass *klass);
+
/**
* object_class_is_abstract:
* @klass: The class to obtain the abstractness for.
diff --git a/linux-user/main.c b/linux-user/main.c
index 60a695b7ca3..36d5c6ded4f 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -700,6 +700,7 @@ int main(int argc, char **argv, char **envp)
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qemu_init_cpu_list();
+ module_call_init(MODULE_INIT_TARGET_INFO);
module_call_init(MODULE_INIT_QOM);
envlist = envlist_create();
diff --git a/qom/object.c b/qom/object.c
index b1834a57cc9..14e4c9a094c 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -15,6 +15,8 @@
#include "qom/compat-properties.h"
#include "qom/object.h"
#include "qom/object_interfaces.h"
+#include "qemu/target-info-impl.h"
+#include "qemu/target-info-qapi.h"
#include "qemu/cutils.h"
#include "qemu/memalign.h"
#include "qapi/visitor.h"
@@ -61,6 +63,7 @@ struct TypeImpl
void (*class_base_init)(ObjectClass *klass, const void *data);
const void *class_data;
+ TypeIsAvailable *is_available;
void (*instance_init)(Object *obj);
void (*instance_post_init)(Object *obj);
@@ -83,6 +86,30 @@ static GHashTable *type_table;
static bool enumerating_types;
+static const TargetInfo target_info_none = {
+ .target_arch = SYS_EMU_TARGET_NONE,
+ .target_name = "none",
+};
+
+/* Use TypeInfo.is_available at registration once TargetInfo is selected. */
+static bool target_info_selected = false;
+static const TargetInfo *target_info_ptr = &target_info_none;
+
+const TargetInfo *target_info(void)
+{
+ return target_info_ptr;
+}
+
+void target_info_select(const TargetInfo *ti)
+{
+ g_assert(!target_info_selected);
+ g_assert(ti != NULL);
+ g_assert(ti->target_arch != SYS_EMU_TARGET_NONE);
+
+ target_info_selected = true;
+ target_info_ptr = ti;
+}
+
static void type_table_add(TypeImpl *ti)
{
assert(!enumerating_types);
@@ -116,6 +143,7 @@ static TypeImpl *type_new(const TypeInfo *info)
ti->class_init = info->class_init;
ti->class_base_init = info->class_base_init;
ti->class_data = info->class_data;
+ ti->is_available = info->is_available;
ti->instance_init = info->instance_init;
ti->instance_post_init = info->instance_post_init;
@@ -163,7 +191,8 @@ static TypeImpl *type_register_internal(const TypeInfo
*info)
abort();
}
- if (info->is_available && !info->is_available()) {
+ if (target_info_selected &&
+ info->is_available && !info->is_available(target_info())) {
return NULL;
}
@@ -1149,6 +1178,11 @@ const char *object_class_get_name(ObjectClass *klass)
return klass->type->name;
}
+TypeIsAvailable *object_class_get_is_available(ObjectClass *klass)
+{
+ return klass->type->is_available;
+}
+
ObjectClass *object_class_by_name(const char *typename)
{
TypeImpl *type = type_get_by_name_noload(typename);
diff --git a/target-info-qom.c b/target-info-qom.c
index 6965e4d1169..aba1f954496 100644
--- a/target-info-qom.c
+++ b/target-info-qom.c
@@ -33,13 +33,6 @@ static const TypeInfo target_info_parent_type = {
DEFINE_TARGET_INFO_TYPE(target_info_parent_type)
-static const TargetInfo *target_info_ptr;
-
-const TargetInfo *target_info(void)
-{
- return target_info_ptr;
-}
-
void target_info_qom_set_target(void)
{
g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false);
@@ -51,5 +44,5 @@ void target_info_qom_set_target(void)
"more than one target-info is available");
}
- target_info_ptr = TARGET_INFO_CLASS(targets->data)->target_info;
+ target_info_select(TARGET_INFO_CLASS(targets->data)->target_info);
}
diff --git a/target-info.c b/target-info.c
index 012b384036d..b690ba14e6f 100644
--- a/target-info.c
+++ b/target-info.c
@@ -42,9 +42,9 @@ bool target_big_endian(void)
return target_endian_mode() == ENDIAN_MODE_BIG;
}
-bool target_base_arm(void)
+bool target_base_arm(const TargetInfo *ti)
{
- switch (target_arch()) {
+ switch (ti->target_arch) {
case SYS_EMU_TARGET_ARM:
case SYS_EMU_TARGET_AARCH64:
return true;
@@ -53,19 +53,19 @@ bool target_base_arm(void)
}
}
-bool target_arm(void)
+bool target_arm(const TargetInfo *ti)
{
- return target_arch() == SYS_EMU_TARGET_ARM;
+ return ti->target_arch == SYS_EMU_TARGET_ARM;
}
-bool target_aarch64(void)
+bool target_aarch64(const TargetInfo *ti)
{
- return target_arch() == SYS_EMU_TARGET_AARCH64;
+ return ti->target_arch == SYS_EMU_TARGET_AARCH64;
}
-bool target_base_ppc(void)
+bool target_base_ppc(const TargetInfo *ti)
{
- switch (target_arch()) {
+ switch (ti->target_arch) {
case SYS_EMU_TARGET_PPC:
case SYS_EMU_TARGET_PPC64:
return true;
@@ -74,22 +74,22 @@ bool target_base_ppc(void)
}
}
-bool target_ppc(void)
+bool target_ppc(const TargetInfo *ti)
{
- return target_arch() == SYS_EMU_TARGET_PPC;
+ return ti->target_arch == SYS_EMU_TARGET_PPC;
}
-bool target_ppc64(void)
+bool target_ppc64(const TargetInfo *ti)
{
- return target_arch() == SYS_EMU_TARGET_PPC64;
+ return ti->target_arch == SYS_EMU_TARGET_PPC64;
}
-bool target_s390x(void)
+bool target_s390x(const TargetInfo *ti)
{
- return target_arch() == SYS_EMU_TARGET_S390X;
+ return ti->target_arch == SYS_EMU_TARGET_S390X;
}
-bool target_riscv64(void)
+bool target_riscv64(const TargetInfo *ti)
{
- return target_arch() == SYS_EMU_TARGET_RISCV64;
+ return ti->target_arch == SYS_EMU_TARGET_RISCV64;
}
diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c
index 739500a04fc..e0cd8fd65e6 100644
--- a/target/arm/cpu-max.c
+++ b/target/arm/cpu-max.c
@@ -94,7 +94,7 @@ void aarch64_aa32_a57_init(ARMCPU *cpu, bool aarch64_enabled)
static void cpu_max_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
- const bool aarch64_enabled = target_aarch64();
+ const bool aarch64_enabled = target_aarch64(target_info());
if (hwaccel_enabled()) {
assert(aarch64_enabled);
diff --git a/target/arm/tcg/cpu-max-v8.c b/target/arm/tcg/cpu-max-v8.c
index 65f851f2006..e24cb418373 100644
--- a/target/arm/tcg/cpu-max-v8.c
+++ b/target/arm/tcg/cpu-max-v8.c
@@ -125,6 +125,6 @@ static void cpu_max_v8_register_type(void)
{ .name = "max-v8", .initfn = aarch32_max_v8_tcg_initfn },
{ .name = "max-v8", .initfn = aarch64_max_v8_tcg_initfn },
};
- arm_cpu_register(&max_v8[target_aarch64()]);
+ arm_cpu_register(&max_v8[target_aarch64(target_info())]);
}
type_init(cpu_max_v8_register_type)
--
2.52.0.windows.1
From 991e312d4cfcd86dd57db1375d43cd296f06679a Mon Sep 17 00:00:00 2001
From: Yonggang Luo <[email protected]>
Date: Thu, 3 Sep 2026 16:30:40 +0800
Subject: [PATCH 3/3] system/vl: group -M help by TargetInfo
- For qemu-system with no selected target, print the none TargetInfo
first, then each registered TYPE_TARGET_INFO section.
- Machines with no TypeInfo.is_available stay in the none group.
Machines with a callback appear only under targets it accepts.
- Single-target binaries (exe name or -target) list registered
machines without a section header and without re-checking
is_available, since QOM already filtered types at registration.
---
system/vl.c | 54 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 8 deletions(-)
diff --git a/system/vl.c b/system/vl.c
index 1b22a358d23..03afb6db452 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -1564,10 +1564,46 @@ static gint machine_class_cmp(gconstpointer a,
gconstpointer b, gpointer d)
object_class_get_name(OBJECT_CLASS(mc1)));
}
+static void machine_help_print_target(GSList *machines, const TargetInfo *ti,
+ bool print_header)
+{
+ bool printed = false;
+ GSList *el;
+
+ for (el = machines; el; el = el->next) {
+ MachineClass *mc = el->data;
+ if (print_header) {
+ TypeIsAvailable *is_available =
+ object_class_get_is_available(OBJECT_CLASS(mc));
+
+ if (is_available) {
+ if (!is_available(ti)) {
+ continue;
+ }
+ } else if (ti->target_arch != SYS_EMU_TARGET_NONE) {
+ continue;
+ }
+ if (!printed) {
+ printf("%s:\n", ti->target_name);
+ printed = true;
+ }
+ }
+ if (mc->alias) {
+ printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
+ }
+ printf("%-20s %s%s%s\n", mc->name, mc->desc,
+ mc->is_default ? " (default)" : "",
+ mc->deprecation_reason ? " (deprecated)" : "");
+ }
+
+ if (print_header) {
+ printf("\n");
+ }
+}
+
static void machine_help_func(const QDict *qdict)
{
g_autoptr(GSList) machines = NULL;
- GSList *el;
const char *type = qdict_get_try_str(qdict, "type");
machines = object_class_get_list(TYPE_MACHINE, false);
@@ -1581,14 +1617,16 @@ static void machine_help_func(const QDict *qdict)
printf("Supported machines are:\n");
machines = g_slist_sort_with_data(machines, machine_class_cmp, NULL);
- for (el = machines; el; el = el->next) {
- MachineClass *mc = el->data;
- if (mc->alias) {
- printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
+ if (target_info()->target_arch == SYS_EMU_TARGET_NONE) {
+ g_autoptr(GSList) targets =
+ object_class_get_list_sorted(TYPE_TARGET_INFO, false);
+ machine_help_print_target(machines, target_info(), true);
+ for (GSList *elem = targets; elem; elem = elem->next) {
+ const TargetInfo *ti = TARGET_INFO_CLASS(elem->data)->target_info;
+ machine_help_print_target(machines, ti, true);
}
- printf("%-20s %s%s%s\n", mc->name, mc->desc,
- mc->is_default ? " (default)" : "",
- mc->deprecation_reason ? " (deprecated)" : "");
+ } else {
+ machine_help_print_target(machines, target_info(), false);
}
}
--
2.52.0.windows.1
From 64d48b5ca69ca45c72040b072d54406adef16ca9 Mon Sep 17 00:00:00 2001
From: Yonggang Luo <[email protected]>
Date: Thu, 3 Sep 2026 12:40:07 +0800
Subject: [PATCH 1/3] qapi: add SysEmuTarget none
- Add SysEmuTarget member none as the first enumerator (C value 0)
for when no TargetInfo is selected.
- Document that none is not a qemu-system- executable name.
---
qapi/machine.json | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/qapi/machine.json b/qapi/machine.json
index 2d63c1bac3b..f14b1462ee5 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -22,6 +22,10 @@
# The individual target constants are not documented here, for the
# time being.
#
+# @none: no TargetInfo selected. Not a qemu-system- executable name.
+# Always the first enumerator (C value 0).
+# (since 11.2)
+#
# @rx: since 5.0
#
# @avr: since 5.1
@@ -30,15 +34,16 @@
#
# @hexagon: since 11.0
#
-# .. note:: The resulting QMP strings can be appended to the
-# "qemu-system-" prefix to produce the corresponding QEMU
-# executable name. This is true even for "qemu-system-x86_64".
+# .. note:: Except for ``none``, the resulting QMP strings can be
+# appended to the "qemu-system-" prefix to produce the
+# corresponding QEMU executable name. This is true even for
+# "qemu-system-x86_64".
#
# Since: 3.0
##
{ 'enum' : 'SysEmuTarget',
- 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'hexagon', 'hppa', 'i386',
- 'loongarch64', 'm68k', 'microblaze', 'mips', 'mips64',
+ 'data' : [ 'none', 'aarch64', 'alpha', 'arm', 'avr', 'hexagon', 'hppa',
+ 'i386', 'loongarch64', 'm68k', 'microblaze', 'mips', 'mips64',
'mips64el', 'mipsel', 'or1k', 'ppc',
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
'sh4eb', 'sparc', 'sparc64', 'tricore',
--
2.52.0.windows.1