[PATCH 09/12] target-info: register le and be TargetInfo variants
Yonggang Luo <[email protected]>
| Newsgroups | org.nongnu.qemu-devel,org.nongnu.qemu-arm,org.nongnu.qemu-riscv |
|---|---|
| Message-ID | <[email protected]> |
- Register target-info-<name>-le and -be from one system target-info-def.c unit, sharing arch fields. - Mark is_default from TARGET_BIG_ENDIAN so riscv/arm stay LE and ppc/s390x stay BE when -target is omitted. - Pick the unique default in target_info_qom_set_target() when more than one TargetInfo is registered. Leave user-mode as a single target_info(). Signed-off-by: Yonggang Luo <[email protected]> --- include/qemu/target-info-impl.h | 6 ++++ include/qemu/target-info-init.h | 29 +++++++++++++--- target-info-def.c | 61 +++++++++++++++++++++++++-------- target-info-qom.c | 33 ++++++++++++++---- 4 files changed, 104 insertions(+), 25 deletions(-) diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h index de329ec2b86..b4222e4455e 100644 --- a/include/qemu/target-info-impl.h +++ b/include/qemu/target-info-impl.h @@ -23,6 +23,12 @@ typedef struct TargetInfo { const char *cpu_type; /* related to TARGET_BIG_ENDIAN definition */ EndianMode endianness; + /* + * True on the endian variant that matches this translation unit's + * TARGET_BIG_ENDIAN. target_info_qom_set_target() uses this when + * more than one TargetInfo is registered and -target is omitted. + */ + bool is_default; /* * runtime equivalent of * TARGET_PAGE_BITS_VARY ? TARGET_PAGE_BITS_LEGACY : TARGET_PAGE_BITS diff --git a/include/qemu/target-info-init.h b/include/qemu/target-info-init.h index b7024c9faef..25d00adcc66 100644 --- a/include/qemu/target-info-init.h +++ b/include/qemu/target-info-init.h @@ -37,15 +37,34 @@ const TargetInfo *target_info(void) \ #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, \ +/* + * QOM type names are target-info-<TARGET_NAME>-le and -be so both + * endian variants can be registered from one system translation unit. + */ +#define TARGET_INFO_QOM_SUFFIX_0 "-le" +#define TARGET_INFO_QOM_SUFFIX_1 "-be" + +#define TARGET_INFO_QOM_NAME(sel) \ + TYPE_TARGET_INFO "-" TARGET_NAME glue(TARGET_INFO_QOM_SUFFIX_, sel) + +#define TARGET_INFO_QOM_TYPEINFO(ti_var, sel) \ +static const TypeInfo glue(target_info_qom_type_, sel) = { \ + .name = TARGET_INFO_QOM_NAME(sel), \ .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) +} + +#define target_info_init_le_be(ti_le, ti_be) \ +TARGET_INFO_QOM_TYPEINFO(ti_le, 0); \ +TARGET_INFO_QOM_TYPEINFO(ti_be, 1); \ +static void do_qemu_init_target_info(void) \ +{ \ + type_register_static(&target_info_qom_type_0); \ + type_register_static(&target_info_qom_type_1); \ +} \ +module_init(do_qemu_init_target_info, MODULE_INIT_TARGET_INFO) #endif /* CONFIG_USER_ONLY */ #endif /* COMPILING_PER_TARGET */ diff --git a/target-info-def.c b/target-info-def.c index 5d38e405735..6722c43a08f 100644 --- a/target-info-def.c +++ b/target-info-def.c @@ -28,39 +28,72 @@ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); QEMU_BUILD_BUG_ON(TARGET_PAGE_BITS < TARGET_PAGE_BITS_MIN); #endif -static const TargetInfo target_info_def = { - .target_name = TARGET_NAME, - .target_arch = glue(SYS_EMU_TARGET_, TARGET_ARCH), - .long_bits = TARGET_LONG_BITS, - .cpu_type = CPU_RESOLVING_TYPE, - .endianness = TARGET_BIG_ENDIAN ? ENDIAN_MODE_BIG : ENDIAN_MODE_LITTLE, #ifdef TARGET_PAGE_BITS_VARY - .page_bits_vary = true, # ifdef TARGET_PAGE_BITS_LEGACY +# define TARGET_INFO_PAGE_BITS \ + .page_bits_vary = true, \ .page_bits_init = TARGET_PAGE_BITS_LEGACY, +# else +# define TARGET_INFO_PAGE_BITS \ + .page_bits_vary = true, # endif #else - .page_bits_vary = false, +# define TARGET_INFO_PAGE_BITS \ + .page_bits_vary = false, \ .page_bits_init = TARGET_PAGE_BITS, #endif #ifndef CONFIG_USER_ONLY # ifdef CONFIG_MULTIPROCESS - .config_multiprocess = true, +# define TARGET_INFO_CONFIG_MULTIPROCESS .config_multiprocess = true, # else - .config_multiprocess = false, +# define TARGET_INFO_CONFIG_MULTIPROCESS .config_multiprocess = false, # endif # ifdef CONFIG_NITRO - .config_nitro = true, +# define TARGET_INFO_CONFIG_NITRO .config_nitro = true, # else - .config_nitro = false, +# define TARGET_INFO_CONFIG_NITRO .config_nitro = false, # endif # ifdef CONFIG_XEN - .config_xen = true, +# define TARGET_INFO_CONFIG_XEN .config_xen = true, # else - .config_xen = false, +# define TARGET_INFO_CONFIG_XEN .config_xen = false, # endif +# define TARGET_INFO_CONFIG \ + TARGET_INFO_CONFIG_MULTIPROCESS \ + TARGET_INFO_CONFIG_NITRO \ + TARGET_INFO_CONFIG_XEN +#else +# define TARGET_INFO_CONFIG #endif + +#define TARGET_INFO_COMMON \ + .target_name = TARGET_NAME, \ + .target_arch = glue(SYS_EMU_TARGET_, TARGET_ARCH), \ + .long_bits = TARGET_LONG_BITS, \ + .cpu_type = CPU_RESOLVING_TYPE, \ + TARGET_INFO_PAGE_BITS \ + TARGET_INFO_CONFIG + +#ifdef CONFIG_USER_ONLY +static const TargetInfo target_info_def = { + TARGET_INFO_COMMON + .endianness = TARGET_BIG_ENDIAN ? ENDIAN_MODE_BIG : ENDIAN_MODE_LITTLE, }; target_info_init(target_info_def) +#else +static const TargetInfo target_info_le = { + TARGET_INFO_COMMON + .endianness = ENDIAN_MODE_LITTLE, + .is_default = !TARGET_BIG_ENDIAN, +}; + +static const TargetInfo target_info_be = { + TARGET_INFO_COMMON + .endianness = ENDIAN_MODE_BIG, + .is_default = TARGET_BIG_ENDIAN, +}; + +target_info_init_le_be(target_info_le, target_info_be) +#endif diff --git a/target-info-qom.c b/target-info-qom.c index 68ad734049c..2c1c57b05fd 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -90,13 +90,34 @@ const TargetInfo *target_info(void) void target_info_qom_set_target(void) { g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false); - + const TargetInfo *chosen = NULL; 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"); + size_t num_default = 0; + + if (num_found == 0) { + error_setg(&error_fatal, "no target-info is available"); + } + + if (num_found == 1) { + target_info_ptr = TARGET_INFO_CLASS(targets->data)->target_info; + return; + } + + for (GSList *l = targets; l; l = l->next) { + const TargetInfo *ti = TARGET_INFO_CLASS(l->data)->target_info; + + if (ti->is_default) { + num_default++; + chosen = ti; + } + } + + if (num_default != 1) { + error_setg(&error_fatal, num_default == 0 ? + "no default target-info is available" : + "more than one default target-info " + "is available"); } - target_info_ptr = TARGET_INFO_CLASS(targets->data)->target_info; + target_info_ptr = chosen; } -- 2.52.0.windows.1