Register target definitions through constructors instead of MODULE_INIT_TARGET_INFO, making target_info_list() and target_info() available on entry to main(), without explicit initialization or a call to module_call_init(MODULE_INIT_QOM).
Keep the target list sorted by target_arch and default to its first entry. Provide an unknown TargetInfo fallback for target-independent tools such as qemu-img and unit tests that link no target-info-def.c objects. Remove the obsolete QOM target-info registration infrastructure and update the multi-target test to inspect target information before initializing QOM. Signed-off-by: Yonggang Luo <[email protected]> --- include/qemu/module.h | 1 - include/qemu/target-info-def.h | 56 +++++++++++++++++++++++++++--- include/qemu/target-info-init.h | 53 ---------------------------- include/qemu/target-info-qom.h | 31 ----------------- include/qemu/target-info.h | 9 +++++ meson.build | 6 ++-- system/vl.c | 4 --- target-info-def.c | 1 - target-info-qom.c | 60 -------------------------------- target-info.c | 61 ++++++++++++++++++++++++++++++++- tests/qtest/fuzz/fuzz.c | 3 -- tests/unit/test-multi-target.c | 12 +++---- 12 files changed, 129 insertions(+), 168 deletions(-) delete mode 100644 include/qemu/target-info-init.h delete mode 100644 include/qemu/target-info-qom.h delete mode 100644 target-info-qom.c diff --git a/include/qemu/module.h b/include/qemu/module.h index fccf017bf9e..9885ac9afb3 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -43,7 +43,6 @@ typedef enum { MODULE_INIT_MIGRATION, MODULE_INIT_BLOCK, MODULE_INIT_OPTS, - MODULE_INIT_TARGET_INFO, MODULE_INIT_QOM, MODULE_INIT_TRACE, MODULE_INIT_XEN_BACKEND, diff --git a/include/qemu/target-info-def.h b/include/qemu/target-info-def.h index 8019d2c7196..080e30a5b0e 100644 --- a/include/qemu/target-info-def.h +++ b/include/qemu/target-info-def.h @@ -11,8 +11,10 @@ #include "qapi/qapi-types-common.h" #include "qapi/qapi-types-machine.h" +#include "qemu/queue.h" +#include "qemu/target-info.h" -typedef struct TargetInfo { +struct TargetInfo { /* runtime equivalent of TARGET_NAME definition */ const char *target_name; /* related to TARGET_ARCH definition */ @@ -30,13 +32,57 @@ typedef struct TargetInfo { unsigned page_bits_init; /* runtime equivalent of TARGET_PAGE_BITS_VARY definition */ bool page_bits_vary; -} TargetInfo; +}; + +typedef struct TargetInfoNode TargetInfoNode; +typedef QLIST_HEAD(, TargetInfoNode) TargetInfoList; + +struct TargetInfoNode { + const TargetInfo *info; + QLIST_ENTRY(TargetInfoNode) next; +}; + +/** + * target_info_list: + * + * TargetInfo is a static list, not a QOM type. Constructors insert + * entries before main(), so type_init can use it. + * + * Returns: registered TargetInfoNode list head, sorted by + * info->target_arch. The list is owned by target-info + * and must not be modified. Iterate with + * QLIST_FOREACH(..., next) and use node->info. + */ +const TargetInfoList *target_info_list(void); /** - * target_info: + * target_info_select: + * @ti: TargetInfo to make current * - * Returns: The TargetInfo structure definition for this target binary. + * Sets target_info() to @ti. + */ +void target_info_select(const TargetInfo *ti); + +/** + * target_info_list_add: + * @node: static TargetInfoNode whose info points at a const TargetInfo + * + * Inserts @node into target_info_list(), sorted by info->target_arch. + * Sets target_info() to the first list entry. + */ +void target_info_list_add(TargetInfoNode *node); + +/* + * Register @ti before main(). Linked into the executable, not a DSO. + * @ti is a unique identifier in this translation unit. */ -const TargetInfo *target_info(void); +#define target_info_init(ti) \ + static TargetInfoNode ti##_node = { \ + .info = &(ti), \ + }; \ + static void __attribute__((constructor)) do_qemu_init_##ti(void) \ + { \ + target_info_list_add(&ti##_node); \ + } #endif diff --git a/include/qemu/target-info-init.h b/include/qemu/target-info-init.h deleted file mode 100644 index b7024c9faef..00000000000 --- a/include/qemu/target-info-init.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * QEMU target info initialization - * - * Copyright (c) Qualcomm - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * This file is included by each file defining a TargetInfo structure and is - * responsible for registering it. - */ - -#ifndef QEMU_TARGET_INFO_INIT_H -#define QEMU_TARGET_INFO_INIT_H - -#define DEFINE_TARGET_INFO_TYPE(info) \ -static void do_qemu_init_target_info(void) \ -{ \ - type_register_static(&info); \ -} \ -module_init(do_qemu_init_target_info, MODULE_INIT_TARGET_INFO) - -#ifdef COMPILING_PER_TARGET -#ifdef CONFIG_USER_ONLY - -/* - * User mode does not support multiple targets in the same binary, so just - * define target_info(). - */ -#define target_info_init(ti_var) \ -const TargetInfo *target_info(void) \ -{ \ - return &ti_var; \ -} - -#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 = { \ - .name = TYPE_TARGET_INFO"-"TARGET_NAME, \ - .parent = TYPE_TARGET_INFO, \ - .instance_size = sizeof(TargetInfoQom), \ - .class_size = sizeof(TargetInfoQomClass), \ - .class_data = &ti_var, \ -}; \ -DEFINE_TARGET_INFO_TYPE(target_info_qom_target_type_info) - -#endif /* CONFIG_USER_ONLY */ -#endif /* COMPILING_PER_TARGET */ - -#endif /* QEMU_TARGET_INFO_INIT_H */ diff --git a/include/qemu/target-info-qom.h b/include/qemu/target-info-qom.h deleted file mode 100644 index ba2e4370afb..00000000000 --- a/include/qemu/target-info-qom.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * QEMU target info QOM types - * - * Copyright (c) Qualcomm - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef QEMU_TARGET_INFO_QOM_H -#define QEMU_TARGET_INFO_QOM_H - -#include "qemu/target-info-def.h" -#include "qom/object.h" - -#define TYPE_TARGET_INFO "target-info" - -typedef struct TargetInfoQom { - Object parent_obj; -} TargetInfoQom; - -typedef struct TargetInfoQomClass { - ObjectClass parent_class; - const TargetInfo *target_info; -} TargetInfoQomClass; - -OBJECT_DECLARE_TYPE(TargetInfoQom, TargetInfoQomClass, TARGET_INFO) - -void target_info_qom_set_target(void); -void target_info_qom_set_target_info(const TargetInfo *ti); - -#endif /* QEMU_TARGET_INFO_QOM_H */ diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h index adda363ac39..d1928cecf84 100644 --- a/include/qemu/target-info.h +++ b/include/qemu/target-info.h @@ -9,6 +9,15 @@ #ifndef QEMU_TARGET_INFO_H #define QEMU_TARGET_INFO_H +typedef struct TargetInfo TargetInfo; + +/** + * target_info: + * + * Returns: The TargetInfo structure definition for the selected target. + */ +const TargetInfo *target_info(void); + /** * target_name: * diff --git a/meson.build b/meson.build index ac78c58cb91..4097784e7a2 100644 --- a/meson.build +++ b/meson.build @@ -3777,6 +3777,9 @@ if enable_modules modulecommon = declare_dependency(objects: libmodulecommon.extract_all_objects(recursive: false), compile_args: '-DBUILD_DSO') endif +qom_ss.add(files( + 'target-info.c', +)) qom_ss = qom_ss.apply({}) libqom = static_library('qom', qom_ss.sources() + genh, dependencies: [qom_ss.dependencies()], @@ -3869,9 +3872,6 @@ endif common_ss.add(pagevary) system_ss.add(files('page-vary-system.c')) -common_ss.add(files('target-info.c')) -system_ss.add(files('target-info-qom.c')) - if 'CONFIG_TCG' in config_all_accel subdir('contrib/plugins') endif diff --git a/system/vl.c b/system/vl.c index 468a9fc247a..2c50aa01a2e 100644 --- a/system/vl.c +++ b/system/vl.c @@ -28,7 +28,6 @@ #include "qemu/units.h" #include "qemu/module.h" #include "qemu/target-info.h" -#include "qemu/target-info-qom.h" #include "exec/cpu-common.h" #include "exec/page-vary.h" #include "hw/core/qdev-properties.h" @@ -2914,9 +2913,6 @@ void qemu_init(int argc, char **argv) os_setup_limits(); - module_call_init(MODULE_INIT_TARGET_INFO); - target_info_qom_set_target(); - module_init_info(qemu_modinfo); module_allow_arch(target_name()); diff --git a/target-info-def.c b/target-info-def.c index fa19cabc55f..3041d64ccd2 100644 --- a/target-info-def.c +++ b/target-info-def.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qemu/target-info.h" #include "qemu/target-info-def.h" -#include "qemu/target-info-init.h" #include "hw/core/boards.h" #include "cpu.h" #include "exec/cpu-defs.h" diff --git a/target-info-qom.c b/target-info-qom.c deleted file mode 100644 index aeeedb7e818..00000000000 --- a/target-info-qom.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * QEMU binary/target API (QOM types) - * - * Copyright (c) Linaro - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qom/object.h" -#include "qemu/target-info-def.h" -#include "qemu/target-info-init.h" -#include "qemu/target-info-qom.h" - -static void target_info_qom_class_init(ObjectClass *oc, const void * data) -{ - TargetInfoQomClass *klass = TARGET_INFO_CLASS(oc); - klass->target_info = data; -} - -static const TypeInfo target_info_parent_type = { - .name = TYPE_TARGET_INFO, - .parent = TYPE_OBJECT, - .instance_size = sizeof(TargetInfoQom), - .class_size = sizeof(TargetInfoQomClass), - /* use class_base_init so children classes can set class_data accordingly */ - .class_base_init = target_info_qom_class_init, - /* children classes will be concrete, which allows to easily query them - * without listing this parent class also */ - .abstract = true, -}; - -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); - - size_t num_found = g_slist_length(targets); - if (num_found != 1) { - error_setg(&error_fatal, num_found == 0 ? - "no target-info is available" : - "more than one target-info is available"); - } - - target_info_ptr = TARGET_INFO_CLASS(targets->data)->target_info; -} - -void target_info_qom_set_target_info(const TargetInfo *ti) -{ - target_info_ptr = ti; -} diff --git a/target-info.c b/target-info.c index 6b365113955..8ccb333e365 100644 --- a/target-info.c +++ b/target-info.c @@ -10,7 +10,66 @@ #include "qemu/target-info.h" #include "qemu/target-info-qapi.h" #include "qemu/target-info-def.h" -#include "qapi/error.h" +#include "exec/page-vary.h" + +/* + * Tools such as qemu-img and unit tests may link target-info.c without any + * target-info-def.c objects. Their target list remains empty, so use this + * fallback. + */ +static const TargetInfo target_info_default = { + .target_arch = SYS_EMU_TARGET__MAX, + .target_name = "unknown", + .long_bits = 64, + .endianness = ENDIAN_MODE_LITTLE, + .page_bits_init = TARGET_PAGE_BITS_MIN, +}; + +static const TargetInfo *target_info_ptr = &target_info_default; +static TargetInfoList target_infos = QLIST_HEAD_INITIALIZER(target_infos); + +const TargetInfo *target_info(void) +{ + g_assert(target_info_ptr != NULL); + return target_info_ptr; +} + +const TargetInfoList *target_info_list(void) +{ + return &target_infos; +} + +void target_info_select(const TargetInfo *ti) +{ + g_assert(ti != NULL); + target_info_ptr = ti; +} + +void target_info_list_add(TargetInfoNode *node) +{ + const TargetInfo *info; + TargetInfoNode *cur, *prev = NULL; + + g_assert(node && node->info); + info = node->info; + QLIST_FOREACH(cur, &target_infos, next) { + if (info->target_arch < cur->info->target_arch) { + QLIST_INSERT_BEFORE(cur, node, next); + break; + } + prev = cur; + } + if (!cur) { + if (prev) { + QLIST_INSERT_AFTER(prev, node, next); + } else { + QLIST_INSERT_HEAD(&target_infos, node, next); + } + } + + /* Default to the first entry in the target_arch-sorted list. */ + target_info_select(QLIST_FIRST(&target_infos)->info); +} const char *target_name(void) { diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index a3a131c80f8..d2355989616 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -22,7 +22,6 @@ #include "system/runstate.h" #include "qemu/main-loop.h" #include "qemu/rcu.h" -#include "qemu/target-info-qom.h" #include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/qgraph.h" #include "fuzz.h" @@ -173,8 +172,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) /* Initialize qgraph and modules */ qos_graph_init(); - module_call_init(MODULE_INIT_TARGET_INFO); - target_info_qom_set_target(); module_call_init(MODULE_INIT_FUZZ_TARGET); module_call_init(MODULE_INIT_QOM); module_call_init(MODULE_INIT_LIBQOS); diff --git a/tests/unit/test-multi-target.c b/tests/unit/test-multi-target.c index 89b55bb1632..150254a3ba3 100644 --- a/tests/unit/test-multi-target.c +++ b/tests/unit/test-multi-target.c @@ -15,7 +15,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "qemu/target-info.h" -#include "qemu/target-info-qom.h" +#include "qemu/target-info-def.h" #include "qom/object.h" #ifdef CONFIG_SDL @@ -32,11 +32,11 @@ int (*qemu_main)(void); static void test_qom_types_are_unique(void) { - module_call_init(MODULE_INIT_TARGET_INFO); - g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false); - g_assert(targets); - const TargetInfo *first_ti = TARGET_INFO_CLASS(targets->data)->target_info; - target_info_qom_set_target_info(first_ti); + const TargetInfoList *targets = target_info_list(); + + g_assert_nonnull(QLIST_FIRST(targets)); + + g_assert_nonnull(target_info()); /* register all types */ module_call_init(MODULE_INIT_QOM); -- 2.55.0.windows.3
