Introduce the 'query-cpu-props-info' QMP command. For CPU model
properties it reports the type (boolean or number) and the set of values
supported under the active accelerator and host.
For numbers the supported values are expressed as a list of inclusive
{min, max} ranges; for booleans as the list of allowed true/false
values.
The command and its return types (CpuPropertyType, CpuPropertyInfo and
friends) are defined in qapi/machine.json rather than an Arm-specific
schema, since the concept applies to other targets (e.g. x86, riscv)
too. Target that do not implement it return an error.
The Arm/KVM implementation spins up a scratch "host" vCPU object,
walks its QOM properties: SYSREG_ ID-register fields become 'number'
properties whose ranges come from arm_field_get_supported_values(),
and the advertised feature toggles become 'boolean' properties.
Signed-off-by: Khushit Shah <[email protected]>
---
qapi/machine.json | 87 ++++++++++++++++++++++++++++++++++++
stubs/meson.build | 1 +
stubs/qmp-cpu-props-info.c | 12 +++++
target/arm/arm-qmp-cmds.c | 90 ++++++++++++++++++++++++++++++++++++++
target/arm/kvm-stub.c | 7 +++
5 files changed, 197 insertions(+)
create mode 100644 stubs/qmp-cpu-props-info.c
diff --git a/qapi/machine.json b/qapi/machine.json
index 685e4e29b8..362efe4c50 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -2251,3 +2251,90 @@
# Since: 1.2
##
{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
+
+##
+# @CpuPropertyType:
+#
+# The type of a CPU model property value.
+#
+# @boolean: the property is an on/off toggle.
+#
+# @number: the property is an unsigned integer.
+#
+# Since: 11.1
+##
+{ 'enum': 'CpuPropertyType',
+ 'data': [ 'boolean', 'number' ] }
+
+##
+# @CpuPropertyValueRange:
+#
+# An inclusive range of numeric values supported for a property.
+#
+# @min: the lowest supported value.
+#
+# @max: the highest supported value.
+#
+# Since: 11.1
+##
+{ 'struct': 'CpuPropertyValueRange',
+ 'data': { 'min': 'uint64', 'max': 'uint64' } }
+
+##
+# @CpuPropertyInfoBoolean:
+#
+# @supported-values: the boolean values the host supports for this
+# property (a subset of {true, false}).
+#
+# Since: 11.1
+##
+{ 'struct': 'CpuPropertyInfoBoolean',
+ 'data': { 'supported-values': ['bool'] } }
+
+##
+# @CpuPropertyInfoNumber:
+#
+# @supported-values: the set of value ranges the host supports for
+# this property.
+#
+# Since: 11.1
+##
+{ 'struct': 'CpuPropertyInfoNumber',
+ 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
+
+##
+# @CpuPropertyInfo:
+#
+# Information about a single CPU model property, including the values
+# the current host supports for it.
+#
+# @name: the name of the property.
+#
+# @type: the type of the property, which selects the layout of
+# @supported-values.
+#
+# Since: 11.1
+##
+{ 'union': 'CpuPropertyInfo',
+ 'base': { 'name': 'str',
+ 'type': 'CpuPropertyType' },
+ 'discriminator': 'type',
+ 'data': { 'boolean': 'CpuPropertyInfoBoolean',
+ 'number': 'CpuPropertyInfoNumber' } }
+
+##
+# @query-cpu-props-info:
+#
+# Return information about the CPU model properties. For each
+# property it reports the values supported under the active
+# accelerator and host.
+#
+# .. note:: This command is currently only implemented on Arm (and
+# KVM accel); all other configurations return an error. The schema
+# is architecture-agnostic so other targets and accelerators can
+# implement it in the future.
+#
+# Since: 11.1
+##
+{ 'command': 'query-cpu-props-info',
+ 'returns': ['CpuPropertyInfo'] }
diff --git a/stubs/meson.build b/stubs/meson.build
index 3b2f2680b1..3bb4028bab 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -83,6 +83,7 @@ if have_system
stub_ss.add(files('qmp-i386-sgx.c'))
stub_ss.add(files('qmp-i386-xen.c'))
stub_ss.add(files('qmp-cpu.c'))
+ stub_ss.add(files('qmp-cpu-props-info.c'))
stub_ss.add(files('qmp-cpu-s390x.c'))
stub_ss.add(files('qmp-cpu-s390x-kvm.c'))
stub_ss.add(files('hmp-cmd-info_mem.c'))
diff --git a/stubs/qmp-cpu-props-info.c b/stubs/qmp-cpu-props-info.c
new file mode 100644
index 0000000000..f0301a1179
--- /dev/null
+++ b/stubs/qmp-cpu-props-info.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-machine.h"
+
+CpuPropertyInfoList *
+qmp_query_cpu_props_info(Error **errp)
+{
+ error_setg(errp, "CPU model properties are not supported on this target");
+ return NULL;
+}
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index bdf46c823a..457cc3edf3 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -81,6 +81,96 @@ static const char *cpu_model_advertised_features[] = {
NULL
};
+CpuPropertyInfoList *qmp_query_cpu_props_info(Error **errp)
+{
+ CpuPropertyInfoList *head = NULL;
+ const ARMISARegisters *host_isar;
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
+ Error *err = NULL;
+ ObjectClass *oc;
+ Object *obj;
+
+ if (!kvm_enabled()) {
+ error_setg(errp, "query-cpu-props-info requires KVM");
+ return NULL;
+ }
+
+ oc = cpu_class_by_name(TYPE_ARM_CPU, "host");
+ if (!oc) {
+ error_setg(errp, "The 'host' CPU type is not available");
+ return NULL;
+ }
+
+ host_isar = kvm_arm_get_host_isar();
+
+ /*
+ * Spin up a scratch "host" vCPU object and walk its QOM properties.
+ * This gives us the exact set we want to expose: the SYSREG_ ID-register
+ * properties and the advertised feature properties, along with their
+ * values for the host.
+ */
+ obj = object_new_with_class(oc);
+ arm_cpu_finalize_features(ARM_CPU(obj), &err);
+ if (err) {
+ error_propagate(errp, err);
+ object_unref(obj);
+ return NULL;
+ }
+
+ object_property_iter_init(&iter, obj);
+ while ((prop = object_property_iter_next(&iter))) {
+ CpuPropertyInfo *info;
+
+ if (g_str_has_prefix(prop->name, "SYSREG_")) {
+ /* The SYSREG_ property stashes its field descriptor as opaque. */
+ const ARM64SysRegField *field = prop->opaque;
+ ArmFieldValueSet *vs = NULL;
+ CpuPropertyValueRangeList *ranges = NULL;
+
+ info = g_new0(CpuPropertyInfo, 1);
+ info->name = g_strdup(prop->name);
+ info->type = CPU_PROPERTY_TYPE_NUMBER;
+
+ arm_field_get_supported_values(field, host_isar, &vs);
+ for (size_t k = 0; k < vs->n_ranges; k++) {
+ CpuPropertyValueRange *r = g_new0(CpuPropertyValueRange, 1);
+ r->min = vs->ranges[k].min;
+ r->max = vs->ranges[k].max;
+ QAPI_LIST_PREPEND(ranges, r);
+ }
+ info->u.number.supported_values = ranges;
+
+ g_free(vs->ranges);
+ g_free(vs);
+ } else if (g_strv_contains(cpu_model_advertised_features, prop->name))
{
+ bool cur = object_property_get_bool(obj, prop->name, &error_abort);
+ boolList *values = NULL;
+
+ info = g_new0(CpuPropertyInfo, 1);
+ info->name = g_strdup(prop->name);
+ info->type = CPU_PROPERTY_TYPE_BOOLEAN;
+
+ /*
+ * "off" is always achievable. "on" is only supported when the
+ * host already has the feature enabled.
+ */
+ QAPI_LIST_PREPEND(values, false);
+ if (cur) {
+ QAPI_LIST_PREPEND(values, true);
+ }
+ info->u.boolean.supported_values = values;
+ } else {
+ continue;
+ }
+
+ QAPI_LIST_PREPEND(head, info);
+ }
+
+ object_unref(obj);
+ return head;
+}
+
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType
type,
CpuModelInfo *model,
Error **errp)
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index dd683beaaf..d19c53927d 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -124,3 +124,10 @@ const ARMISARegisters *kvm_arm_get_host_isar(void)
{
return NULL;
}
+
+void arm_field_get_supported_values(const ARM64SysRegField *field,
+ const ARMISARegisters *host_isar,
+ ArmFieldValueSet **value_set)
+{
+ g_assert_not_reached();
+}
--
2.52.0