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.1 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 #ifndef QGRAPH_H 20 #define QGRAPH_H 21 22 #include <gmodule.h> 23 #include "qemu/module.h" 24 #include "libqos-malloc.h" 25 26 /* maximum path length */ 27 #define QOS_PATH_MAX_ELEMENT_SIZE 50 28 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; 34 35 /* Constructor for drivers, machines and test */ 36 typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc, 37 void *addr); 38 typedef void *(*QOSCreateMachineFunc) (QTestState *qts); 39 typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc); 40 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); 46 47 /* Test options functions */ 48 typedef void *(*QOSBeforeTest) (GString *cmd_line, void *arg); 49 50 /** 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 "," 59 * to this argument. 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, 64 * like "-fdsev synt" 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 72 */ 73 struct QOSGraphEdgeOptions { 74 void *arg; 75 uint32_t size_arg; 76 const char *extra_device_opts; 77 const char *before_cmd_line; 78 const char *after_cmd_line; 79 const char *edge_name; 80 }; 81 82 /** 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. 95 */ 96 struct QOSGraphTestOptions { 97 QOSGraphEdgeOptions edge; 98 void *arg; 99 QOSBeforeTest before; 100 bool subprocess; 101 }; 102 103 /** 104 * struct QOSGraphObject: 105 * Each driver, test or machine of this framework will have a 106 * QOSGraphObject as first field. 107 * 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 130 * called. 131 * @free: free the memory associated to the QOSGraphObject and its contained 132 * children 133 */ 134 struct QOSGraphObject { 135 QOSGetDriver get_driver; 136 QOSGetDevice get_device; 137 QOSStartFunct start_hw; 138 QOSDestructorFunc destructor; 139 GDestroyNotify free; 140 }; 141 142 /** 143 * qos_graph_init(): initialize the framework, creates two hash 144 * tables: one for the nodes and another for the edges. 145 */ 146 void qos_graph_init(void); 147 148 /** 149 * qos_graph_destroy(): deallocates all the hash tables, 150 * freeing all nodes and edges. 151 */ 152 void qos_graph_destroy(void); 153 154 /** 155 * qos_node_destroy(): removes and frees a node from the 156 * nodes hash table. 157 * @key: Name of the node 158 */ 159 void qos_node_destroy(void *key); 160 161 /** 162 * qos_edge_destroy(): removes and frees an edge from the 163 * edges hash table. 164 * @key: Name of the node 165 */ 166 void qos_edge_destroy(void *key); 167 168 /** 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) 174 * 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). 179 * 180 * For tests, opts->edge.arg and size_arg represent the arg to pass 181 * to @test_func 182 */ 183 void qos_add_test(const char *name, const char *interface, 184 QOSTestFunc test_func, 185 QOSGraphTestOptions *opts); 186 187 /** 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 192 * 193 * This node will be of type QNODE_MACHINE and have @function 194 * as constructor 195 */ 196 void qos_node_create_machine(const char *name, QOSCreateMachineFunc function); 197 198 /** 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 201 * command line. 202 * @name: Name of the machine 203 * @function: Machine constructor 204 * @opts: Optional additional command line 205 */ 206 void qos_node_create_machine_args(const char *name, 207 QOSCreateMachineFunc function, 208 const char *opts); 209 210 /** 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 215 * 216 * This node will be of type QNODE_DRIVER and have @function 217 * as constructor 218 */ 219 void qos_node_create_driver(const char *name, QOSCreateDriverFunc function); 220 221 /** 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 224 * device name. 225 * @name: Custom, unique name of the node to be created 226 * @qemu_name: Actual (official) QEMU driver name the node shall be 227 * associated with 228 * @function: Driver constructor 229 * 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. 233 */ 234 void qos_node_create_driver_named(const char *name, const char *qemu_name, 235 QOSCreateDriverFunc function); 236 237 /** 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 240 * edge hash table. 241 * @container: Source node that "contains" 242 * @contained: Destination node that "is contained" 243 * @opts: Facultative options (see %QOSGraphEdgeOptions) 244 * 245 * The edges will have @container as source and @contained as destination. 246 * 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. 251 * 252 * This function can be useful when there are multiple devices 253 * with the same node name contained in a machine/other node 254 * 255 * For example, if ``arm/raspi2b`` contains 2 ``generic-sdhci`` 256 * devices, the right commands will be: 257 * 258 * .. code:: 259 * 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); 266 * 267 * Of course this also requires that the @container's get_device function 268 * should implement a case for "emmc" and "sdcard". 269 * 270 * For contains, op1.arg and op1.size_arg represent the arg to pass 271 * to @contained constructor to properly initialize it. 272 */ 273 void qos_node_contains(const char *container, const char *contained, 274 QOSGraphEdgeOptions *opts, ...); 275 276 /** 277 * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and 278 * adds it to the edge list mapped to @producer in the 279 * edge hash table. 280 * @producer: Source node that "produces" 281 * @interface: Interface node that "is produced" 282 * 283 * This edge will have @producer as source and @interface as destination. 284 */ 285 void qos_node_produces(const char *producer, const char *interface); 286 287 /** 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 290 * edge hash table. 291 * @consumer: Node that "consumes" 292 * @interface: Interface node that "is consumed by" 293 * @opts: Facultative options (see %QOSGraphEdgeOptions) 294 * 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) 298 */ 299 void qos_node_consumes(const char *consumer, const char *interface, 300 QOSGraphEdgeOptions *opts); 301 302 /** 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. 306 */ 307 void qos_invalidate_command_line(void); 308 309 /** 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. 313 */ 314 const char *qos_get_current_command_line(void); 315 316 /** 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. 320 * 321 * Allocate driver objects for the current test 322 * path, but relative to the QTestState @qts. 323 * 324 * Returns a test object just like the one that was passed to 325 * the test function, but relative to @qts. 326 */ 327 void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc); 328 329 /** 330 * qos_object_destroy(): calls the destructor for @obj 331 * @obj: A #QOSGraphObject to destroy 332 */ 333 void qos_object_destroy(QOSGraphObject *obj); 334 335 /** 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 339 */ 340 void qos_object_queue_destroy(QOSGraphObject *obj); 341 342 /** 343 * qos_object_start_hw(): calls the start_hw function for @obj 344 * @obj: A #QOSGraphObject containing the start_hw function 345 */ 346 void qos_object_start_hw(QOSGraphObject *obj); 347 348 /** 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. 352 * 353 * Returns a machine object. 354 */ 355 QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts); 356 357 /** 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. 363 * 364 * Calls the constructor for the driver object. 365 */ 366 QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent, 367 QGuestAllocator *alloc, void *arg); 368 369 /** 370 * qos_dump_graph(): prints all currently existing nodes and 371 * edges to stdout. Just for debugging purposes. 372 * 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. 379 * 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 pathes as 385 * 'unavailable' in such cases (e.g. when QEMU was compiled without support for 386 * a certain feature). 387 */ 388 void qos_dump_graph(void); 389 390 #endif 391