@@ -282,6 +282,10 @@
#
# @alias-of: Name of CPU model this model is an alias for. The target of the
# CPU model alias may change depending on the machine type.
+# If the @machine argument was provided to query-cpu-definitions,
+# alias information for that machine type will be returned.
+# If @machine is not provided, alias information for
+# the current machine will be returned.
# Management software is supposed to translate CPU model aliases
# in the VM configuration, because aliases may stop being
# migration-safe in the future (since 4.1)
@@ -318,9 +322,17 @@
#
# Return a list of supported virtual CPU definitions
#
+# @machine: Name of machine type. The value of the @alias-of field
+# is machine-specific. This overrides the machine type
+# used to look up that information. This can be used
+# to query machine-specific CPU model aliases without
+# restarting QEMU (since 5.2)
+#
# Returns: a list of CpuDefInfo
#
# Since: 1.2.0
##
-{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'],
+{ 'command': 'query-cpu-definitions',
+ 'data': { '*machine': 'str' },
+ 'returns': ['CpuDefinitionInfo'],
'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
@@ -8276,7 +8276,9 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
*cpu_list = entry;
}
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(bool has_machine,
+ const char *machine,
+ Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
GSList *list;
@@ -56,6 +56,7 @@
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
#include "hw/i386/apic_internal.h"
+#include "hw/i386/pc.h"
#include "hw/boards.h"
#endif
@@ -4187,6 +4188,13 @@ static char *x86_cpu_model_resolve_alias(const X86CPUModel *model,
}
return x86_cpu_versioned_model_name(model->cpudef, version);
}
+
+static X86CPUVersion default_cpu_version_for_machine(MachineClass *mc)
+{
+ PCMachineClass *pcmc =
+ (PCMachineClass *)object_class_dynamic_cast(OBJECT_CLASS(mc), TYPE_PC_MACHINE);
+ return pcmc ? pcmc->default_cpu_version : 1;
+}
#endif
void x86_cpu_change_kvm_default(const char *prop, const char *value)
@@ -5027,12 +5035,24 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
args->cpu_list = entry;
}
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(bool has_machine,
+ const char *machine,
+ Error **errp)
{
X86CPUDefinitionArgs args = { .cpu_list = NULL };
GSList *list = get_sorted_cpu_model_list();
- args.default_version = default_cpu_version;
+ if (!has_machine) {
+ args.default_version = default_cpu_version;
+ } else {
+ MachineClass *mc = machine_find_class(machine);
+ if (!mc) {
+ error_setg(errp, "Machine type '%s' not found", machine);
+ return NULL;
+ }
+ args.default_version = default_cpu_version_for_machine(mc);
+ }
+
g_slist_foreach(list, x86_cpu_definition_entry, &args);
g_slist_free(list);
return args.cpu_list;
@@ -1518,7 +1518,9 @@ static void mips_cpu_add_definition(gpointer data, gpointer user_data)
*cpu_list = entry;
}
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(bool has_machine,
+ const char *machine,
+ Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
GSList *list;
@@ -456,7 +456,9 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
*cpu_list = entry;
}
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(bool has_machine,
+ const char *machine,
+ Error **errp)
{
struct CpuDefinitionInfoListData list_data = {
.list = NULL,
@@ -10635,7 +10635,9 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
*first = entry;
}
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(bool has_machine,
+ const char *machine,
+ Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
GSList *list;
@@ -238,6 +238,54 @@ class X86CPUModelAliases(avocado_qemu.Test):
self.validate_aliases(cpus)
+ def test_machine_arg_none(self):
+ """Check results using explicit machine=none argument"""
+ vm1 = self.get_vm()
+ vm1.add_args('-S')
+ vm1.set_machine('pc-i440fx-4.0')
+ vm1.launch()
+ cpus1 = dict((m['name'], m.get('alias-of'))
+ for m in vm1.command('query-cpu-definitions',
+ machine='none'))
+ vm1.shutdown()
+
+ vm2 = self.get_vm()
+ vm2.add_args('-S')
+ vm2.set_machine('none')
+ vm2.launch()
+ cpus2 = dict((m['name'], m.get('alias-of'))
+ for m in vm2.command('query-cpu-definitions'))
+ vm1.shutdown()
+
+ self.assertEquals(cpus1, cpus2)
+
+ def test_machine_arg_4_1(self):
+ """Check results using explicit machine=pc-i440fx-4.1 argument"""
+ vm1 = self.get_vm()
+ vm1.add_args('-S')
+ vm1.set_machine('pc-i440fx-4.0')
+ vm1.launch()
+ cpus1 = dict((m['name'], m.get('alias-of'))
+ for m in vm1.command('query-cpu-definitions',
+ machine='pc-i440fx-4.1'))
+ vm1.shutdown()
+
+ vm2 = self.get_vm()
+ vm2.add_args('-S')
+ vm2.set_machine('pc-i440fx-4.1')
+ vm2.launch()
+ cpus2 = dict((m['name'], m.get('alias-of'))
+ for m in vm2.command('query-cpu-definitions'))
+ vm1.shutdown()
+
+ self.assertEquals(cpus1, cpus2)
+
+ def test_invalid_machine(self):
+ self.vm.add_args('-S')
+ self.vm.launch()
+ r = self.vm.qmp('query-cpu-definitions', machine='invalid-machine-123')
+ self.assertIn('error', r)
+
class CascadelakeArchCapabilities(avocado_qemu.Test):
"""
The new parameter can be used by management software to query for CPU model alias information for multiple machines without restarting QEMU. Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- Changes v1 -> v2: * Rewrite documentation, with suggestions from Markus --- qapi/machine-target.json | 14 ++++++- target/arm/helper.c | 4 +- target/i386/cpu.c | 24 ++++++++++- target/mips/helper.c | 4 +- target/s390x/cpu_models.c | 4 +- target/ppc/translate_init.c.inc | 4 +- tests/acceptance/x86_cpu_model_versions.py | 48 ++++++++++++++++++++++ 7 files changed, 95 insertions(+), 7 deletions(-)