Signed-off-by: Maxim Davydov <maxim.davy...@openvz.org>
---
qapi/qom.json | 69 ++++++++++++++++++++++++++
qom/qom-qmp-cmds.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 190 insertions(+)
diff --git a/qapi/qom.json b/qapi/qom.json
index eeb5395ff3..1eedc441eb 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -949,3 +949,72 @@
##
{ 'command': 'object-del', 'data': {'id': 'str'},
'allow-preconfig': true }
+
+##
+# @InitValue:
+#
+# Not all objects have default values but they have "initial" values.
+#
+# @name: property name
+#
+# @value: Current value (default or after initialization. It makes sence,
+# for example, for x86-cpus)
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'InitValue',
+ 'data': { 'name': 'str',
+ '*value': 'any' } }
+
+##
+# @ClassProperties:
+#
+# Initial values of properties that are owned by the class
+#
+# @classname: name of the class that owns appropriate properties
+#
+# @classprops: List of class properties
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'ClassProperties',
+ 'data': { 'classname': 'str',
+ '*classprops': [ 'InitValue' ] } }
+
+##
+# @InitProps:
+#
+# List of properties and their values that are available after class
+# initialization. So it important to know default value of the property
+# even if it doesn't have "QObject *defval"
+#
+# @name: Object name
+#
+# @props: List of properties
+#
+# Notes: a value in each property was defval if it's available
+# otherwise it's obtained via "(ObjectPropertyAccessor*) get"
+# immediately after initialization of device object.
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'InitProps',
+ 'data': { 'name': 'str',
+ 'props': [ 'ClassProperties' ] } }
+
+##
+# @query-init-properties:
+#
+# Returns list of all objects (except all types related with machine type)
+# with all properties and their "default" values that will be available
+# after initialization. The main purpose of this command is to be used to
+# build table with all machine-type-specific properties
+#
+# Since: 7.0
+#
+##
+{ 'command': 'query-init-properties',
+ 'returns': [ 'InitProps' ] }
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
index 2d6f41ecc7..c1bb3f1f8b 100644
--- a/qom/qom-qmp-cmds.c
+++ b/qom/qom-qmp-cmds.c
@@ -27,6 +27,7 @@
#include "qemu/cutils.h"
#include "qom/object_interfaces.h"
#include "qom/qom-qobject.h"
+#include "hw/boards.h"
ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
{
@@ -235,3 +236,123 @@ void qmp_object_del(const char *id, Error **errp)
{
user_creatable_del(id, errp);
}
+
+static void query_object_prop(InitValueList **props_list, ObjectProperty *prop,
+ Object *obj, Error **errp)
+{
+ InitValue *prop_info = NULL;
+
+ /* Skip inconsiderable properties */
+ if (strcmp(prop->name, "type") == 0 ||
+ strcmp(prop->name, "realized") == 0 ||
+ strcmp(prop->name, "hotpluggable") == 0 ||
+ strcmp(prop->name, "hotplugged") == 0 ||
+ strcmp(prop->name, "parent_bus") == 0) {
+ return;
+ }
+
+ prop_info = g_malloc0(sizeof(*prop_info));
+ prop_info->name = g_strdup(prop->name);
+ prop_info->value = NULL;
+ if (prop->defval) {
+ prop_info->value = qobject_ref(prop->defval);
+ } else if (prop->get) {
+ /*
+ * crash-information in x86-cpu uses errp to return current state.
+ * So, after requesting this property it returns GenericError:
+ * "No crash occured"
+ */
+ if (strcmp(prop->name, "crash-information") != 0) {
+ prop_info->value = object_property_get_qobject(obj, prop->name,
+ errp);
+ }
+ }
+ prop_info->has_value = !!prop_info->value;
+
+ QAPI_LIST_PREPEND(*props_list, prop_info);
+}
+
+typedef struct QIPData {
+ InitPropsList **dev_list;
+ Error **errp;
+} QIPData;
+
+static void query_init_properties_tramp(gpointer list_data, gpointer opaque)
+{
+ ObjectClass *k = list_data;
+ Object *obj;
+ ObjectClass *parent;
+ GHashTableIter iter;
+
+ QIPData *data = opaque;
+ ClassPropertiesList *class_props_list = NULL;
+ InitProps *dev_info;
+
+ /* Only one machine can be initialized correctly (it's already happened) */
+ if (object_class_dynamic_cast(k, TYPE_MACHINE)) {
+ return;
+ }
+
+ const char *klass_name = object_class_get_name(k);
+ /*
+ * Uses machine type infrastructure with notifiers. It causes immediate
+ * notify and SEGSEGV during remote_object_machine_done
+ */
+ if (strcmp(klass_name, "x-remote-object") == 0) {
+ return;
+ }
+
+ dev_info = g_malloc0(sizeof(*dev_info));
+ dev_info->name = g_strdup(klass_name);
+
+ obj = object_new_with_class(k);
+
+ /*
+ * Part of ObjectPropertyIterator infrastructure, but we need more precise
+ * control of current class to dump appropriate features
+ * This part was taken out from loop because first initialization differ
+ * from other reinitializations
+ */
+ parent = object_get_class(obj);
+ g_hash_table_iter_init(&iter, obj->properties);
+ const char *prop_owner_name = object_get_typename(obj);
+ do {
+ InitValueList *prop_list = NULL;
+ ClassProperties *class_data;
+
+ gpointer key, val;
+ while (g_hash_table_iter_next(&iter, &key, &val)) {
+ query_object_prop(&prop_list, (ObjectProperty *)val, obj,
+ data->errp);
+ }
+ class_data = g_malloc0(sizeof(*class_data));
+ class_data->classname = g_strdup(prop_owner_name);
+ class_data->classprops = prop_list;
+ class_data->has_classprops = !!prop_list;
+
+ QAPI_LIST_PREPEND(class_props_list, class_data);
+
+ if (!parent) {
+ break;
+ }
+ g_hash_table_iter_init(&iter, parent->properties);
+ prop_owner_name = object_class_get_name(parent);
+ parent = object_class_get_parent(parent);
+ } while (true);
+ dev_info->props = class_props_list;
+ object_unref(OBJECT(obj));
+
+ QAPI_LIST_PREPEND(*(data->dev_list), dev_info);
+}
+
+InitPropsList *qmp_query_init_properties(Error **errp)
+{
+ GSList *typename_list = object_class_get_list(TYPE_OBJECT, false);
+
+ InitPropsList *dev_list = NULL;
+ QIPData data = { &dev_list, errp };
+ g_slist_foreach(typename_list, query_init_properties_tramp, &data);
+ g_slist_free(typename_list);
+
+ return dev_list;
+}