Match -machine $target_arch-$machine_name against registered machine
names and aliases. Also accept -machine $machine_name when it uniquely
identifies a machine; report architecture-qualified choices when it is
ambiguous.

This do not change single-target behavior.

Signed-off-by: Yonggang Luo <[email protected]>
---
 system/vl.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 124 insertions(+), 9 deletions(-)

diff --git a/system/vl.c b/system/vl.c
index e2bd65ebd40..5d6ba08b591 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -1205,6 +1205,77 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, 
Error **errp)
     return 0;
 }
 
+static bool machine_target_matches(MachineClass *mc, const TargetInfo *ti,
+                                   const char *name)
+{
+    const char *names[] = { mc->name, mc->alias };
+
+    for (unsigned i = 0; i < ARRAY_SIZE(names); i++) {
+        if (names[i]) {
+            if (!strcmp(name, names[i])) {
+                return true;
+            }
+            g_autofree char *qualified =
+                g_strdup_printf("%s-%s", ti->target_name, names[i]);
+
+            if (!strcmp(name, qualified)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+static MachineClass *machine_target_select(GSList *machines, GSList **targets,
+                                           const char *name, Error **errp)
+{
+    ERRP_GUARD();
+    MachineClass *machine = NULL;
+    const TargetInfo *target = NULL;
+    g_autoptr(GString) hints = g_string_new(NULL);
+    unsigned count = 0;
+    GSList *el;
+    GSList *tel;
+
+    *targets = object_class_get_list(TYPE_TARGET_INFO, false);
+    if (!name) {
+        return NULL;
+    }
+
+    for (el = machines; el; el = el->next) {
+        MachineClass *mc = el->data;
+
+        for (tel = *targets; tel; tel = tel->next) {
+            const TargetInfo *ti = TARGET_INFO_CLASS(tel->data)->target_info;
+
+            if ((mc->targets & QEMU_ARCH_BIT(ti->target_arch)) &&
+                machine_target_matches(mc, ti, name)) {
+                count++;
+                machine = mc;
+                target = ti;
+                g_string_append_printf(hints, "  -machine %s-%s\n",
+                                       ti->target_name, mc->name);
+            }
+        }
+    }
+    if (!count) {
+        error_setg(errp, "unsupported machine type: \"%s\"", name);
+        error_append_hint(errp, "Use -machine help to list supported names, "
+                          "then select <arch>-<machine-name> or an "
+                          "unambiguous <machine-name>\n");
+        return NULL;
+    }
+    if (count != 1) {
+        error_setg(errp, "machine name '%s' is ambiguous", name);
+        error_append_hint(errp, "Select an architecture-prefixed name:\n%s",
+                          hints->str);
+        return NULL;
+    }
+
+    target_info_qom_set_target_info(target);
+    return machine;
+}
+
 static int device_help_func(void *opaque, QemuOpts *opts, Error **errp)
 {
     return qdev_device_help(opts);
@@ -1565,16 +1636,23 @@ static gint machine_class_cmp(gconstpointer a, 
gconstpointer b, gpointer d)
 static void machine_help_func(const QDict *qdict)
 {
     g_autoptr(GSList) machines = NULL;
+    g_autoptr(GSList) targets = NULL;
     GSList *el;
+    GSList *tel;
     const char *type = qdict_get_try_str(qdict, "type");
+    MachineClass *machine_class = NULL;
 
     machines = object_class_get_list(TYPE_MACHINE, false);
-    if (type) {
-        ObjectClass *machine_class = OBJECT_CLASS(find_machine(type, 
machines));
-        if (machine_class) {
-            type_print_class_properties(object_class_get_name(machine_class));
-            return;
-        }
+    if (target_combined_binary()) {
+        machine_class = machine_target_select(machines, &targets, type,
+                                              &error_fatal);
+    } else if (type) {
+        machine_class = find_machine(type, machines);
+    }
+    if (machine_class) {
+        type_print_class_properties(
+            object_class_get_name(OBJECT_CLASS(machine_class)));
+        return;
     }
 
     printf("Supported machines are:\n");
@@ -1585,9 +1663,20 @@ static void machine_help_func(const QDict *qdict)
             printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
         }
         printf("%-20s %s%s%s%s\n", mc->name, mc->desc,
-               mc->is_default ? " (default)" : "",
+               mc->is_default && !target_combined_binary() ? " (default)" : "",
                mc->deprecation_reason ? " (deprecated)" : "",
                object_class_is_secure(OBJECT_CLASS(mc)) ? " (secure)" : "");
+        for (tel = targets; tel; tel = tel->next) {
+            const TargetInfo *ti = TARGET_INFO_CLASS(tel->data)->target_info;
+
+            if (mc->targets & QEMU_ARCH_BIT(ti->target_arch)) {
+                printf("  %s-%s\n", ti->target_name, mc->name);
+                if (mc->alias && strcmp(mc->name, mc->alias)) {
+                    printf("  %s-%s (alias)\n",
+                           ti->target_name, mc->alias);
+                }
+            }
+        }
     }
 }
 
@@ -1684,6 +1773,26 @@ static MachineClass *select_machine(QDict *qdict, Error 
**errp)
     g_autoptr(GSList) machines = object_class_get_list(TYPE_MACHINE, false);
     MachineClass *machine_class = NULL;
 
+    if (target_combined_binary()) {
+        g_autoptr(GSList) targets = NULL;
+
+        if (!machine_type) {
+            error_setg(errp, "No machine specified; combined binaries "
+                       "have no default machine");
+            error_append_hint(errp,
+                              "Use -machine help to list supported names, "
+                              "then select <arch>-<machine-name> or an "
+                              "unambiguous <machine-name>\n");
+            return NULL;
+        }
+        machine_class = machine_target_select(machines, &targets, machine_type,
+                                              errp);
+        if (machine_class) {
+            qdict_del(qdict, "type");
+        }
+        return machine_class;
+    }
+
     if (machine_type) {
         machine_class = find_machine(machine_type, machines);
         if (!machine_class) {
@@ -2913,10 +3022,16 @@ void qemu_init(int argc, char **argv)
     os_setup_limits();
 
     target_info_qom_init();
-    target_info_qom_set_target();
+    if (!target_combined_binary()) {
+        target_info_qom_set_target();
+    }
 
     module_init_info(qemu_modinfo);
-    module_allow_arch(target_name());
+    if (target_combined_binary()) {
+        module_allow_all_arch();
+    } else {
+        module_allow_arch(target_name());
+    }
 
     qemu_init_subsystems();
 
-- 
2.55.0.windows.3


Reply via email to