From: goremykin <oleg.goremi...@yandex.ru> Option -dt-printf 'file' writes Device Tree (DiveceClass hierarchy) to 'file' using Json format. This helps developers visualize the hierarchy of DeviceClass and its properties.
Signed-off-by: Oleg Goremykin <goremy...@ispras.ru> --- include/qom/qom-dt.h | 22 ++++++++ qemu-options.hx | 16 ++++++ qom/Makefile.objs | 1 + qom/qom-dt.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 4 ++ 5 files changed, 185 insertions(+) create mode 100644 include/qom/qom-dt.h create mode 100644 qom/qom-dt.c diff --git a/include/qom/qom-dt.h b/include/qom/qom-dt.h new file mode 100644 index 0000000..bb641f0 --- /dev/null +++ b/include/qom/qom-dt.h @@ -0,0 +1,22 @@ +/* + * Device Tree (DeviceClass hierarchy) + * + * Copyright ISP RAS, 2016 + * + * Created on: Jul 6, 2016 + * Author: Oleg Goremykin <goremy...@ispras.ru> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef INCLUDE_QOM_QOM_DT_H_ +#define INCLUDE_QOM_QOM_DT_H_ + +/** + * dt_printf: writes Device Tree (DiveceClass hierarchy) to @file_name + * @file_name: output file name + */ +int dt_printf(const char *file_name); + +#endif /* INCLUDE_QOM_QOM_DT_H_ */ diff --git a/qemu-options.hx b/qemu-options.hx index 9692e53..0140bc4 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -96,6 +96,22 @@ STEXI Select CPU model (@code{-cpu help} for list and additional feature selection) ETEXI +DEF("dt-printf", HAS_ARG, QEMU_OPTION_dt_printf, + "-dt-printf create FILE with device tree\n", QEMU_ARCH_ALL) +STEXI +@item -dt-printf @var{file} +@findex -dt-printf +Write DeviceClass hierarchy to @var{file} in JSON format. +The @var{file} contains a list of DeviceClass. +Each DeviceClass is a collection with following fields: +-children: list of DeviceClass to which current class is parent_class +-type: name of device (string) +-property: list of device properties where each property is a collection +Each property in list has following fields: +-name: property name (string) +-type: property qtype (number) +ETEXI + DEF("smp", HAS_ARG, QEMU_OPTION_smp, "-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets]\n" " set the number of CPUs to 'n' [default=1]\n" diff --git a/qom/Makefile.objs b/qom/Makefile.objs index 516349e..6df3a1e 100644 --- a/qom/Makefile.objs +++ b/qom/Makefile.objs @@ -1,4 +1,5 @@ qom-obj-y = object.o container.o qom-qobject.o qom-obj-y += object_interfaces.o +qom-obj-y += qom-dt.o common-obj-y = cpu.o diff --git a/qom/qom-dt.c b/qom/qom-dt.c new file mode 100644 index 0000000..81b5bec --- /dev/null +++ b/qom/qom-dt.c @@ -0,0 +1,142 @@ +/* + * Device Tree (DeviceClass hierarchy) + * + * Copyright ISP RAS, 2016 + * + * Created on: Jul 6, 2016 + * Author: Oleg Goremykin <goremy...@ispras.ru> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qom/qom-dt.h" + +#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qint.h" +#include "hw/qdev-core.h" + +#define DT_PROPERTY "property" +#define DT_NAME "name" +#define DT_TYPE "type" +#define DT_CHILDREN "children" + +typedef struct _QOMTreeData QOMTreeData; + +struct _QOMTreeData { + ObjectClass *root_class; + QOMTreeData *prev; + QList *list; +}; + +static void dt_put_props(Property *props, QDict *device) +{ + if (!props) { + return; + } + + QList *props_list = qlist_new(); + QString *prop_name; + QInt *prop_type; + QDict *prop; + + while (props->name) { + prop = qdict_new(); + prop_name = qstring_from_str(props->name); + qdict_put_obj(prop, DT_NAME, QOBJECT(prop_name)); + prop_type = qint_from_int(props->qtype); + qdict_put_obj(prop, DT_TYPE, QOBJECT(prop_type)); + qlist_append_obj(props_list, QOBJECT(prop)); + + props++; + } + + qdict_put_obj(device, DT_PROPERTY, QOBJECT(props_list)); +} + +static void dt_create_tree(ObjectClass *cur_class, void *opaque) +{ + QOMTreeData *cur_data = (QOMTreeData *) opaque; + QOMTreeData data; + QString *qstring; + const char *dev_type; + + if (object_class_get_parent(cur_class) != cur_data->root_class) { + return; + } + + dev_type = object_class_get_name(cur_class); + + if (object_class_dynamic_cast(cur_class, TYPE_DEVICE)) { + QList *child_list = qlist_new(); + QDict *device = qdict_new(); + + qstring = qstring_from_str(dev_type); + + qdict_put_obj(device, DT_TYPE, QOBJECT(qstring)); + qdict_put_obj(device, DT_CHILDREN, QOBJECT(child_list)); + dt_put_props(DEVICE_CLASS(cur_class)->props, device); + + qlist_append_obj(cur_data->list, QOBJECT(device)); + + data.list = child_list; + } else { + data.list = cur_data->list; + } + + data.prev = cur_data; + data.root_class = cur_class; + + object_class_foreach(dt_create_tree, object_class_get_name(data.root_class), + 1, (void *) &data); +} + +static void dt_del_empty_child(QList *device_list, QDict *device) +{ + const QListEntry *entry; + if (device) { + if (qlist_size(device_list) == 0) { + qdict_del(device, DT_CHILDREN); + return; + } + } + + if (device_list) { + entry = qlist_first(device_list); + while (entry) { + device = qobject_to_qdict(qlist_entry_obj(entry)); + dt_del_empty_child(qobject_to_qlist(qdict_get(device, DT_CHILDREN)), + device); + entry = qlist_next(entry); + } + } +} + +int dt_printf(const char *file_name) +{ + FILE *output_file = fopen(file_name, "w"); + + if (!output_file) { + fprintf(stderr, "Couldn't open \"%s\": %s", file_name, strerror(errno)); + return 1; + } + + QOMTreeData data; + QString *str_json; + + data.prev = 0; + data.root_class = NULL; + data.list = qlist_new(); + + object_class_foreach(dt_create_tree, NULL, 1, (void *) &data); + dt_del_empty_child(data.list, NULL); + + str_json = qobject_to_json_pretty(QOBJECT(data.list)); + fprintf(output_file, "%s\n", qstring_get_str(str_json)); + + QDECREF(data.list); + + fclose(output_file); + return 0; +} diff --git a/vl.c b/vl.c index 5cd0f2a..2ee097c 100644 --- a/vl.c +++ b/vl.c @@ -115,6 +115,7 @@ int main(int argc, char **argv) #include "ui/qemu-spice.h" #include "qapi/string-input-visitor.h" #include "qapi/opts-visitor.h" +#include "qom/qom-dt.h" #include "qom/object_interfaces.h" #include "qapi-event.h" #include "exec/semihost.h" @@ -3065,6 +3066,9 @@ int main(int argc, char **argv, char **envp) /* hw initialization will check this */ cpu_model = optarg; break; + case QEMU_OPTION_dt_printf: + exit(dt_printf(optarg)); + break; case QEMU_OPTION_hda: { char buf[256]; -- 1.9.1