[PATCH v2 11/13] system/vl: add new option -target
Yonggang Luo <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
- Parse -target with QEMU_OPTION_nouserconfig, right after MODULE_INIT_TARGET_INFO, because later init depends on TargetInfo. - target_info_qom_set_target() takes Error **errp. A name comes from -target or from argv0 (qemu-system-aarch64). qemu-system with no suffix and no -target fails; use -target ? to list names. - Fuzz passes TARGET_NAME instead of relying on a unique TargetInfo. Signed-off-by: Pierrick Bouvier <[email protected]> Signed-off-by: Yonggang Luo <[email protected]> --- include/qemu/target-info-qom.h | 3 +- qemu-options.hx | 8 ++++ system/vl.c | 36 ++++++++++++---- target-info-qom.c | 77 ++++++++++++++++++++++++++++++---- tests/qtest/fuzz/fuzz.c | 2 +- 5 files changed, 110 insertions(+), 16 deletions(-) diff --git a/include/qemu/target-info-qom.h b/include/qemu/target-info-qom.h index 842cf241e0a..9e56383ea6b 100644 --- a/include/qemu/target-info-qom.h +++ b/include/qemu/target-info-qom.h @@ -10,6 +10,7 @@ #define QEMU_TARGET_INFO_QOM_H #include "qemu/target-info-impl.h" +#include "qapi/error.h" #include "qom/object.h" #define TYPE_TARGET_INFO "target-info" @@ -40,7 +41,7 @@ typedef struct TargetInfoQomClass { OBJECT_DECLARE_TYPE(TargetInfoQom, TargetInfoQomClass, TARGET_INFO) -void target_info_qom_set_target(void); +void target_info_qom_set_target(const char *name, Error **errp); /** * get_machine_types_available: diff --git a/qemu-options.hx b/qemu-options.hx index 34970fffc94..824807be1d8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -24,6 +24,14 @@ SRST Display version information and exit ERST +DEF("target", HAS_ARG, QEMU_OPTION_target, \ + "-target target selects the target architecture ('-target help' for list)\n", + QEMU_ARCH_ALL) +SRST +``-target target`` + Selects target architecture ('-target help' for list) +ERST + DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop=value[,...]]\n" " selects emulated machine ('-machine help' for list)\n" diff --git a/system/vl.c b/system/vl.c index 4b1fcd2031f..28c5741c385 100644 --- a/system/vl.c +++ b/system/vl.c @@ -281,6 +281,15 @@ static QemuOptsList qemu_accel_opts = { }, }; +static QemuOptsList qemu_target_opts = { + .name = "target", + .implied_opt_name = "target", + .head = QTAILQ_HEAD_INITIALIZER(qemu_target_opts.head), + .desc = { + { /* end of list */ }, + }, +}; + static QemuOptsList qemu_boot_opts = { .name = "boot-opts", .implied_opt_name = "order", @@ -2856,6 +2865,7 @@ void qemu_init(int argc, char **argv) const char *optarg; MachineClass *machine_class; bool userconfig = true; + const char *target_name_option = NULL; FILE *vmstate_dump_file = NULL; qemu_add_opts(&qemu_drive_opts); @@ -2889,6 +2899,7 @@ void qemu_init(int argc, char **argv) qemu_add_opts(&qemu_semihosting_config_opts); qemu_add_opts(&qemu_fw_cfg_opts); qemu_add_opts(&qemu_action_opts); + qemu_add_opts(&qemu_target_opts); qemu_add_run_with_opts(); module_call_init(MODULE_INIT_OPTS); @@ -2898,13 +2909,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()); - - qemu_init_subsystems(); - /* first pass of option parsing */ optind = 1; while (optind < argc) { @@ -2919,10 +2923,25 @@ void qemu_init(int argc, char **argv) case QEMU_OPTION_nouserconfig: userconfig = false; break; + case QEMU_OPTION_target: + target_name_option = optarg; + break; } } } + /* + * Identify target: first from option, then from argv[0]. + * This happens even before handling --help option, because it may contain + * entries that are target specific. + */ + target_info_qom_set_target(target_name_option, &error_fatal); + + module_init_info(qemu_modinfo); + module_allow_arch(target_name()); + + qemu_init_subsystems(); + machine_opts_dict = qdict_new(); if (userconfig) { qemu_read_default_config_file(&error_fatal); @@ -2946,6 +2965,9 @@ void qemu_init(int argc, char **argv) exit(1); } switch(popt->index) { + case QEMU_OPTION_target: + /* handled previously, ignore it here */ + break; case QEMU_OPTION_cpu: /* hw initialization will check this */ cpu_option = optarg; diff --git a/target-info-qom.c b/target-info-qom.c index 68ad734049c..5f7af028749 100644 --- a/target-info-qom.c +++ b/target-info-qom.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "qemu/help_option.h" #include "qapi/error.h" #include "qom/object.h" #include "qemu/target-info-impl.h" @@ -87,16 +88,78 @@ const TargetInfo *target_info(void) return target_info_ptr; } -void target_info_qom_set_target(void) +static void set_target_info(const TargetInfo *chosen) { - g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false); + target_info_ptr = chosen; +} + +static void list_targets_available(void) +{ + printf("List of targets available:\n"); + g_autoptr(GSList) targets = object_class_get_list_sorted(TYPE_TARGET_INFO, false); + for (GSList *elem = targets; elem; elem = elem->next) { + const TargetInfo *ti = TARGET_INFO_CLASS(elem->data)->target_info; + + printf("- %s\n", ti->target_name); + } +} + +static bool target_info_matches_name(const TargetInfo *ti, const char *name) +{ + return !strcmp(name, ti->target_name); +} + +/* qemu-system-aarch64[.exe] -> aarch64; qemu-system[.exe] -> NULL. */ +static const char *target_from_argv0(char *base) +{ + if (g_str_has_prefix(base, "qemu-system-")) { + return base + strlen("qemu-system-"); + } + return NULL; +} +void target_info_qom_set_target(const char *name, Error **errp) +{ + g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false); + g_autofree char *prg_base = 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"); + + if (num_found == 0) { + error_setg(errp, "no target-info is available"); + return; + } + + if (!name) { + const char *prg = g_get_prgname(); + if (prg && prg[0]) { + char *dot; + + prg_base = g_path_get_basename(prg); + dot = strrchr(prg_base, '.'); + if (dot && g_ascii_strcasecmp(dot, ".exe") == 0) { + *dot = '\0'; + } + name = target_from_argv0(prg_base); + } + } + + if (name) { + if (is_help_option(name)) { + list_targets_available(); + exit(0); + } + for (GSList *elem = targets; elem; elem = elem->next) { + const TargetInfo *ti = TARGET_INFO_CLASS(elem->data)->target_info; + if (target_info_matches_name(ti, name)) { + set_target_info(ti); + return; + } + } + error_setg(errp, "target '%s' is not available, " + "use -target ? to list available targets", name); + return; } - target_info_ptr = TARGET_INFO_CLASS(targets->data)->target_info; + error_setg(errp, "no target specified, " + "use -target ? to list available targets"); } diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index a3a131c80f8..c992fab4079 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -174,7 +174,7 @@ 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(); + target_info_qom_set_target(fuzz_arch, &error_fatal); module_call_init(MODULE_INIT_FUZZ_TARGET); module_call_init(MODULE_INIT_QOM); module_call_init(MODULE_INIT_LIBQOS); -- 2.52.0.windows.1