>
> > 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

Reply via email to