:p
atchew
Login
We are getting close to be able to link several targets in a single QEMU system binary, and the last obstacle on the road is to embed several TargetInfo in the same binary. The end result of this series is to have a single definition for target_info symbol. This series adds TargetInfo types in QOM, and retrieve them dynamically(). At the moment, we don't deal yet with multiple TargetInfo selection, but install all that is needed to be able to do it easily. Because TargetInfo data is set through class_init, it creates an issue at startup, where we may try to instantiate additional (unrelated) types just to retrieve the list of "target-info-X" types. Those other types class_init may be using target information, to add target specific properties for instance. This issue has been fixed by adding a new object_class_get_list_by_name_prefix that does not force instantiation of all QOM types, but only those matching a specific pattern. This way, we first initialize and retrieve target-info types before others. An alternative would be to leave all this out of QOM, and use startup initializer to add them in a single list. However, because all the single-binary work has been using QOM where possible, it would be really sad to not use it for this final step. Comments are welcome! Finally, sticking to our promise not create a special "single-binary configuration", the goal is to use the *exact* same codepath for normal binaries also. It means that even for existing system binaries, the goal will be to use QOM to retrieve current target, even if there is only one. v5 -- - Fix header guard name for target-info-init.h (TARGET_INFO_INIT_H -> QEMU_TARGET_INFO_INIT_H) - add a new patch to initialize type_table with TYPE_OBJECT and TYPE_INTERFACE, as suggested by Richard - use a single class_init for all target-info-* classes. v4 -- - Revert to v2 MODULE_INIT_TARGET_INFO as Daniel didn't comment on issues about about MODULE_INIT_QOM_EARLY. v3 -- - fix rebase mistake for one header guard - remove MODULE_INIT_TARGET_INFO and introduce MODULE_INIT_QOM_EARLY, as requested by Daniel v2 -- - fix header guards - introduce new module init step (MODULE_INIT_TARGET_INFO) - as a consequence of item above, we need to register TYPE_OBJECT before startup - fix xtensa core type registration using type_init instead of static ctor Pierrick Bouvier (6): qom/object: register OBJECT and INTERFACE QOM types before main qom/object: initialize type_table in static ctor with fundamental QOM types target-info: extract target_info() definition in target-info-init.h target-info-qom: detect target from QOM target-info: replace target_info() in system-mode target-info-qom: use a single class_init for target-info-* classes configs/targets/aarch64-softmmu.c | 6 +-- configs/targets/arm-softmmu.c | 6 +-- include/qemu/module.h | 1 + include/qemu/target-info-init.h | 63 +++++++++++++++++++++++++++++++ include/qemu/target-info-qom.h | 31 +++++++++++++++ qom/object.c | 22 +++-------- system/vl.c | 4 ++ target-info-qom.c | 41 ++++++++++++++++++++ target-info-stub.c | 6 +-- 9 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 include/qemu/target-info-init.h create mode 100644 include/qemu/target-info-qom.h -- 2.43.0
Those types are special, as they are the base of all other QOM types. In next commit, we'll introduce an extra step in module initialization for target-info-* types. However, those types depend on TYPE_OBJECT, which is only registered at MODULE_INIT_QOM step. To avoid having to introduce another step, and modify all code calling module_call_init(MODULE_INIT_QOM), we simply register those base types directly in the static constructor, before anything else. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- qom/object.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qom/object.c b/qom/object.c index XXXXXXX..XXXXXXX 100644 --- a/qom/object.c +++ b/qom/object.c @@ -XXX,XX +XXX,XX @@ static void object_class_init(ObjectClass *klass, const void *data) NULL); } -static void register_types(void) +static void __attribute__((constructor)) register_types(void) { static const TypeInfo interface_info = { .name = TYPE_INTERFACE, @@ -XXX,XX +XXX,XX @@ static void register_types(void) type_interface = type_register_internal(&interface_info); type_register_internal(&object_info); } - -type_init(register_types) -- 2.43.0
This saves us having to check if it's initialized everytime we have to access it. No other QOM type should be initialized or accessed during static ctor calls, so we don't depend on their ordering. Suggested-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- qom/object.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/qom/object.c b/qom/object.c index XXXXXXX..XXXXXXX 100644 --- a/qom/object.c +++ b/qom/object.c @@ -XXX,XX +XXX,XX @@ struct TypeImpl static Type type_interface; -static GHashTable *type_table_get(void) -{ - static GHashTable *type_table; - - if (type_table == NULL) { - type_table = g_hash_table_new(g_str_hash, g_str_equal); - } - - return type_table; -} +static GHashTable *type_table; static bool enumerating_types; static void type_table_add(TypeImpl *ti) { assert(!enumerating_types); - g_hash_table_insert(type_table_get(), (void *)ti->name, ti); + g_hash_table_insert(type_table, (void *)ti->name, ti); } static TypeImpl *type_table_lookup(const char *name) { - return g_hash_table_lookup(type_table_get(), name); + return g_hash_table_lookup(type_table, name); } static TypeImpl *type_new(const TypeInfo *info) @@ -XXX,XX +XXX,XX @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), OCFData data = { fn, implements_type, include_abstract, opaque }; enumerating_types = true; - g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); + g_hash_table_foreach(type_table, object_class_foreach_tramp, &data); enumerating_types = false; } @@ -XXX,XX +XXX,XX @@ static void __attribute__((constructor)) register_types(void) .abstract = true, }; + type_table = g_hash_table_new(g_str_hash, g_str_equal); type_interface = type_register_internal(&interface_info); type_register_internal(&object_info); } -- 2.43.0
This allows us to prepare next commits, which will introduce qom registration for system mode. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- configs/targets/aarch64-softmmu.c | 6 +-- configs/targets/arm-softmmu.c | 6 +-- include/qemu/module.h | 1 + include/qemu/target-info-init.h | 78 +++++++++++++++++++++++++++++++ include/qemu/target-info-qom.h | 28 +++++++++++ system/vl.c | 2 + target-info-qom.c | 14 ++++++ target-info-stub.c | 6 +-- 8 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 include/qemu/target-info-init.h create mode 100644 include/qemu/target-info-qom.h diff --git a/configs/targets/aarch64-softmmu.c b/configs/targets/aarch64-softmmu.c index XXXXXXX..XXXXXXX 100644 --- a/configs/targets/aarch64-softmmu.c +++ b/configs/targets/aarch64-softmmu.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" #include "hw/arm/machines-qom.h" #include "target/arm/cpu-qom.h" #include "target/arm/cpu-param.h" @@ -XXX,XX +XXX,XX @@ static const TargetInfo target_info_aarch64_system = { .page_bits_init = TARGET_PAGE_BITS_LEGACY, }; -const TargetInfo *target_info(void) -{ - return &target_info_aarch64_system; -} +target_info_init(target_info_aarch64_system) diff --git a/configs/targets/arm-softmmu.c b/configs/targets/arm-softmmu.c index XXXXXXX..XXXXXXX 100644 --- a/configs/targets/arm-softmmu.c +++ b/configs/targets/arm-softmmu.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" #include "hw/arm/machines-qom.h" #include "target/arm/cpu-qom.h" #include "target/arm/cpu-param.h" @@ -XXX,XX +XXX,XX @@ static const TargetInfo target_info_arm_system = { .page_bits_init = TARGET_PAGE_BITS_LEGACY, }; -const TargetInfo *target_info(void) -{ - return &target_info_arm_system; -} +target_info_init(target_info_arm_system) diff --git a/include/qemu/module.h b/include/qemu/module.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -XXX,XX +XXX,XX @@ 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-init.h b/include/qemu/target-info-init.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/qemu/target-info-init.h @@ -XXX,XX +XXX,XX @@ +/* + * 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 TYPE_TARGET_INFO_TARGET TYPE_TARGET_INFO"-"TARGET_NAME + +typedef struct TargetInfoQomTarget { + TargetInfoQom parent; +} TargetInfoQomTarget; + +typedef struct TargetInfoQomTargetClass { + TargetInfoQomClass parent_class; +} TargetInfoQomTargetClass; + +OBJECT_DECLARE_TYPE(TargetInfoQomTarget, TargetInfoQomTargetClass, TARGET_INFO_TARGET) + +#define target_info_init(ti_var) \ +const TargetInfo *target_info(void) \ +{ \ + return &ti_var; \ +} \ + \ +static void target_info_qom_class_init(ObjectClass *oc, const void * data) \ +{ \ + TargetInfoQomTargetClass *klass = TARGET_INFO_TARGET_CLASS(oc); \ + klass->parent_class.target_info = &ti_var; \ +} \ + \ +static const TypeInfo target_info_qom_target_type_info = { \ + .name = TYPE_TARGET_INFO_TARGET, \ + .parent = TYPE_TARGET_INFO, \ + .instance_size = sizeof(TargetInfoQomTarget), \ + .class_size = sizeof(TargetInfoQomTargetClass), \ + .class_init = target_info_qom_class_init, \ + .abstract = false, \ +}; \ + \ +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 new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/qemu/target-info-qom.h @@ -XXX,XX +XXX,XX @@ +/* + * 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-impl.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) + +#endif /* QEMU_TARGET_INFO_QOM_H */ diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) os_setup_limits(); + module_call_init(MODULE_INIT_TARGET_INFO); + module_init_info(qemu_modinfo); module_allow_arch(target_name()); diff --git a/target-info-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qom/object.h" +#include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" +#include "qemu/target-info-qom.h" #include "hw/arm/machines-qom.h" static const TypeInfo target_info_types[] = { @@ -XXX,XX +XXX,XX @@ static const TypeInfo target_info_types[] = { }; DEFINE_TYPES(target_info_types) + +static const TypeInfo target_info_parent_type = { + .name = TYPE_TARGET_INFO, + .parent = TYPE_OBJECT, + .instance_size = sizeof(TargetInfoQom), + .class_size = sizeof(TargetInfoQomClass), + .abstract = true, +}; + +DEFINE_TARGET_INFO_TYPE(target_info_parent_type) diff --git a/target-info-stub.c b/target-info-stub.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qemu/target-info.h" #include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" #include "hw/core/boards.h" #include "cpu.h" #include "exec/cpu-defs.h" @@ -XXX,XX +XXX,XX @@ static const TargetInfo target_info_stub = { #endif }; -const TargetInfo *target_info(void) -{ - return &target_info_stub; -} +target_info_init(target_info_stub) -- 2.43.0
For now, we expect only one target to be available at runtime. This will change with the single-binary and we'll detect which one to use dynamically. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- include/qemu/target-info-qom.h | 2 ++ system/vl.c | 2 ++ target-info-qom.c | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/qemu/target-info-qom.h b/include/qemu/target-info-qom.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/target-info-qom.h +++ b/include/qemu/target-info-qom.h @@ -XXX,XX +XXX,XX @@ typedef struct TargetInfoQomClass { OBJECT_DECLARE_TYPE(TargetInfoQom, TargetInfoQomClass, TARGET_INFO) +void target_info_qom_set_target(void); + #endif /* QEMU_TARGET_INFO_QOM_H */ diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ #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" @@ -XXX,XX +XXX,XX @@ 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-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo target_info_parent_type = { }; DEFINE_TARGET_INFO_TYPE(target_info_parent_type) + +static const TargetInfo *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; +} -- 2.43.0
We now can use TargetInfo information available from QOM, and remove duplicated target_info() symbol. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- include/qemu/target-info-init.h | 5 ----- target-info-qom.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/qemu/target-info-init.h b/include/qemu/target-info-init.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/target-info-init.h +++ b/include/qemu/target-info-init.h @@ -XXX,XX +XXX,XX @@ typedef struct TargetInfoQomTargetClass { OBJECT_DECLARE_TYPE(TargetInfoQomTarget, TargetInfoQomTargetClass, TARGET_INFO_TARGET) #define target_info_init(ti_var) \ -const TargetInfo *target_info(void) \ -{ \ - return &ti_var; \ -} \ - \ static void target_info_qom_class_init(ObjectClass *oc, const void * data) \ { \ TargetInfoQomTargetClass *klass = TARGET_INFO_TARGET_CLASS(oc); \ diff --git a/target-info-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ 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); -- 2.43.0
Instead of defining a class_init per class, just use a common constructor and set class_data to corresponding TargetInfo structure. Suggested-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- include/qemu/target-info-init.h | 14 ++------------ include/qemu/target-info-qom.h | 1 + target-info-qom.c | 6 ++++++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/qemu/target-info-init.h b/include/qemu/target-info-init.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/target-info-init.h +++ b/include/qemu/target-info-init.h @@ -XXX,XX +XXX,XX @@ const TargetInfo *target_info(void) \ #include "qemu/target-info-qom.h" #include "qom/object.h" -#define TYPE_TARGET_INFO_TARGET TYPE_TARGET_INFO"-"TARGET_NAME - typedef struct TargetInfoQomTarget { TargetInfoQom parent; } TargetInfoQomTarget; @@ -XXX,XX +XXX,XX @@ typedef struct TargetInfoQomTargetClass { TargetInfoQomClass parent_class; } TargetInfoQomTargetClass; -OBJECT_DECLARE_TYPE(TargetInfoQomTarget, TargetInfoQomTargetClass, TARGET_INFO_TARGET) - #define target_info_init(ti_var) \ -static void target_info_qom_class_init(ObjectClass *oc, const void * data) \ -{ \ - TargetInfoQomTargetClass *klass = TARGET_INFO_TARGET_CLASS(oc); \ - klass->parent_class.target_info = &ti_var; \ -} \ - \ static const TypeInfo target_info_qom_target_type_info = { \ - .name = TYPE_TARGET_INFO_TARGET, \ + .name = TYPE_TARGET_INFO"-"TARGET_NAME, \ .parent = TYPE_TARGET_INFO, \ .instance_size = sizeof(TargetInfoQomTarget), \ .class_size = sizeof(TargetInfoQomTargetClass), \ .class_init = target_info_qom_class_init, \ + .class_data = &ti_var, \ .abstract = false, \ }; \ - \ DEFINE_TARGET_INFO_TYPE(target_info_qom_target_type_info) #endif /* CONFIG_USER_ONLY */ diff --git a/include/qemu/target-info-qom.h b/include/qemu/target-info-qom.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/target-info-qom.h +++ b/include/qemu/target-info-qom.h @@ -XXX,XX +XXX,XX @@ typedef struct TargetInfoQomClass { OBJECT_DECLARE_TYPE(TargetInfoQom, TargetInfoQomClass, TARGET_INFO) +void target_info_qom_class_init(ObjectClass *oc, const void * data); void target_info_qom_set_target(void); #endif /* QEMU_TARGET_INFO_QOM_H */ diff --git a/target-info-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo target_info_parent_type = { DEFINE_TARGET_INFO_TYPE(target_info_parent_type) +void target_info_qom_class_init(ObjectClass *oc, const void * data) +{ + TargetInfoQomClass *klass = TARGET_INFO_CLASS(oc); + klass->target_info = data; +} + static const TargetInfo *target_info_ptr; const TargetInfo *target_info(void) -- 2.43.0
We are getting close to be able to link several targets in a single QEMU system binary, and the last obstacle on the road is to embed several TargetInfo in the same binary. The end result of this series is to have a single definition for target_info symbol. This series adds TargetInfo types in QOM, and retrieve them dynamically(). At the moment, we don't deal yet with multiple TargetInfo selection, but install all that is needed to be able to do it easily. Because TargetInfo data is set through class_init, it creates an issue at startup, where we may try to instantiate additional (unrelated) types just to retrieve the list of "target-info-X" types. Those other types class_init may be using target information, to add target specific properties for instance. This issue has been fixed by adding a new object_class_get_list_by_name_prefix that does not force instantiation of all QOM types, but only those matching a specific pattern. This way, we first initialize and retrieve target-info types before others. An alternative would be to leave all this out of QOM, and use startup initializer to add them in a single list. However, because all the single-binary work has been using QOM where possible, it would be really sad to not use it for this final step. Comments are welcome! Finally, sticking to our promise not create a special "single-binary configuration", the goal is to use the *exact* same codepath for normal binaries also. It means that even for existing system binaries, the goal will be to use QOM to retrieve current target, even if there is only one. v6 -- - Simplify QOM types as suggested by Richard - Use class_base_init + class_data mechanic to initialize target-info pointer v5 -- - Fix header guard name for target-info-init.h (TARGET_INFO_INIT_H -> QEMU_TARGET_INFO_INIT_H) - add a new patch to initialize type_table with TYPE_OBJECT and TYPE_INTERFACE, as suggested by Richard - use a single class_init for all target-info-* classes. v4 -- - Revert to v2 MODULE_INIT_TARGET_INFO as Daniel didn't comment on issues about about MODULE_INIT_QOM_EARLY. v3 -- - fix rebase mistake for one header guard - remove MODULE_INIT_TARGET_INFO and introduce MODULE_INIT_QOM_EARLY, as requested by Daniel v2 -- - fix header guards - introduce new module init step (MODULE_INIT_TARGET_INFO) - as a consequence of item above, we need to register TYPE_OBJECT before startup - fix xtensa core type registration using type_init instead of static ctor Pierrick Bouvier (5): qom/object: register OBJECT and INTERFACE QOM types before main qom/object: initialize type_table in static ctor with fundamental QOM types target-info: introduce TargetInfo in QOM target-info-qom: detect target from QOM target-info: replace target_info() in system-mode configs/targets/aarch64-softmmu.c | 6 ++-- configs/targets/arm-softmmu.c | 6 ++-- include/qemu/module.h | 1 + include/qemu/target-info-init.h | 53 +++++++++++++++++++++++++++++++ include/qemu/target-info-qom.h | 30 +++++++++++++++++ qom/object.c | 22 ++++--------- system/vl.c | 4 +++ target-info-qom.c | 45 ++++++++++++++++++++++++++ target-info-stub.c | 6 ++-- 9 files changed, 145 insertions(+), 28 deletions(-) create mode 100644 include/qemu/target-info-init.h create mode 100644 include/qemu/target-info-qom.h -- 2.43.0
Those types are special, as they are the base of all other QOM types. In next commit, we'll introduce an extra step in module initialization for target-info-* types. However, those types depend on TYPE_OBJECT, which is only registered at MODULE_INIT_QOM step. To avoid having to introduce another step, and modify all code calling module_call_init(MODULE_INIT_QOM), we simply register those base types directly in the static constructor, before anything else. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- qom/object.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qom/object.c b/qom/object.c index XXXXXXX..XXXXXXX 100644 --- a/qom/object.c +++ b/qom/object.c @@ -XXX,XX +XXX,XX @@ static void object_class_init(ObjectClass *klass, const void *data) NULL); } -static void register_types(void) +static void __attribute__((constructor)) register_types(void) { static const TypeInfo interface_info = { .name = TYPE_INTERFACE, @@ -XXX,XX +XXX,XX @@ static void register_types(void) type_interface = type_register_internal(&interface_info); type_register_internal(&object_info); } - -type_init(register_types) -- 2.43.0
This saves us having to check if it's initialized everytime we have to access it. No other QOM type should be initialized or accessed during static ctor calls, so we don't depend on their ordering. Suggested-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- qom/object.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/qom/object.c b/qom/object.c index XXXXXXX..XXXXXXX 100644 --- a/qom/object.c +++ b/qom/object.c @@ -XXX,XX +XXX,XX @@ struct TypeImpl static Type type_interface; -static GHashTable *type_table_get(void) -{ - static GHashTable *type_table; - - if (type_table == NULL) { - type_table = g_hash_table_new(g_str_hash, g_str_equal); - } - - return type_table; -} +static GHashTable *type_table; static bool enumerating_types; static void type_table_add(TypeImpl *ti) { assert(!enumerating_types); - g_hash_table_insert(type_table_get(), (void *)ti->name, ti); + g_hash_table_insert(type_table, (void *)ti->name, ti); } static TypeImpl *type_table_lookup(const char *name) { - return g_hash_table_lookup(type_table_get(), name); + return g_hash_table_lookup(type_table, name); } static TypeImpl *type_new(const TypeInfo *info) @@ -XXX,XX +XXX,XX @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), OCFData data = { fn, implements_type, include_abstract, opaque }; enumerating_types = true; - g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); + g_hash_table_foreach(type_table, object_class_foreach_tramp, &data); enumerating_types = false; } @@ -XXX,XX +XXX,XX @@ static void __attribute__((constructor)) register_types(void) .abstract = true, }; + type_table = g_hash_table_new(g_str_hash, g_str_equal); type_interface = type_register_internal(&interface_info); type_register_internal(&object_info); } -- 2.43.0
For the single-binary, we want to be able to retrieve at runtime the current target among the different ones available. A consequence is that we can't rely on existing target_info() definition since it will create a conflict once more than one target is available. To solve this, we add TargetInfo in QOM, with this hierarchy. We define one class "target-info-X" per target, that inherits from abstract class "target-info". Using concrete vs abstract class ensure we can easily filter "target-info-X" from all QOM types. Associated TargetInfo is directly set through class initialization, without relying on any instance. For user mode, we simply define target_info() like it was done previously. In this patch, we keep the same definition for system-mode also, and it will be replaced in next commits. We will introduce detection of target from QOM, so we need to make sure those types are registered early. Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- configs/targets/aarch64-softmmu.c | 6 ++-- configs/targets/arm-softmmu.c | 6 ++-- include/qemu/module.h | 1 + include/qemu/target-info-init.h | 58 +++++++++++++++++++++++++++++++ include/qemu/target-info-qom.h | 28 +++++++++++++++ system/vl.c | 2 ++ target-info-qom.c | 24 +++++++++++++ target-info-stub.c | 6 ++-- 8 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 include/qemu/target-info-init.h create mode 100644 include/qemu/target-info-qom.h diff --git a/configs/targets/aarch64-softmmu.c b/configs/targets/aarch64-softmmu.c index XXXXXXX..XXXXXXX 100644 --- a/configs/targets/aarch64-softmmu.c +++ b/configs/targets/aarch64-softmmu.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" #include "hw/arm/machines-qom.h" #include "target/arm/cpu-qom.h" #include "target/arm/cpu-param.h" @@ -XXX,XX +XXX,XX @@ static const TargetInfo target_info_aarch64_system = { .page_bits_init = TARGET_PAGE_BITS_LEGACY, }; -const TargetInfo *target_info(void) -{ - return &target_info_aarch64_system; -} +target_info_init(target_info_aarch64_system) diff --git a/configs/targets/arm-softmmu.c b/configs/targets/arm-softmmu.c index XXXXXXX..XXXXXXX 100644 --- a/configs/targets/arm-softmmu.c +++ b/configs/targets/arm-softmmu.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" #include "hw/arm/machines-qom.h" #include "target/arm/cpu-qom.h" #include "target/arm/cpu-param.h" @@ -XXX,XX +XXX,XX @@ static const TargetInfo target_info_arm_system = { .page_bits_init = TARGET_PAGE_BITS_LEGACY, }; -const TargetInfo *target_info(void) -{ - return &target_info_arm_system; -} +target_info_init(target_info_arm_system) diff --git a/include/qemu/module.h b/include/qemu/module.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -XXX,XX +XXX,XX @@ 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-init.h b/include/qemu/target-info-init.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/qemu/target-info-init.h @@ -XXX,XX +XXX,XX @@ +/* + * 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) \ +const TargetInfo *target_info(void) \ +{ \ + return &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 new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/qemu/target-info-qom.h @@ -XXX,XX +XXX,XX @@ +/* + * 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-impl.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) + +#endif /* QEMU_TARGET_INFO_QOM_H */ diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) os_setup_limits(); + module_call_init(MODULE_INIT_TARGET_INFO); + module_init_info(qemu_modinfo); module_allow_arch(target_name()); diff --git a/target-info-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qom/object.h" +#include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" +#include "qemu/target-info-qom.h" #include "hw/arm/machines-qom.h" static const TypeInfo target_info_types[] = { @@ -XXX,XX +XXX,XX @@ static const TypeInfo target_info_types[] = { }; DEFINE_TYPES(target_info_types) + +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) diff --git a/target-info-stub.c b/target-info-stub.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qemu/target-info.h" #include "qemu/target-info-impl.h" +#include "qemu/target-info-init.h" #include "hw/core/boards.h" #include "cpu.h" #include "exec/cpu-defs.h" @@ -XXX,XX +XXX,XX @@ static const TargetInfo target_info_stub = { #endif }; -const TargetInfo *target_info(void) -{ - return &target_info_stub; -} +target_info_init(target_info_stub) -- 2.43.0
For now, we expect only one target to be available at runtime. This will change with the single-binary and we'll detect which one to use dynamically. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- include/qemu/target-info-qom.h | 2 ++ system/vl.c | 2 ++ target-info-qom.c | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/qemu/target-info-qom.h b/include/qemu/target-info-qom.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/target-info-qom.h +++ b/include/qemu/target-info-qom.h @@ -XXX,XX +XXX,XX @@ typedef struct TargetInfoQomClass { OBJECT_DECLARE_TYPE(TargetInfoQom, TargetInfoQomClass, TARGET_INFO) +void target_info_qom_set_target(void); + #endif /* QEMU_TARGET_INFO_QOM_H */ diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ #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" @@ -XXX,XX +XXX,XX @@ 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-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo target_info_parent_type = { }; DEFINE_TARGET_INFO_TYPE(target_info_parent_type) + +static const TargetInfo *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; +} -- 2.43.0
We now can use TargetInfo information available from QOM, and remove duplicated target_info() symbol. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- include/qemu/target-info-init.h | 5 ----- target-info-qom.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/qemu/target-info-init.h b/include/qemu/target-info-init.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/target-info-init.h +++ b/include/qemu/target-info-init.h @@ -XXX,XX +XXX,XX @@ const TargetInfo *target_info(void) \ #include "qom/object.h" #define target_info_init(ti_var) \ -const TargetInfo *target_info(void) \ -{ \ - return &ti_var; \ -} \ - \ static const TypeInfo target_info_qom_target_type_info = { \ .name = TYPE_TARGET_INFO"-"TARGET_NAME, \ .parent = TYPE_TARGET_INFO, \ diff --git a/target-info-qom.c b/target-info-qom.c index XXXXXXX..XXXXXXX 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -XXX,XX +XXX,XX @@ 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); -- 2.43.0