| 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 | #include "qemu/osdep.h" |
| 20 | #include <getopt.h> |
| 21 | #include "../libqtest.h" |
| 22 | #include "qobject/qdict.h" |
| 23 | #include "qobject/qbool.h" |
| 24 | #include "qobject/qstring.h" |
| 25 | #include "qemu/module.h" |
| 26 | #include "qobject/qlist.h" |
| 27 | #include "libqos-malloc.h" |
| 28 | #include "qgraph.h" |
| 29 | #include "qgraph_internal.h" |
| 30 | #include "qos_external.h" |
| 31 | |
| 32 | static void machine_apply_to_node(const char *name) |
| 33 | { |
| 34 | char *machine_name = g_strconcat(qtest_get_arch(), "/", name, NULL); |
| 35 | |
| 36 | qos_graph_node_set_availability(machine_name, true); |
| 37 | g_free(machine_name); |
| 38 | } |
| 39 | |
| 40 | void machines_apply_to_node(MachineInfoList *mach_info) |
| 41 | { |
| 42 | MachineInfoList *tail; |
| 43 | |
| 44 | for (tail = mach_info; tail; tail = tail->next) { |
| 45 | machine_apply_to_node(tail->value->name); |
| 46 | if (tail->value->alias) { |
| 47 | machine_apply_to_node(tail->value->alias); |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | static void type_apply_to_node(const char *name, bool is_abstract) |
| 53 | { |
| 54 | qos_graph_node_set_availability(name, true); |
| 55 | if (is_abstract) { |
| 56 | qos_delete_cmd_line(name); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | void types_apply_to_node(ObjectTypeInfoList *type_info) |
| 61 | { |
| 62 | ObjectTypeInfoList *tail; |
| 63 | |
| 64 | for (tail = type_info; tail; tail = tail->next) { |
| 65 | type_apply_to_node(tail->value->name, tail->value->abstract); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj) |
| 70 | { |
| 71 | return obj->get_driver(obj, "memory"); |
| 72 | } |
| 73 | |
| 74 | /** |
| 75 | * allocate_objects(): given an array of nodes @arg, |
| 76 | * walks the path invoking all constructors and |
| 77 | * passing the corresponding parameter in order to |
| 78 | * continue the objects allocation. |
| 79 | * Once the test is reached, return the object it consumes. |
| 80 | * |
| 81 | * Since the machine and QEDGE_CONSUMED_BY nodes allocate |
| 82 | * memory in the constructor, g_test_queue_destroy is used so |
| 83 | * that after execution they can be safely free'd. (The test's |
| 84 | * ->before callback is also welcome to use g_test_queue_destroy). |
| 85 | * |
| 86 | * Note: as specified in walk_path() too, @arg is an array of |
| 87 | * char *, where arg[0] is a pointer to the command line |
| 88 | * string that will be used to properly start QEMU when executing |
| 89 | * the test, and the remaining elements represent the actual objects |
| 90 | * that will be allocated. |
| 91 | */ |
| 92 | void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc) |
| 93 | { |
| 94 | int current = 0; |
| 95 | QGuestAllocator *alloc; |
| 96 | QOSGraphObject *parent = NULL; |
| 97 | QOSGraphEdge *edge; |
| 98 | QOSGraphNode *node; |
| 99 | void *edge_arg; |
| 100 | void *obj; |
| 101 | |
| 102 | node = qos_graph_get_node(path[current]); |
| 103 | g_assert(node->type == QNODE_MACHINE); |
| 104 | |
| 105 | obj = qos_machine_new(node, qts); |
| 106 | qos_object_queue_destroy(obj); |
| 107 | |
| 108 | alloc = get_machine_allocator(obj); |
| 109 | if (p_alloc) { |
| 110 | *p_alloc = alloc; |
| 111 | } |
| 112 | |
| 113 | for (;;) { |
| 114 | if (node->type != QNODE_INTERFACE) { |
| 115 | qos_object_start_hw(obj); |
| 116 | parent = obj; |
| 117 | } |
| 118 | |
| 119 | /* follow edge and get object for next node constructor */ |
| 120 | current++; |
| 121 | edge = qos_graph_get_edge(path[current - 1], path[current]); |
| 122 | node = qos_graph_get_node(path[current]); |
| 123 | |
| 124 | if (node->type == QNODE_TEST) { |
| 125 | g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY); |
| 126 | return obj; |
| 127 | } |
| 128 | |
| 129 | switch (qos_graph_edge_get_type(edge)) { |
| 130 | case QEDGE_PRODUCES: |
| 131 | obj = parent->get_driver(parent, path[current]); |
| 132 | break; |
| 133 | |
| 134 | case QEDGE_CONSUMED_BY: |
| 135 | edge_arg = qos_graph_edge_get_arg(edge); |
| 136 | obj = qos_driver_new(node, obj, alloc, edge_arg); |
| 137 | qos_object_queue_destroy(obj); |
| 138 | break; |
| 139 | |
| 140 | case QEDGE_CONTAINS: |
| 141 | obj = parent->get_device(parent, path[current]); |
| 142 | break; |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 |