2 * libqos driver framework
4 * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
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.1 as published by the Free Software Foundation.
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.
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/>
23 #include "qemu/module.h"
24 #include "libqos-malloc.h"
26 /* maximum path length */
27 #define QOS_PATH_MAX_ELEMENT_SIZE 128
29 typedef struct QOSGraphObject QOSGraphObject
;
30 typedef struct QOSGraphNode QOSGraphNode
;
31 typedef struct QOSGraphEdge QOSGraphEdge
;
32 typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions
;
33 typedef struct QOSGraphTestOptions QOSGraphTestOptions
;
35 /* Constructor for drivers, machines and test */
36 typedef void *(*QOSCreateDriverFunc
) (void *parent
, QGuestAllocator
*alloc
,
38 typedef void *(*QOSCreateMachineFunc
) (QTestState
*qts
);
39 typedef void (*QOSTestFunc
) (void *parent
, void *arg
, QGuestAllocator
*alloc
);
41 /* QOSGraphObject functions */
42 typedef void *(*QOSGetDriver
) (void *object
, const char *interface
);
43 typedef QOSGraphObject
*(*QOSGetDevice
) (void *object
, const char *name
);
44 typedef void (*QOSDestructorFunc
) (QOSGraphObject
*object
);
45 typedef void (*QOSStartFunct
) (QOSGraphObject
*object
);
47 /* Test options functions */
48 typedef void *(*QOSBeforeTest
) (GString
*cmd_line
, void *arg
);
51 * struct QOSGraphEdgeOptions:
52 * Edge options to be passed to the contains/consumes \*_args function.
53 * @arg: optional arg that will be used by dest edge
54 * @size_arg: @arg size that will be used by dest edge
55 * @extra_device_opts: optional additional command line for dest
56 * edge, used to add additional attributes
57 * *after* the node command line, the
58 * framework automatically prepends ","
60 * @before_cmd_line: optional additional command line for dest
61 * edge, used to add additional attributes
62 * *before* the node command line, usually
63 * other non-node represented commands,
65 * @after_cmd_line: optional extra command line to be added
66 * after the device command. This option
67 * is used to add other devices
68 * command line that depend on current node.
69 * Automatically prepends " " to this argument
70 * @edge_name: optional edge to differentiate multiple
71 * devices with same node name
73 struct QOSGraphEdgeOptions
{
76 const char *extra_device_opts
;
77 const char *before_cmd_line
;
78 const char *after_cmd_line
;
79 const char *edge_name
;
83 * struct QOSGraphTestOptions:
84 * Test options to be passed to the test functions.
85 * @edge: edge arguments that will be used by test.
86 * Note that test *does not* use edge_name,
87 * and uses instead arg and size_arg as
88 * data arg for its test function.
89 * @arg: if @before is non-NULL, pass @arg there.
90 * Otherwise pass it to the test function.
91 * @before: executed before the test. Used to add
92 * additional parameters to the command line
93 * and modify the argument to the test function.
94 * @subprocess: run the test in a subprocess.
96 struct QOSGraphTestOptions
{
97 QOSGraphEdgeOptions edge
;
104 * struct QOSGraphObject:
105 * Each driver, test or machine of this framework will have a
106 * QOSGraphObject as first field.
108 * This set of functions offered by QOSGraphObject are executed
109 * in different stages of the framework:
110 * @get_driver: see @get_device
111 * @get_device: Once a machine-to-test path has been
112 * found, the framework traverses it again and allocates all the
113 * nodes, using the provided constructor. To satisfy their
114 * relations, i.e. for produces or contains, where a struct
115 * constructor needs an external parameter represented by the
116 * previous node, the framework will call
117 * @get_device (for contains) or @get_driver (for produces),
118 * depending on the edge type, passing them the name of the next
119 * node to be taken and getting from them the corresponding
120 * pointer to the actual structure of the next node to
121 * be used in the path.
122 * @start_hw: This function is executed after all the path objects
123 * have been allocated, but before the test is run. It starts the
124 * hw, setting the initial configurations (\*_device_enable) and
125 * making it ready for the test.
126 * @destructor: Opposite to the node constructor, destroys the object.
127 * This function is called after the test has been executed, and
128 * performs a complete cleanup of each node allocated field.
129 * In case no constructor is provided, no destructor will be
131 * @free: free the memory associated to the QOSGraphObject and its contained
134 struct QOSGraphObject
{
135 QOSGetDriver get_driver
;
136 QOSGetDevice get_device
;
137 QOSStartFunct start_hw
;
138 QOSDestructorFunc destructor
;
143 * qos_graph_init(): initialize the framework, creates two hash
144 * tables: one for the nodes and another for the edges.
146 void qos_graph_init(void);
149 * qos_graph_destroy(): deallocates all the hash tables,
150 * freeing all nodes and edges.
152 void qos_graph_destroy(void);
155 * qos_node_destroy(): removes and frees a node from the
157 * @key: Name of the node
159 void qos_node_destroy(void *key
);
162 * qos_edge_destroy(): removes and frees an edge from the
164 * @key: Name of the node
166 void qos_edge_destroy(void *key
);
169 * qos_add_test(): adds a test node @name to the nodes hash table.
170 * @name: Name of the test
171 * @interface: Name of the interface node it consumes
172 * @test_func: Actual test to perform
173 * @opts: Facultative options (see %QOSGraphTestOptions)
175 * The test will consume a @interface node, and once the
176 * graph walking algorithm has found it, the @test_func will be
177 * executed. It also has the possibility to
178 * add an optional @opts (see %QOSGraphTestOptions).
180 * For tests, opts->edge.arg and size_arg represent the arg to pass
183 void qos_add_test(const char *name
, const char *interface
,
184 QOSTestFunc test_func
,
185 QOSGraphTestOptions
*opts
);
188 * qos_node_create_machine(): creates the machine @name and
189 * adds it to the node hash table.
190 * @name: Name of the machine
191 * @function: Machine constructor
193 * This node will be of type QNODE_MACHINE and have @function
196 void qos_node_create_machine(const char *name
, QOSCreateMachineFunc function
);
199 * qos_node_create_machine_args(): same as qos_node_create_machine,
200 * but with the possibility to add an optional ", @opts" after -M machine
202 * @name: Name of the machine
203 * @function: Machine constructor
204 * @opts: Optional additional command line
206 void qos_node_create_machine_args(const char *name
,
207 QOSCreateMachineFunc function
,
211 * qos_node_create_driver(): creates the driver @name and
212 * adds it to the node hash table.
213 * @name: Name of the driver
214 * @function: Driver constructor
216 * This node will be of type QNODE_DRIVER and have @function
219 void qos_node_create_driver(const char *name
, QOSCreateDriverFunc function
);
222 * qos_node_create_driver_named(): behaves as qos_node_create_driver() with the
223 * extension of allowing to specify a different node name vs. associated QEMU
225 * @name: Custom, unique name of the node to be created
226 * @qemu_name: Actual (official) QEMU driver name the node shall be
228 * @function: Driver constructor
230 * Use this function instead of qos_node_create_driver() if you need to create
231 * several instances of the same QEMU device. You are free to choose a custom
232 * node name, however the chosen node name must always be unique.
234 void qos_node_create_driver_named(const char *name
, const char *qemu_name
,
235 QOSCreateDriverFunc function
);
238 * qos_node_contains(): creates one or more edges of type QEDGE_CONTAINS
239 * and adds them to the edge list mapped to @container in the
241 * @container: Source node that "contains"
242 * @contained: Destination node that "is contained"
243 * @opts: Facultative options (see %QOSGraphEdgeOptions)
245 * The edges will have @container as source and @contained as destination.
247 * If @opts is NULL, a single edge will be added with no options.
248 * If @opts is non-NULL, the arguments after @contained represent a
249 * NULL-terminated list of %QOSGraphEdgeOptions structs, and an
250 * edge will be added for each of them.
252 * This function can be useful when there are multiple devices
253 * with the same node name contained in a machine/other node
255 * For example, if ``arm/raspi2b`` contains 2 ``generic-sdhci``
256 * devices, the right commands will be:
260 * qos_node_create_machine("arm/raspi2b");
261 * qos_node_create_driver("generic-sdhci", constructor);
262 * // assume rest of the fields are set NULL
263 * QOSGraphEdgeOptions op1 = { .edge_name = "emmc" };
264 * QOSGraphEdgeOptions op2 = { .edge_name = "sdcard" };
265 * qos_node_contains("arm/raspi2b", "generic-sdhci", &op1, &op2, NULL);
267 * Of course this also requires that the @container's get_device function
268 * should implement a case for "emmc" and "sdcard".
270 * For contains, op1.arg and op1.size_arg represent the arg to pass
271 * to @contained constructor to properly initialize it.
273 void qos_node_contains(const char *container
, const char *contained
,
274 QOSGraphEdgeOptions
*opts
, ...);
277 * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and
278 * adds it to the edge list mapped to @producer in the
280 * @producer: Source node that "produces"
281 * @interface: Interface node that "is produced"
283 * This edge will have @producer as source and @interface as destination.
285 void qos_node_produces(const char *producer
, const char *interface
);
288 * qos_node_consumes(): creates an edge of type QEDGE_CONSUMED_BY and
289 * adds it to the edge list mapped to @interface in the
291 * @consumer: Node that "consumes"
292 * @interface: Interface node that "is consumed by"
293 * @opts: Facultative options (see %QOSGraphEdgeOptions)
295 * This edge will have @interface as source and @consumer as destination.
296 * It also has the possibility to add an optional @opts
297 * (see %QOSGraphEdgeOptions)
299 void qos_node_consumes(const char *consumer
, const char *interface
,
300 QOSGraphEdgeOptions
*opts
);
303 * qos_invalidate_command_line(): invalidates current command line, so that
304 * qgraph framework cannot try to cache the current command line and
305 * forces QEMU to restart.
307 void qos_invalidate_command_line(void);
310 * qos_get_current_command_line(): return the command line required by the
311 * machine and driver objects. This is the same string that was passed to
312 * the test's "before" callback, if any.
314 const char *qos_get_current_command_line(void);
317 * qos_allocate_objects():
318 * @qts: The #QTestState that will be referred to by the machine object.
319 * @p_alloc: Where to store the allocator for the machine object, or %NULL.
321 * Allocate driver objects for the current test
322 * path, but relative to the QTestState @qts.
324 * Returns a test object just like the one that was passed to
325 * the test function, but relative to @qts.
327 void *qos_allocate_objects(QTestState
*qts
, QGuestAllocator
**p_alloc
);
330 * qos_object_destroy(): calls the destructor for @obj
331 * @obj: A #QOSGraphObject to destroy
333 void qos_object_destroy(QOSGraphObject
*obj
);
336 * qos_object_queue_destroy(): queue the destructor for @obj so that it is
337 * called at the end of the test
338 * @obj: A #QOSGraphObject to destroy
340 void qos_object_queue_destroy(QOSGraphObject
*obj
);
343 * qos_object_start_hw(): calls the start_hw function for @obj
344 * @obj: A #QOSGraphObject containing the start_hw function
346 void qos_object_start_hw(QOSGraphObject
*obj
);
349 * qos_machine_new(): instantiate a new machine node
350 * @node: Machine node to be instantiated
351 * @qts: A #QTestState that will be referred to by the machine object.
353 * Returns a machine object.
355 QOSGraphObject
*qos_machine_new(QOSGraphNode
*node
, QTestState
*qts
);
358 * qos_machine_new(): instantiate a new driver node
359 * @node: A driver node to be instantiated
360 * @parent: A #QOSGraphObject to be consumed by the new driver node
361 * @alloc: An allocator to be used by the new driver node.
362 * @arg: The argument for the consumed-by edge to @node.
364 * Calls the constructor for the driver object.
366 QOSGraphObject
*qos_driver_new(QOSGraphNode
*node
, QOSGraphObject
*parent
,
367 QGuestAllocator
*alloc
, void *arg
);
370 * qos_dump_graph(): prints all currently existing nodes and
371 * edges to stdout. Just for debugging purposes.
373 * All qtests add themselves to the overall qos graph by calling qgraph
374 * functions that add device nodes and edges between the individual graph
375 * nodes for tests. As the actual graph is assmbled at runtime by the qos
376 * subsystem, it is sometimes not obvious how the overall graph looks like.
377 * E.g. when writing new tests it may happen that those new tests are simply
378 * ignored by the qtest framework.
380 * This function allows to identify problems in the created qgraph. Keep in
381 * mind: only tests with a path down from the actual test case node (leaf) up
382 * to the graph's root node are actually executed by the qtest framework. And
383 * the qtest framework uses QMP to automatically check which QEMU drivers are
384 * actually currently available, and accordingly qos marks certain paths as
385 * 'unavailable' in such cases (e.g. when QEMU was compiled without support for
386 * a certain feature).
388 void qos_dump_graph(void);