xref: /openbmc/qemu/tests/qtest/libqos/qos_external.c (revision 6ab425d8)
1 /*
2  * libqos driver framework
3  *
4  * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License version 2 as published by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see <http://www.gnu.org/licenses/>
17  */
18 
19 #include "qemu/osdep.h"
20 #include <getopt.h>
21 #include "libqtest.h"
22 #include "qapi/qmp/qdict.h"
23 #include "qapi/qmp/qbool.h"
24 #include "qapi/qmp/qstring.h"
25 #include "qemu/module.h"
26 #include "qapi/qmp/qlist.h"
27 #include "libqos/malloc.h"
28 #include "libqos/qgraph.h"
29 #include "libqos/qgraph_internal.h"
30 #include "libqos/qos_external.h"
31 
32 
33 
34 void apply_to_node(const char *name, bool is_machine, bool is_abstract)
35 {
36     char *machine_name = NULL;
37     if (is_machine) {
38         const char *arch = qtest_get_arch();
39         machine_name = g_strconcat(arch, "/", name, NULL);
40         name = machine_name;
41     }
42     qos_graph_node_set_availability(name, true);
43     if (is_abstract) {
44         qos_delete_cmd_line(name);
45     }
46     g_free(machine_name);
47 }
48 
49 /**
50  * apply_to_qlist(): using QMP queries QEMU for a list of
51  * machines and devices available, and sets the respective node
52  * as true. If a node is found, also all its produced and contained
53  * child are marked available.
54  *
55  * See qos_graph_node_set_availability() for more info
56  */
57 void apply_to_qlist(QList *list, bool is_machine)
58 {
59     const QListEntry *p;
60     const char *name;
61     bool abstract;
62     QDict *minfo;
63     QObject *qobj;
64     QString *qstr;
65     QBool *qbool;
66 
67     for (p = qlist_first(list); p; p = qlist_next(p)) {
68         minfo = qobject_to(QDict, qlist_entry_obj(p));
69         qobj = qdict_get(minfo, "name");
70         qstr = qobject_to(QString, qobj);
71         name = qstring_get_str(qstr);
72 
73         qobj = qdict_get(minfo, "abstract");
74         if (qobj) {
75             qbool = qobject_to(QBool, qobj);
76             abstract = qbool_get_bool(qbool);
77         } else {
78             abstract = false;
79         }
80 
81         apply_to_node(name, is_machine, abstract);
82         qobj = qdict_get(minfo, "alias");
83         if (qobj) {
84             qstr = qobject_to(QString, qobj);
85             name = qstring_get_str(qstr);
86             apply_to_node(name, is_machine, abstract);
87         }
88     }
89 }
90 
91 QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
92 {
93     return obj->get_driver(obj, "memory");
94 }
95 
96 /**
97  * allocate_objects(): given an array of nodes @arg,
98  * walks the path invoking all constructors and
99  * passing the corresponding parameter in order to
100  * continue the objects allocation.
101  * Once the test is reached, return the object it consumes.
102  *
103  * Since the machine and QEDGE_CONSUMED_BY nodes allocate
104  * memory in the constructor, g_test_queue_destroy is used so
105  * that after execution they can be safely free'd.  (The test's
106  * ->before callback is also welcome to use g_test_queue_destroy).
107  *
108  * Note: as specified in walk_path() too, @arg is an array of
109  * char *, where arg[0] is a pointer to the command line
110  * string that will be used to properly start QEMU when executing
111  * the test, and the remaining elements represent the actual objects
112  * that will be allocated.
113  */
114 void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
115 {
116     int current = 0;
117     QGuestAllocator *alloc;
118     QOSGraphObject *parent = NULL;
119     QOSGraphEdge *edge;
120     QOSGraphNode *node;
121     void *edge_arg;
122     void *obj;
123 
124     node = qos_graph_get_node(path[current]);
125     g_assert(node->type == QNODE_MACHINE);
126 
127     obj = qos_machine_new(node, qts);
128     qos_object_queue_destroy(obj);
129 
130     alloc = get_machine_allocator(obj);
131     if (p_alloc) {
132         *p_alloc = alloc;
133     }
134 
135     for (;;) {
136         if (node->type != QNODE_INTERFACE) {
137             qos_object_start_hw(obj);
138             parent = obj;
139         }
140 
141         /* follow edge and get object for next node constructor */
142         current++;
143         edge = qos_graph_get_edge(path[current - 1], path[current]);
144         node = qos_graph_get_node(path[current]);
145 
146         if (node->type == QNODE_TEST) {
147             g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
148             return obj;
149         }
150 
151         switch (qos_graph_edge_get_type(edge)) {
152         case QEDGE_PRODUCES:
153             obj = parent->get_driver(parent, path[current]);
154             break;
155 
156         case QEDGE_CONSUMED_BY:
157             edge_arg = qos_graph_edge_get_arg(edge);
158             obj = qos_driver_new(node, obj, alloc, edge_arg);
159             qos_object_queue_destroy(obj);
160             break;
161 
162         case QEDGE_CONTAINS:
163             obj = parent->get_device(parent, path[current]);
164             break;
165         }
166     }
167 }
168 
169