From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531127778068436.2245016216647; Mon, 9 Jul 2018 02:16:18 -0700 (PDT) Received: from localhost ([::1]:40000 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSHI-0007se-J6 for importer@patchew.org; Mon, 09 Jul 2018 05:16:16 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38447) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSE2-0005Rq-2r for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSDw-0007HY-JM for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:54 -0400 Received: from mail-ed1-x544.google.com ([2a00:1450:4864:20::544]:41477) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSDw-0007Gl-4a for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:48 -0400 Received: by mail-ed1-x544.google.com with SMTP id b12-v6so13343223edt.8 for ; Mon, 09 Jul 2018 02:12:48 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=nPCJQJ5O4jU6lGbliGuCC5YOUXqCupHJ9Xn9DKaqSAw=; b=DZg0LKg+rrI85qMQFNCXIJiz7p2XRXw0Ypef7h92tdOqEsX0pVXqs9Qnx8KBzNozdV vXopFc+0aAFrzoej2gJMWkN1tmf+cJ6AQT0Uu1wMd4jknYfyDLw5vCxsFFvRtWyoz23K ILRi6/xTZ4bys8gqNo9XV72uJsuoaEe362DUmEeTVJC1zgCWDsatAmQhNbgVhd2EUr0T 1uBNKeIbr9IRRLl9C9a252eOYh4mkY5ZZK7zhxlYSFmnBohK7bN8wpT769FpC7IP95W3 d9fSrm1LEdRb95FgbDTF7+6Lg8THZALs1jqw2AmiOif1TAHLM1AZ/JTwQ8c2uLUSRRhV VX4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=nPCJQJ5O4jU6lGbliGuCC5YOUXqCupHJ9Xn9DKaqSAw=; b=WwI8KHqNkixDLjQjqkhqvoXY8vs/GGzc13crpjz7IkhMlCFzxmwu2a0W/fRJmfkyIg KJTq/aAPGqKznPzOd/y11KoUh2EVvGx/2iG9TFx+KAHNqHRTJYS+yEGFXkCHg0P2Nycp FuDP3Q/N00hgkS7uZonsq9uTcOcDHMkBiU7AqnDOQUpONnTXX43HaoT7CquR0L56IDTo R0D8pTRtJvqZ7fw4jIT41t7pGDCiPk6trYR7WQJoIX0mdGwr4aRI/gy7F/Mw10nSlXKG R7wWe5SH5k3S8eA9QL/uCwf9uRIpBBxqK1t9KtjusOFnhPctdyKaKCoTGpwNbtUU2/ei Ub4Q== X-Gm-Message-State: APt69E2XFmYy5Ua6Dh2XSMQmnhsaEZyMZJ/lV5FcxIkQCf0PNE0FdhTL Q9GiYlojoAg4DFOXlYwBYQ0= X-Google-Smtp-Source: AAOMgpeNEAtGVEZ0Oa5DBT2Xp40VG/ACtfZWH4MPdCJsKJJis7H1aM6xKV2St5NTsXErngAW3/FpGA== X-Received: by 2002:a50:d01a:: with SMTP id j26-v6mr21323848edf.15.1531127566373; Mon, 09 Jul 2018 02:12:46 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:30 +0200 Message-Id: <20180709091136.28849-2-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::544 Subject: [Qemu-devel] [PATCH 1/7] tests: qgraph API for the qtest driver framework X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add qgraph API that allows to add/remove nodes and edges from the graph, implementation of Depth First Search to discover the paths and basic unit test to check correctness of the API. graph.h provides the public API to manage the graph nodes/edges graph_extra.h provides a more private API used successively by the gtest in= tegration part Signed-off-by: Emanuele Giuseppe Esposito --- configure | 2 +- include/qemu/module.h | 2 + tests/Makefile.include | 5 + tests/libqos/qgraph.c | 676 ++++++++++++++++++++++++++++++++++++ tests/libqos/qgraph.h | 259 ++++++++++++++ tests/libqos/qgraph_extra.h | 155 +++++++++ tests/test-qgraph.c | 446 ++++++++++++++++++++++++ 7 files changed, 1544 insertions(+), 1 deletion(-) create mode 100644 tests/libqos/qgraph.c create mode 100644 tests/libqos/qgraph.h create mode 100644 tests/libqos/qgraph_extra.h create mode 100644 tests/test-qgraph.c diff --git a/configure b/configure index 2a7796ea80..85a108506a 100755 --- a/configure +++ b/configure @@ -7352,7 +7352,7 @@ if test "$ccache_cpp2" =3D "yes"; then fi =20 # build tree in object directory in case the source is not in the current = directory -DIRS=3D"tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/q= api-schema tests/tcg/xtensa tests/qemu-iotests tests/vm" +DIRS=3D"tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/q= api-schema tests/tcg/xtensa tests/qemu-iotests tests/vm tests/qgraph" DIRS=3D"$DIRS docs docs/interop fsdev scsi" DIRS=3D"$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" DIRS=3D"$DIRS roms/seabios roms/vgabios" diff --git a/include/qemu/module.h b/include/qemu/module.h index 54300ab6e5..1fcdca084d 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -44,6 +44,7 @@ typedef enum { MODULE_INIT_OPTS, MODULE_INIT_QOM, MODULE_INIT_TRACE, + MODULE_INIT_LIBQOS, MODULE_INIT_MAX } module_init_type; =20 @@ -51,6 +52,7 @@ typedef enum { #define opts_init(function) module_init(function, MODULE_INIT_OPTS) #define type_init(function) module_init(function, MODULE_INIT_QOM) #define trace_init(function) module_init(function, MODULE_INIT_TRACE) +#define libqos_init(function) module_init(function, MODULE_INIT_LIBQOS) =20 #define block_module_load_one(lib) module_load_one("block-", lib) #define ui_module_load_one(lib) module_load_one("ui-", lib) diff --git a/tests/Makefile.include b/tests/Makefile.include index a49282704e..b16bbd55df 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -769,6 +769,11 @@ libqos-imx-obj-y =3D $(libqos-obj-y) tests/libqos/i2c-= imx.o libqos-usb-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos= /usb.o libqos-virtio-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/lib= qos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/lib= qos/malloc-generic.o =20 +libqgraph-obj-y =3D tests/libqos/qgraph.o + +check-unit-y +=3D tests/test-qgraph$(EXESUF) +tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y) + tests/qmp-test$(EXESUF): tests/qmp-test.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o tests/rtc-test$(EXESUF): tests/rtc-test.o diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c new file mode 100644 index 0000000000..5e37ba9f6d --- /dev/null +++ b/tests/libqos/qgraph.c @@ -0,0 +1,676 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/queue.h" +#include "qgraph.h" +#include "qgraph_extra.h" + +#define QOS_ROOT "" +typedef struct QOSStackElement QOSStackElement; + +/* Graph Edge.*/ +struct QOSGraphEdge { + QOSEdgeType type; + char *dest; + char *arg; /* just for CONTAIS and CONSUMED_BY */ + QSLIST_ENTRY(QOSGraphEdge) edge_list; +}; + +/* Linked list grouping all edges with the same source node */ +QSLIST_HEAD(QOSGraphEdgeList, QOSGraphEdge); + + +/** + * Stack used to keep track of the discovered path when using + * the DFS algorithm + */ +struct QOSStackElement { + QOSGraphNode *node; + QOSStackElement *parent; + QOSGraphEdge *parent_edge; + int length; +}; + +/* Each enty in these hash table will consist of pair.= */ +static GHashTable *edge_table; +static GHashTable *node_table; + +/* stack used by the DFS algorithm to store the path from machine to test = */ +static QOSStackElement qos_node_stack[QOS_PATH_MAX_ELEMENT_SIZE]; +static int qos_node_tos; + +/** + * add_edge_arg(): creates an edge of type @type + * from @source to @dest node, and inserts it in the + * edges hash table + * + * Nodes @source and @dest do not necessarily need to exist. + * Adds also an optional command line arg. + */ +static void add_edge_arg(const char *source, const char *dest, + QOSEdgeType type, const char *arg) +{ + char *key; + QOSGraphEdgeList *list =3D g_hash_table_lookup(edge_table, source); + if (!list) { + list =3D g_new0(QOSGraphEdgeList, 1); + key =3D g_strdup(source); + g_hash_table_insert(edge_table, key, list); + } + + QOSGraphEdge *edge =3D g_new0(QOSGraphEdge, 1); + edge->type =3D type; + edge->dest =3D g_strdup(dest); + if (arg) { + edge->arg =3D g_strconcat(",", arg, NULL); + } + QSLIST_INSERT_HEAD(list, edge, edge_list); +} + +/* add_edge(): same as add_edge_arg, but the arg is null */ +static void add_edge(const char *source, const char *dest, QOSEdgeType typ= e) +{ + add_edge_arg(source, dest, type, NULL); +} + +/* remove_edges(): removes all edges inside a given @list */ +static void remove_edges(void *list) +{ + QOSGraphEdge *temp; + QOSGraphEdgeList *elist =3D list; + + while (!QSLIST_EMPTY(elist)) { + temp =3D QSLIST_FIRST(elist); + QSLIST_REMOVE_HEAD(elist, edge_list); + free(temp); + } + g_free(elist); +} + +/** + * create_node(): creates a node @name of type @type + * and inserts it to the nodes hash table. + * By default, node is not available. + */ +static QOSGraphNode *create_node(const char *name, QOSNodeType type) +{ + if (g_hash_table_lookup(node_table, name)) { + g_printerr("Node %s already created\n", name); + abort(); + } + + QOSGraphNode *node =3D g_new0(QOSGraphNode, 1); + node->type =3D type; + node->available =3D FALSE; + node->name =3D g_strdup(name); + g_hash_table_insert(node_table, node->name, node); + return node; +} + +/** + * remove_node(): removes a node @val from the nodes hash table. + * Note that node->name is not free'd since it will represent the + * hash table key + */ +static void remove_node(void *val) +{ + QOSGraphNode *node =3D (QOSGraphNode *) val; + g_free(node->command_line); + g_free(node); +} + +/** + * remove_string(): removes @key from the nodes hash table. + * Actually frees the node->name + */ +static void remove_string(void *key) +{ + g_free(key); +} + +/** + * search_node(): search for a node @key in the nodes hash table + * Returns the QOSGraphNode if found, fails otherwise + */ +static QOSGraphNode *search_node(const char *key) +{ + return g_hash_table_lookup(node_table, key); +} + +/** + * get_edgelist(): returns the edge list (value) assigned to + * the @key in the edge hash table. + * This list will contain all edges with source equal to @key + * + * Returns: on success: the %QOSGraphEdgeList + * otherwise: abort() + */ +static QOSGraphEdgeList *get_edgelist(const char *key) +{ + return g_hash_table_lookup(edge_table, key); +} + +/** + * search_list_edges(): search for an edge with destination @dest + * in the given @edgelist. + * + * Returns: on success: the %QOSGraphEdge + * otherwise: #NULL + */ +static QOSGraphEdge *search_list_edges(QOSGraphEdgeList *edgelist, + const char *dest) +{ + QOSGraphEdge *tmp, *next; + if (!edgelist) { + return NULL; + } + QSLIST_FOREACH_SAFE(tmp, edgelist, edge_list, next) { + if (g_strcmp0(tmp->dest, dest) =3D=3D 0) { + break; + } + } + return tmp; +} + +/** + * search_machine(): search for a machine @name in the node hash + * table. A machine is the child of the root node. + * This function forces the research in the childs of the root, + * to check the node is a proper machine + * + * Returns: on success: the %QOSGraphNode + * otherwise: #NULL + */ +static QOSGraphNode *search_machine(const char *name) +{ + QOSGraphNode *n; + QOSGraphEdgeList *root_list =3D get_edgelist(QOS_ROOT); + QOSGraphEdge *e =3D search_list_edges(root_list, name); + if (!e) { + return NULL; + } + n =3D search_node(e->dest); + if (n->type =3D=3D MACHINE) { + return n; + } + return NULL; +} + +/** + * build_machine_cmd_line(): builds the command line for the machine + * @node. The node name must be a valid qemu identifier, since it + * will be used to build the command line. + * + * It is also possible to pass an optional @args that will be + * concatenated to the command line. + * + * For machines, prepend -M to the machine name. + */ +static void build_machine_cmd_line(QOSGraphNode *node, const char *args) +{ + char *arch, *machine; + qos_separate_arch_machine(node->name, &arch, &machine); + if (args) { + node->command_line =3D g_strconcat("-M ", machine, ",", args, NULL= ); + } else { + node->command_line =3D g_strconcat("-M ", machine, NULL); + } +} + +/** + * build_driver_cmd_line(): builds the command line for the driver + * @node. The node name must be a valid qemu identifier, since it + * will be used to build the command line. + * + * It is also possible to pass an optional @args that will be + * concatenated to the command line. + * + * For drivers, prepend -device to the driver name. + */ +static void build_driver_cmd_line(QOSGraphNode *node, const char *args) +{ + if (args) { + node->command_line =3D g_strconcat("-device ", node->name, ",", + args, NULL); + } else { + node->command_line =3D g_strconcat("-device ", node->name, NULL); + } +} + +/** + * build_test_cmd_line(): builds the command line for the test + * @node. The node name need not to be a valid qemu identifier, since it + * will not be used to build the command line. + * + * It is also possible to pass an optional @args that will be + * used as additional command line. + */ +static void build_test_cmd_line(QOSGraphNode *node, const char *args) +{ + if (args) { + node->command_line =3D g_strdup(args); + } else { + node->command_line =3D NULL; + } +} + +/* qos_print_cb(): callback prints all path found by the DFS algorithm. */ +static void qos_print_cb(QOSGraphNode *path, int length) +{ + #if PRINT_DEBUG + printf("%d elements\n", length); + + if (!path) { + return; + } + + while (path->path_edge) { + printf("%s ", path->name); + switch (path->path_edge->type) { + case PRODUCES: + printf("--PRODUCES--> "); + break; + case CONSUMED_BY: + printf("--CONSUMED_BY--> "); + break; + case CONTAINS: + printf("--CONTAINS--> "); + break; + } + path =3D search_node(path->path_edge->dest); + } + + printf("%s\n\n", path->name); + #endif +} + +/* qos_push(): push a node @el and edge @e in the qos_node_stack */ +static void qos_push(QOSGraphNode *el, QOSStackElement *parent, + QOSGraphEdge *e) +{ + int len =3D 0; /* root is not counted */ + if (qos_node_tos =3D=3D QOS_PATH_MAX_ELEMENT_SIZE) { + g_printerr("QOSStack: full stack, cannot push"); + abort(); + } + + if (parent) { + len =3D parent->length + 1; + } + qos_node_stack[qos_node_tos++] =3D (QOSStackElement) {el, parent, e, l= en}; +} + +/* qos_tos(): returns the top of stack, without popping */ +static QOSStackElement *qos_tos(void) +{ + return &qos_node_stack[(qos_node_tos - 1)]; +} + +/* qos_pop(): pops an element from the tos, setting it unvisited*/ +static QOSStackElement *qos_pop(void) +{ + if (qos_node_tos =3D=3D 0) { + g_printerr("QOSStack: empty stack, cannot pop"); + abort(); + } + QOSStackElement *e =3D qos_tos(); + e->node->visited =3D FALSE; + qos_node_tos--; + return e; +} + +/** + * qos_reverse_path(): reverses the found path, going from + * test-to-machine to machine-to-test + */ +static QOSGraphNode *qos_reverse_path(QOSStackElement *el) +{ + if (!el) { + return NULL; + } + + el->node->path_edge =3D NULL; + + while (el->parent->length > 0) { + el->parent->node->path_edge =3D el->parent_edge; + el =3D el->parent; + } + + return el->node; +} + +/** + * qos_traverse_graph(): graph-walking algorithm, using Depth First Search= it + * starts from the root @machine and walks all possible path until it + * reaches a test node. + * At that point, it reverses the path found and invokes the @callback. + * + * Being Depth First Search, time complexity is O(|V| + |E|), while + * space is O(|V|). In this case, the maximum stack size is set by + * QOS_PATH_MAX_ELEMENT_SIZE. + */ +static void qos_traverse_graph(QOSGraphNode *machine, QOSTestCallback call= back) +{ + QOSGraphNode *v, *dest_node, *path; + QOSStackElement *s_el; + QOSGraphEdge *e, *next; + QOSGraphEdgeList *list; + + qos_push(machine, NULL, NULL); + + while (qos_node_tos > 0) { + s_el =3D qos_tos(); + v =3D s_el->node; + if (v->visited) { + qos_pop(); + continue; + } + v->visited =3D TRUE; + list =3D get_edgelist(v->name); + if (!list) { + qos_pop(); + if (v->type =3D=3D TEST) { + v->visited =3D FALSE; + path =3D qos_reverse_path(s_el); + callback(path, s_el->length); + } + } else { + QSLIST_FOREACH_SAFE(e, list, edge_list, next) { + dest_node =3D search_node(e->dest); + + if (!dest_node) { + printf("node %s in %s -> %s does not exist\n", + e->dest, v->name, e->dest); + abort(); + } + + if (!dest_node->visited && dest_node->available) { + qos_push(dest_node, s_el, e); + } + } + } + } +} + +/* QGRAPH API*/ + +QOSGraphNode *qos_graph_get_node(const char *key) +{ + return search_node(key); +} + +bool qos_graph_has_node(const char *node) +{ + QOSGraphNode *n =3D search_node(node); + return n !=3D NULL; +} + +QOSNodeType qos_graph_get_node_type(const char *node) +{ + QOSGraphNode *n =3D search_node(node); + if (n) { + return n->type; + } + return -1; +} + +bool qos_graph_get_node_availability(const char *node) +{ + QOSGraphNode *n =3D search_node(node); + if (n) { + return n->available; + } + return FALSE; +} + +QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest) +{ + QOSGraphEdgeList *list =3D get_edgelist(node); + return search_list_edges(list, dest); +} + +QOSEdgeType qos_graph_get_edge_type(const char *node1, const char *node2) +{ + QOSGraphEdgeList *list =3D get_edgelist(node1); + QOSGraphEdge *e =3D search_list_edges(list, node2); + if (e) { + return e->type; + } + return -1; +} + +char *qos_graph_get_edge_dest(QOSGraphEdge *edge) +{ + if (!edge) { + return NULL; + } + return edge->dest; +} + +char *qos_graph_get_edge_arg(QOSGraphEdge *edge) +{ + if (!edge) { + return NULL; + } + return edge->arg; +} + +bool qos_graph_has_edge(const char *start, const char *dest) +{ + QOSGraphEdgeList *list =3D get_edgelist(start); + QOSGraphEdge *e =3D search_list_edges(list, dest); + if (e) { + return TRUE; + } + return FALSE; +} + +QOSGraphNode *qos_graph_get_machine(const char *node) +{ + return search_machine(node); +} + +bool qos_graph_has_machine(const char *node) +{ + QOSGraphNode *m =3D search_machine(node); + return m !=3D NULL; +} + +void qos_print_graph(void) +{ + qos_graph_foreach_test_path(qos_print_cb); +} + +void qos_graph_init(void) +{ + if (!node_table) { + node_table =3D g_hash_table_new_full(g_str_hash, g_str_equal, + remove_string, remove_node); + create_node(QOS_ROOT, DRIVER); + } + + if (!edge_table) { + edge_table =3D g_hash_table_new_full(g_str_hash, g_str_equal, + remove_string, remove_edges); + } +} + +void qos_graph_destroy(void) +{ + if (node_table) { + g_hash_table_destroy(node_table); + } + + if (edge_table) { + g_hash_table_destroy(edge_table); + } + + node_table =3D NULL; + edge_table =3D NULL; +} + +void qos_node_destroy(void *key) +{ + g_hash_table_remove(node_table, key); +} + +void qos_edge_destroy(void *key) +{ + g_hash_table_remove(edge_table, key); +} + +void qos_add_test(const char *name, const char *driver, QOSTestFunc test_f= unc) +{ + qos_add_test_data_args(name, driver, test_func, NULL, NULL); +} + +void qos_add_test_args(const char *name, const char *driver, + QOSTestFunc test_func, const char *extra_args) +{ + qos_add_test_data_args(name, driver, test_func, NULL, extra_args); +} + +void qos_add_test_data(const char *name, const char *driver, + QOSTestFunc test_func, void *arg) +{ + qos_add_test_data_args(name, driver, test_func, arg, NULL); +} + +void qos_add_test_data_args(const char *name, const char *driver, + QOSTestFunc test_func, void *arg, + const char *extra_args) +{ + QOSGraphNode *node =3D create_node(name, TEST); + build_test_cmd_line(node, extra_args); + node->u.test.function =3D test_func; + node->u.test.arg =3D arg; + node->available =3D TRUE; + add_edge(driver, name, CONSUMED_BY); +} + +void qos_node_create_machine(const char *name, QOSCreateMachineFunc functi= on) +{ + qos_node_create_machine_args(name, function, NULL); +} + +void qos_node_create_machine_args(const char *name, + QOSCreateMachineFunc function, + const char *extra_args) +{ + QOSGraphNode *node =3D create_node(name, MACHINE); + build_machine_cmd_line(node, extra_args); + node->u.machine.constructor =3D function; + add_edge(QOS_ROOT, name, CONTAINS); +} + +void qos_node_create_driver(const char *name, QOSCreateDriverFunc function) +{ + qos_node_create_driver_args(name, function, NULL); +} + +void qos_node_create_driver_args(const char *name, + QOSCreateDriverFunc function, + const char *extra_args) +{ + QOSGraphNode *node =3D create_node(name, DRIVER); + build_driver_cmd_line(node, extra_args); + node->u.driver.constructor =3D function; +} + +void qos_node_create_interface(const char *name) +{ + create_node(name, INTERFACE); +} + +void qos_node_contains(const char *container, const char *contained) +{ + add_edge(container, contained, CONTAINS); +} + +void qos_node_contains_arg(const char *container, const char *contained, + const char *arg) +{ + add_edge_arg(container, contained, CONTAINS, arg); +} + +void qos_node_produces(const char *producer, const char *produced) +{ + add_edge(producer, produced, PRODUCES); +} + +void qos_node_consumes(const char *consumer, const char *consumed) +{ + add_edge(consumed, consumer, CONSUMED_BY); +} + +void qos_node_consumes_arg(const char *consumer, const char *consumed, + const char *arg) +{ + add_edge_arg(consumed, consumer, CONSUMED_BY, arg); +} + +void qos_graph_node_set_availability(const char *node, bool av) +{ + QOSGraphEdgeList *elist; + QOSGraphNode *n =3D search_node(node); + QOSGraphEdge *e, *next; + if (!n) { + return; + } + n->available =3D av; + elist =3D get_edgelist(node); + if (!elist) { + return; + } + QSLIST_FOREACH_SAFE(e, elist, edge_list, next) { + if (e->type =3D=3D CONTAINS || e->type =3D=3D PRODUCES) { + qos_graph_node_set_availability(e->dest, av); + } + } +} + +void qos_graph_foreach_test_path(QOSTestCallback fn) +{ + QOSGraphNode *root =3D qos_graph_get_node(QOS_ROOT); + qos_traverse_graph(root, fn); +} + +void qos_destroy_object(QOSGraphObject *obj) +{ + if (!obj || !(obj->destructor)) { + return; + } + obj->destructor(obj); +} + +void qos_separate_arch_machine(char *name, char **arch, char **machine) +{ + *arch =3D name; + while (*name !=3D '\0' && *name !=3D '/') { + name++; + } + + if (*name =3D=3D '/' && (*name + 1) !=3D '\0') { + *machine =3D name + 1; + } else { + printf("Machine name has to be of the form /\n"); + abort(); + } +} diff --git a/tests/libqos/qgraph.h b/tests/libqos/qgraph.h new file mode 100644 index 0000000000..54a1786c1e --- /dev/null +++ b/tests/libqos/qgraph.h @@ -0,0 +1,259 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#ifndef QGRAPH_H +#define QGRAPH_H + +#include +#include +#include +#include +#include +#include "qemu/module.h" + +/* maximum path length */ +#define QOS_PATH_MAX_ELEMENT_SIZE 50 + +typedef struct QOSGraphMachine QOSGraphMachine; +typedef struct QOSGraphMachineList QOSGraphMachineList; +typedef struct QOSGraphObject QOSGraphObject; +typedef struct QOSGraphNode QOSGraphNode; +typedef struct QOSGraphEdge QOSGraphEdge; +typedef struct QOSGraphEdgeList QOSGraphEdgeList; +typedef enum QOSEdgeType QOSEdgeType; +typedef enum QOSNodeType QOSNodeType; + +typedef void *(*QOSCreateDriverFunc) (void *parent, QOSGraphObject *alloc); +typedef void *(*QOSCreateMachineFunc) (void); +typedef void (*QOSTestFunc) (void *parent, void *arg); +typedef void (*QOSTestCallback) (QOSGraphNode *path, int len); + +typedef void *(*QOSGetDriver) (void *object, const char *interface); +typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name); +typedef void (*QOSDestructorFunc) (QOSGraphObject *object); + +/* edge types*/ +enum QOSEdgeType { + CONTAINS, + PRODUCES, + CONSUMED_BY +}; + +/* node types*/ +enum QOSNodeType { + MACHINE, + DRIVER, + INTERFACE, + TEST +}; + +/** + * Each driver, test or machine will have this as first field. + * Depending on the edge, the node will call the corresponding + * function when walking the path. + * + * QOSGraphObject also provides a destructor, used to deallocate the + * after the test has been executed. + */ +struct QOSGraphObject { + /* for produces, returns void * */ + QOSGetDriver get_driver; + /* for contains, returns a QOSGraphObject * */ + QOSGetDevice get_device; + /* destroy this QOSGraphObject */ + QOSDestructorFunc destructor; +}; + +/* Graph Node */ +struct QOSGraphNode { + QOSNodeType type; + bool available; /* set by QEMU via QMP, used during graph walk */ + bool visited; /* used during graph walk */ + char *name; /* used to identify the node */ + char *command_line; /* used to start QEMU at test execution */ + union { + struct { + QOSCreateDriverFunc constructor; + } driver; + struct { + QOSCreateMachineFunc constructor; + } machine; + struct { + QOSTestFunc function; + void *arg; + } test; + } u; + + /** + * only used when traversing the path, never rely on that except in the + * qos_traverse_graph callback function + */ + QOSGraphEdge *path_edge; +}; + +/** + * qos_graph_init(): initialize the framework, creates two hash + * tables: one for the nodes and another for the edges. + */ +void qos_graph_init(void); + +/** + * qos_graph_destroy(): deallocates all the hash tables, + * freeing all nodes and edges. + */ +void qos_graph_destroy(void); + +/** + * qos_node_destroy(): removes and frees a node from the, + * nodes hash table. + */ +void qos_node_destroy(void *key); + +/** + * qos_edge_destroy(): removes and frees an edge from the, + * edges hash table. + */ +void qos_edge_destroy(void *key); + +/** + * qos_add_test(): adds a test node @name to the nodes hash table. + * + * The test will consume a @driver node, and once the + * graph walking algorithm has found it, the @test_func will be + * executed. + */ +void qos_add_test(const char *name, const char *driver, QOSTestFunc test_f= unc); + +/** + * qos_add_test_args(): same as qos_add_test, with the possibility to + * add an optional @extra_args for the command line. + */ +void qos_add_test_args(const char *name, const char *driver, + QOSTestFunc test_func, + const char *extra_args); + +/** + * qos_add_test(): adds a test node @name to the nodes hash table. + * + * The test will consume a @driver node, and once the + * graph walking algorithm has found it, the @test_func will be + * executed passing @arg as parameter. + */ +void qos_add_test_data(const char *name, const char *driver, + QOSTestFunc test_func, void *arg); + +/** + * qos_add_test_data_args(): same as qos_add_test_data, with the possibili= ty to + * add an optional @extra_args for the command line. + */ +void qos_add_test_data_args(const char *name, const char *driver, + QOSTestFunc test_func, void *arg, + const char *extra_args); + +/** + * qos_node_create_machine(): creates the machine @name and + * adds it to the node hash table. + * + * This node will be of type MACHINE and have @function as constructor + */ +void qos_node_create_machine(const char *name, QOSCreateMachineFunc functi= on); + +/** + * qos_node_create_machine_args(): same as qos_node_create_machine, + * but with the possibility to add an optional @extra_args to the + * command line. + */ +void qos_node_create_machine_args(const char *name, + QOSCreateMachineFunc function, + const char *extra_args); + +/** + * qos_node_create_driver(): creates the driver @name and + * adds it to the node hash table. + * + * This node will be of type DRIVER and have @function as constructor + */ +void qos_node_create_driver(const char *name, QOSCreateDriverFunc function= ); + +/** + * qos_node_create_driver_args(): same as qos_node_create_driver, + * but with the possibility to add an optional @extra_args to the + * command line. + */ +void qos_node_create_driver_args(const char *name, + QOSCreateDriverFunc function, + const char *extra_args); + +/** + * qos_node_create_driver(): creates the interface @name and + * adds it to the node hash table. + * + * This node will be of type INTERFACE and won't have any constructor + */ +void qos_node_create_interface(const char *name); + +/** + * qos_node_contains(): creates the edge CONTAINS and + * adds it to the edge list mapped to @container in the + * edge hash table. + * + * This edge will have @container as source and @contained as destination. + */ +void qos_node_contains(const char *container, const char *contained); + +/** + * qos_node_contains_arg(): same as qos_node_contains, + * but with the possibility to add an optional @arg to the + * command line. + */ +void qos_node_contains_arg(const char *container, const char *contained, + const char *arg); + +/** + * qos_node_produces(): creates the edge PRODUCES and + * adds it to the edge list mapped to @producer in the + * edge hash table. + * + * This edge will have @producer as source and @produced as destination. + */ +void qos_node_produces(const char *producer, const char *produced); + +/** + * qos_node_consumes(): creates the edge CONSUMED_BY and + * adds it to the edge list mapped to @consumed in the + * edge hash table. + * + * This edge will have @consumed as source and @consumer as destination. + */ +void qos_node_consumes(const char *consumer, const char *consumed); + +/** + * qos_node_consumes_arg(): same as qos_node_consumes, + * but with the possibility to add an optional @arg to the + * command line. + */ +void qos_node_consumes_arg(const char *consumer, const char *consumed, + const char *arg); + +/** + * qos_graph_node_set_availability(): sets the node identified + * by @node with availability @av. + */ +void qos_graph_node_set_availability(const char *node, bool av); + +#endif diff --git a/tests/libqos/qgraph_extra.h b/tests/libqos/qgraph_extra.h new file mode 100644 index 0000000000..22850c0368 --- /dev/null +++ b/tests/libqos/qgraph_extra.h @@ -0,0 +1,155 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#ifndef QGRAPH_EXTRA_H +#define QGRAPH_EXTRA_H + +#include "qgraph.h" +#define PRINT_DEBUG 0 + +/** + * qos_graph_get_node(): returns the node mapped to that @key. + * It performs an hash map search O(1) + * + * Returns: on success: the %QOSGraphNode + * otherwise: #NULL + */ +QOSGraphNode *qos_graph_get_node(const char *key); + +/** + * qos_graph_has_node(): returns #TRUE if the node + * has map has a node mapped to that @key. + */ +bool qos_graph_has_node(const char *node); + +/** + * qos_graph_get_node_type(): returns the %QOSNodeType + * of the node @node. + * It performs an hash map search O(1) + * Returns: on success: the %QOSNodeType + * otherwise: #-1 + */ +QOSNodeType qos_graph_get_node_type(const char *node); + +/** + * qos_graph_get_node_availability(): returns the availability (boolean) + * of the node @node. + */ +bool qos_graph_get_node_availability(const char *node); + +/** + * qos_graph_get_edge(): returns the edge + * linking of the node @node with @dest. + * + * Returns: on success: the %QOSGraphEdge + * otherwise: #NULL + */ +QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest); + +/** + * qos_graph_get_edge_type(): returns the edge type + * of the edge linking of the node @start with @dest. + * + * Returns: on success: the %QOSEdgeType + * otherwise: #-1 + */ +QOSEdgeType qos_graph_get_edge_type(const char *start, const char *dest); + +/** + * qos_graph_get_edge_dest(): returns the name of the node + * pointed as destination of edge @edge. + * + * Returns: on success: the destination + * otherwise: #NULL + */ +char *qos_graph_get_edge_dest(QOSGraphEdge *edge); + +/** + * qos_graph_has_edge(): returns #TRUE if there + * exists an edge from @start to @dest. + */ +bool qos_graph_has_edge(const char *start, const char *dest); + +/** + * qos_graph_get_edge_arg(): returns the args assigned + * to that @edge. + * + * Returns: on success: the arg + * otherwise: #NULL + */ +char *qos_graph_get_edge_arg(QOSGraphEdge *edge); + +/** + * qos_graph_get_machine(): returns the machine assigned + * to that @node name. + * + * It performs a search only trough the list of machines + * (i.e. the QOS_ROOT child). + * + * Returns: on success: the %QOSGraphNode + * otherwise: #NULL + */ +QOSGraphNode *qos_graph_get_machine(const char *node); + +/** + * qos_graph_has_machine(): returns #TRUE if the node + * has map has a node mapped to that @node. + */ +bool qos_graph_has_machine(const char *node); + + +/** + * qos_print_graph(): walks the graph and prints + * all machine-to-test paths. + */ +void qos_print_graph(void); + +/** + * qos_graph_foreach_test_path(): executes the Depth First search + * algorithm and applies @fn to all discovered paths. + * + * See qos_traverse_graph() in qgraph.c for more info on + * how it works. + */ +void qos_graph_foreach_test_path(QOSTestCallback fn); + +/** + * qos_destroy_object(): calls the destructor for @obj + */ +void qos_destroy_object(QOSGraphObject *obj); + +/** + * qos_separate_arch_machine(): separate arch from machine. + * This function requires every machine @name to be in the form + * /, like "arm/raspi2" or "x86_64/pc". + * + * The function will split then the string in two parts, + * assigning @arch to point to /, and + * @machine to . + * + * For example, "x86_64/pc" will be split in this way: + * *arch =3D "x86_64/pc" + * *machine =3D "pc" + * + * Note that this function *does not* allocate any new string, + * but just sets the pointer *arch and *machine to the respective + * part of the string. + */ +void qos_separate_arch_machine(char *name, char **arch, char **machine); + +#endif diff --git a/tests/test-qgraph.c b/tests/test-qgraph.c new file mode 100644 index 0000000000..64bd32ec86 --- /dev/null +++ b/tests/test-qgraph.c @@ -0,0 +1,446 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/qgraph.h" +#include "libqos/qgraph_extra.h" + +#define MACHINE_PC "x86_64/pc" +#define MACHINE_RASPI2 "arm/raspi2" +#define I440FX "i440FX-pcihost" +#define PCIBUS_PC "pcibus-pc" +#define SDHCI "sdhci" +#define PCIBUS "pci-bus" +#define SDHCI_PCI "sdhci-pci" +#define SDHCI_MM "generic-sdhci" +#define REGISTER_TEST "register-test" + +int npath; + +static void *machinefunct(void) +{ + return NULL; +} + +static void *driverfunct(void *obj, QOSGraphObject *machine) +{ + return NULL; +} + +static void testfunct(void *obj, void *arg) +{ + return; +} + +static void check_machine(const char *machine) +{ + qos_node_create_machine(machine, machinefunct); + g_assert_nonnull(qos_graph_get_machine(machine)); + g_assert_cmpint(qos_graph_has_machine(machine), =3D=3D, TRUE); + g_assert_nonnull(qos_graph_get_node(machine)); + g_assert_cmpint(qos_graph_get_node_availability(machine), =3D=3D, FALS= E); + qos_graph_node_set_availability(machine, TRUE); + g_assert_cmpint(qos_graph_get_node_availability(machine), =3D=3D, TRUE= ); + g_assert_cmpint(qos_graph_has_node(machine), =3D=3D, TRUE); + g_assert_cmpint(qos_graph_get_node_type(machine), =3D=3D, MACHINE); +} + +static void check_contains(const char *machine, const char *i440fx) +{ + qos_node_contains(machine, i440fx); + g_assert_nonnull(qos_graph_get_edge(machine, i440fx)); + g_assert_cmpint(qos_graph_get_edge_type(machine, i440fx), =3D=3D, CONT= AINS); + g_assert_cmpint(qos_graph_has_edge(machine, i440fx), =3D=3D, TRUE); +} + +static void check_produces(const char *machine, const char *i440fx) +{ + qos_node_produces(machine, i440fx); + g_assert_nonnull(qos_graph_get_edge(machine, i440fx)); + g_assert_cmpint(qos_graph_get_edge_type(machine, i440fx), =3D=3D, PROD= UCES); + g_assert_cmpint(qos_graph_has_edge(machine, i440fx), =3D=3D, TRUE); +} + +static void check_consumes(const char *interface, const char *driver) +{ + qos_node_consumes(driver, interface); + g_assert_nonnull(qos_graph_get_edge(interface, driver)); + g_assert_cmpint( + qos_graph_get_edge_type(interface, driver), =3D=3D, CONSUMED_BY); + g_assert_cmpint(qos_graph_has_edge(interface, driver), =3D=3D, TRUE); +} + +static void check_driver(const char *driver) +{ + qos_node_create_driver(driver, driverfunct); + g_assert_cmpint(qos_graph_has_machine(driver), =3D=3D, FALSE); + g_assert_nonnull(qos_graph_get_node(driver)); + g_assert_cmpint(qos_graph_has_node(driver), =3D=3D, TRUE); + g_assert_cmpint(qos_graph_get_node_type(driver), =3D=3D, DRIVER); + g_assert_cmpint(qos_graph_get_node_availability(driver), =3D=3D, FALSE= ); + qos_graph_node_set_availability(driver, TRUE); + g_assert_cmpint(qos_graph_get_node_availability(driver), =3D=3D, TRUE); +} + +static void check_interface(const char *interface) +{ + qos_node_create_interface(interface); + g_assert_cmpint(qos_graph_has_machine(interface), =3D=3D, FALSE); + g_assert_nonnull(qos_graph_get_node(interface)); + g_assert_cmpint(qos_graph_has_node(interface), =3D=3D, TRUE); + g_assert_cmpint(qos_graph_get_node_type(interface), =3D=3D, INTERFACE); + g_assert_cmpint(qos_graph_get_node_availability(interface), =3D=3D, FA= LSE); + qos_graph_node_set_availability(interface, TRUE); + g_assert_cmpint(qos_graph_get_node_availability(interface), =3D=3D, TR= UE); +} + +static void check_test(const char *test, const char *interface) +{ + qos_add_test(test, interface, testfunct); + g_assert_cmpint(qos_graph_has_machine(test), =3D=3D, FALSE); + g_assert_nonnull(qos_graph_get_node(test)); + g_assert_cmpint(qos_graph_has_node(test), =3D=3D, TRUE); + g_assert_cmpint(qos_graph_get_node_type(test), =3D=3D, TEST); + g_assert_nonnull(qos_graph_get_edge(interface, test)); + g_assert_cmpint(qos_graph_get_edge_type(interface, test), =3D=3D, CONS= UMED_BY); + g_assert_cmpint(qos_graph_has_edge(interface, test), =3D=3D, TRUE); + g_assert_cmpint(qos_graph_get_node_availability(test), =3D=3D, TRUE); + qos_graph_node_set_availability(test, FALSE); + g_assert_cmpint(qos_graph_get_node_availability(test), =3D=3D, FALSE); +} + +static void count_each_test(QOSGraphNode *path, int len) +{ + npath++; +} + +static void check_leaf_discovered(int n) +{ + npath =3D 0; + qos_graph_foreach_test_path(count_each_test); + g_assert_cmpint(n, =3D=3D, npath); +} + +/* G_Test functions */ + +static void init_nop(void) +{ + qos_graph_init(); + qos_graph_destroy(); +} + +static void test_machine(void) +{ + qos_graph_init(); + check_machine(MACHINE_PC); + qos_graph_destroy(); +} + +static void test_contains(void) +{ + qos_graph_init(); + check_contains(MACHINE_PC, I440FX); + g_assert_null(qos_graph_get_machine(MACHINE_PC)); + g_assert_null(qos_graph_get_machine(I440FX)); + g_assert_null(qos_graph_get_node(MACHINE_PC)); + g_assert_null(qos_graph_get_node(I440FX)); + qos_graph_destroy(); +} + +static void test_multiple_contains(void) +{ + qos_graph_init(); + check_contains(MACHINE_PC, I440FX); + check_contains(MACHINE_PC, PCIBUS_PC); + qos_graph_destroy(); +} + +static void test_produces(void) +{ + qos_graph_init(); + check_produces(MACHINE_PC, I440FX); + g_assert_null(qos_graph_get_machine(MACHINE_PC)); + g_assert_null(qos_graph_get_machine(I440FX)); + g_assert_null(qos_graph_get_node(MACHINE_PC)); + g_assert_null(qos_graph_get_node(I440FX)); + qos_graph_destroy(); +} + +static void test_multiple_produces(void) +{ + qos_graph_init(); + check_produces(MACHINE_PC, I440FX); + check_produces(MACHINE_PC, PCIBUS_PC); + qos_graph_destroy(); +} + +static void test_consumed_by(void) +{ + qos_graph_init(); + check_consumes(SDHCI, I440FX); + g_assert_null(qos_graph_get_machine(I440FX)); + g_assert_null(qos_graph_get_machine(SDHCI)); + g_assert_null(qos_graph_get_node(I440FX)); + g_assert_null(qos_graph_get_node(SDHCI)); + qos_graph_destroy(); +} + +static void test_multiple_consumed_by(void) +{ + qos_graph_init(); + check_consumes(SDHCI, I440FX); + check_consumes(SDHCI, PCIBUS_PC); + qos_graph_destroy(); +} + +static void test_driver(void) +{ + qos_graph_init(); + check_driver(I440FX); + qos_graph_destroy(); +} + +static void test_interface(void) +{ + qos_graph_init(); + check_interface(SDHCI); + qos_graph_destroy(); +} + +static void test_test(void) +{ + qos_graph_init(); + check_test(REGISTER_TEST, SDHCI); + qos_graph_destroy(); +} + +static void test_machine_contains_driver(void) +{ + qos_graph_init(); + check_machine(MACHINE_PC); + check_driver(I440FX); + check_contains(MACHINE_PC, I440FX); + qos_graph_destroy(); +} + +static void test_driver_contains_driver(void) +{ + qos_graph_init(); + check_driver(PCIBUS_PC); + check_driver(I440FX); + check_contains(PCIBUS_PC, I440FX); + qos_graph_destroy(); +} + +static void test_machine_produces_interface(void) +{ + qos_graph_init(); + check_machine(MACHINE_PC); + check_interface(SDHCI); + check_produces(MACHINE_PC, SDHCI); + qos_graph_destroy(); +} + +static void test_driver_produces_interface(void) +{ + qos_graph_init(); + check_driver(I440FX); + check_interface(SDHCI); + check_produces(I440FX, SDHCI); + qos_graph_destroy(); +} + +static void test_interface_consumed_by_machine(void) +{ + qos_graph_init(); + check_machine(MACHINE_PC); + check_interface(SDHCI); + check_consumes(SDHCI, MACHINE_PC); + qos_graph_destroy(); +} + +static void test_interface_consumed_by_driver(void) +{ + qos_graph_init(); + check_driver(I440FX); + check_interface(SDHCI); + check_consumes(SDHCI, I440FX); + qos_graph_destroy(); +} + +static void test_interface_consumed_by_test(void) +{ + qos_graph_init(); + check_interface(SDHCI); + check_test(REGISTER_TEST, SDHCI); + qos_graph_destroy(); +} + +static void test_full_sample(void) +{ + qos_graph_init(); + check_machine(MACHINE_PC); + check_contains(MACHINE_PC, I440FX); + check_driver(I440FX); + check_driver(PCIBUS_PC); + check_contains(I440FX, PCIBUS_PC); + check_interface(PCIBUS); + check_produces(PCIBUS_PC, PCIBUS); + check_driver(SDHCI_PCI); + qos_node_consumes(SDHCI_PCI, PCIBUS); + check_produces(SDHCI_PCI, SDHCI); + check_interface(SDHCI); + check_driver(SDHCI_MM); + check_produces(SDHCI_MM, SDHCI); + qos_add_test(REGISTER_TEST, SDHCI, testfunct); + check_leaf_discovered(1); + qos_print_graph(); + qos_graph_destroy(); +} + +static void test_full_sample_raspi(void) +{ + qos_graph_init(); + check_machine(MACHINE_PC); + check_contains(MACHINE_PC, I440FX); + check_driver(I440FX); + check_driver(PCIBUS_PC); + check_contains(I440FX, PCIBUS_PC); + check_interface(PCIBUS); + check_produces(PCIBUS_PC, PCIBUS); + check_driver(SDHCI_PCI); + qos_node_consumes(SDHCI_PCI, PCIBUS); + check_produces(SDHCI_PCI, SDHCI); + check_interface(SDHCI); + check_machine(MACHINE_RASPI2); + check_contains(MACHINE_RASPI2, SDHCI_MM); + check_driver(SDHCI_MM); + check_produces(SDHCI_MM, SDHCI); + qos_add_test(REGISTER_TEST, SDHCI, testfunct); + qos_print_graph(); + check_leaf_discovered(2); + qos_graph_destroy(); +} + +static void test_full_alternative_path(void) +{ + qos_graph_init(); + check_machine(MACHINE_RASPI2); + check_driver("B"); + check_driver("C"); + check_driver("D"); + check_driver("E"); + check_driver("F"); + check_contains(MACHINE_RASPI2, "B"); + check_contains("B", "C"); + check_contains("C", "D"); + check_contains("D", "E"); + check_contains("D", "F"); + qos_add_test("G", "D", testfunct); + check_contains("F", "G"); + check_contains("E", "B"); + qos_print_graph(); + check_leaf_discovered(2); + qos_graph_destroy(); +} + +static void test_cycle(void) +{ + qos_graph_init(); + check_machine(MACHINE_RASPI2); + check_driver("B"); + check_driver("C"); + check_driver("D"); + check_contains(MACHINE_RASPI2, "B"); + check_contains("B", "C"); + check_contains("C", "D"); + check_contains("D", MACHINE_RASPI2); + check_leaf_discovered(0); + qos_print_graph(); + qos_graph_destroy(); +} + +static void test_two_test_same_interface(void) +{ + qos_graph_init(); + check_machine(MACHINE_RASPI2); + check_interface("B"); + qos_add_test("C", "B", testfunct); + qos_add_test("D", "B", testfunct); + check_contains(MACHINE_RASPI2, "B"); + check_leaf_discovered(2); + qos_print_graph(); + qos_graph_destroy(); +} + +static void test_double_edge(void) +{ + qos_graph_init(); + check_machine(MACHINE_RASPI2); + check_driver("B"); + check_driver("C"); + check_produces("B", "C"); + qos_node_consumes("C", "B"); + qos_add_test("D", "C", testfunct); + check_contains(MACHINE_RASPI2, "B"); + qos_print_graph(); + qos_graph_destroy(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/qgraph/init_nop", init_nop); + g_test_add_func("/qgraph/test_machine", test_machine); + g_test_add_func("/qgraph/test_contains", test_contains); + g_test_add_func("/qgraph/test_multiple_contains", test_multiple_contai= ns); + g_test_add_func("/qgraph/test_produces", test_produces); + g_test_add_func("/qgraph/test_multiple_produces", test_multiple_produc= es); + g_test_add_func("/qgraph/test_consumed_by", test_consumed_by); + g_test_add_func("/qgraph/test_multiple_consumed_by", + test_multiple_consumed_by); + g_test_add_func("/qgraph/test_driver", test_driver); + g_test_add_func("/qgraph/test_interface", test_interface); + g_test_add_func("/qgraph/test_test", test_test); + g_test_add_func("/qgraph/test_machine_contains_driver", + test_machine_contains_driver); + g_test_add_func("/qgraph/test_driver_contains_driver", + test_driver_contains_driver); + g_test_add_func("/qgraph/test_machine_produces_interface", + test_machine_produces_interface); + g_test_add_func("/qgraph/test_driver_produces_interface", + test_driver_produces_interface); + g_test_add_func("/qgraph/test_interface_consumed_by_machine", + test_interface_consumed_by_machine); + g_test_add_func("/qgraph/test_interface_consumed_by_driver", + test_interface_consumed_by_driver); + g_test_add_func("/qgraph/test_interface_consumed_by_test", + test_interface_consumed_by_test); + g_test_add_func("/qgraph/test_full_sample", test_full_sample); + g_test_add_func("/qgraph/test_full_sample_raspi", test_full_sample_ras= pi); + g_test_add_func("/qgraph/test_full_alternative_path", + test_full_alternative_path); + g_test_add_func("/qgraph/test_cycle", test_cycle); + g_test_add_func("/qgraph/test_two_test_same_interface", + test_two_test_same_interface); + g_test_add_func("/qgraph/test_double_edge", test_double_edge); + + g_test_run(); + return 0; +} --=20 2.17.1 From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531127694145699.0968706022638; Mon, 9 Jul 2018 02:14:54 -0700 (PDT) Received: from localhost ([::1]:39991 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSFr-0006Yb-WB for importer@patchew.org; Mon, 09 Jul 2018 05:14:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38408) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSDz-0005R9-NG for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSDw-0007Hk-QW for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:51 -0400 Received: from mail-ed1-x544.google.com ([2a00:1450:4864:20::544]:33780) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSDw-0007HK-JI for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:48 -0400 Received: by mail-ed1-x544.google.com with SMTP id x5-v6so9676238edr.0 for ; Mon, 09 Jul 2018 02:12:48 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ynSHATwvwcgV+WoQrgaoozN6evLYGuZ6cZOWLkl+ZrI=; b=QEwaA/glPeL8pj0wMdK23tqTFYBxnCTaIN9/uy3yclr/aDqU+kx9QuaRTkTilHRtNV RBdp9AEC192fT5zdF7a0JlACSnMXWGgSDUuaL6bGqHYyEUrQZDBnxbwiPP32sEY9RcM5 WrpMOB0RdwW3CEVWODmyF+6A7Vxu+MjmfvY87qeJgjJYjKtRgFV+Ll6HMeMrMDL+jUBc t8bbeLGMvy8lr/USzm5MaReS/an0AXi3cbxniCrmsi2J1oPFnXoUdj3d7rFOza4trsko /WW/NHTwSEG3kyS+hPkCWZOmcLdZ99kq8/BCmlBEcSYT01LZZ26EUSI4rXB3lNK4zoJe GM6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ynSHATwvwcgV+WoQrgaoozN6evLYGuZ6cZOWLkl+ZrI=; b=sXVNkpV9OnJh/JYMdJVysxLbhH4giHCrzFV/O3RFqDxMkpjRsMDmrZTF8M/jJexmQj FzrOGcbaSgo7j8vWD9d8uyf/hG79+HTVWrDdouAK3klz2huUC8cfeXEKuUkQnBbDbo89 +d9WhWIbcnUadPPc/q24JJd++NK77Sd+60YuuNGyE2Xh3osL8I4bc/bPoVM96n+wBPNz CnaoBAOz83Zs7rm2jI6JX/xzLxGUDyOZsXzA1gbdkM1ENBYBKxaGsY/dUQpdrx3Z/GP+ BWQs86mIh0ofhJKqBBE8lVuQ/dVhJtl15nObslTev39gaVgrMnUye0jtengYONNrIZhz EWjw== X-Gm-Message-State: APt69E3jqvZ9zb9/ifeRnamHtL0HUEOIEdUf1nyk3dcrm/TJ2mfjOKTI ggO24XhBUx4+lkLw2UOdq+0= X-Google-Smtp-Source: AAOMgpchtVPPCSDCZpy5kbYLwhgoZWYcLGtkLRQrctTTghQRU7IQtIB8WO495i5gy0rVD4/5jvMSyQ== X-Received: by 2002:a50:fa82:: with SMTP id w2-v6mr22124797edr.256.1531127567635; Mon, 09 Jul 2018 02:12:47 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:31 +0200 Message-Id: <20180709091136.28849-3-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::544 Subject: [Qemu-devel] [PATCH 2/7] tests/qgraph: pci-pc driver and interface nodes X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add pci-bus-pc node and pci-bus interface, moved QPCIBusPC struct declaration in its header (since it will be needed by other drivers) and introduced a setter method for drivers that do not need to allocate but have to initialize QPCIBusPC. Signed-off-by: Emanuele Giuseppe Esposito --- tests/libqos/pci-pc.c | 53 ++++++++++++++++++++++++++++++++++++------- tests/libqos/pci-pc.h | 8 +++++++ tests/libqos/pci.c | 8 +++++++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index a7803308b7..f1c1741279 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -18,15 +18,9 @@ =20 #include "qemu-common.h" =20 - #define ACPI_PCIHP_ADDR 0xae00 #define PCI_EJ_BASE 0x0008 =20 -typedef struct QPCIBusPC -{ - QPCIBus bus; -} QPCIBusPC; - static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) { return inb(addr); @@ -115,10 +109,33 @@ static void qpci_pc_config_writel(QPCIBus *bus, int d= evfn, uint8_t offset, uint3 outl(0xcfc, value); } =20 -QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc) +static void *qpci_get_driver(void *obj, const char *interface) { - QPCIBusPC *ret =3D g_new0(QPCIBusPC, 1); + QPCIBusPC *qpci =3D obj; + if (!g_strcmp0(interface, "pci-bus")) { + return &qpci->bus; + } + printf("%s not present in pci-bus-pc", interface); + abort(); +} =20 +void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, int devfn) +{ + if (!bus) { + return; + } + dev->bus =3D bus; + dev->devfn =3D devfn; + + if (qpci_config_readw(dev, PCI_VENDOR_ID) =3D=3D 0xFFFF) { + printf("PCI Device not found\n"); + abort(); + } + qpci_device_enable(dev); +} + +void qpci_set_pc(QPCIBusPC *ret, QTestState *qts, QGuestAllocator *alloc) +{ assert(qts); =20 ret->bus.pio_readb =3D qpci_pc_pio_readb; @@ -147,11 +164,23 @@ QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocato= r *alloc) ret->bus.mmio_alloc_ptr =3D 0xE0000000; ret->bus.mmio_limit =3D 0x100000000ULL; =20 + ret->obj.get_driver =3D qpci_get_driver; +} + +QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc) +{ + QPCIBusPC *ret =3D g_new0(QPCIBusPC, 1); + qpci_set_pc(ret, qts, alloc); + return &ret->bus; } =20 void qpci_free_pc(QPCIBus *bus) { + if (!bus) { + return; + } + QPCIBusPC *s =3D container_of(bus, QPCIBusPC, bus); =20 g_free(s); @@ -176,3 +205,11 @@ void qpci_unplug_acpi_device_test(const char *id, uint= 8_t slot) =20 qmp_eventwait("DEVICE_DELETED"); } + +static void qpci_pc(void) +{ + qos_node_create_driver("pci-bus-pc", NULL); + qos_node_produces("pci-bus-pc", "pci-bus"); +} + +libqos_init(qpci_pc); diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h index 491eeac756..ee381c5667 100644 --- a/tests/libqos/pci-pc.h +++ b/tests/libqos/pci-pc.h @@ -15,7 +15,15 @@ =20 #include "libqos/pci.h" #include "libqos/malloc.h" +#include "qgraph.h" =20 +typedef struct QPCIBusPC { + QOSGraphObject obj; + QPCIBus bus; +} QPCIBusPC; + +void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, int devfn); +void qpci_set_pc(QPCIBusPC *ret, QTestState *qts, QGuestAllocator *alloc); QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc); void qpci_free_pc(QPCIBus *bus); =20 diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index 0b73cb23d0..c51c186867 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -15,6 +15,7 @@ =20 #include "hw/pci/pci_regs.h" #include "qemu/host-utils.h" +#include "qgraph.h" =20 void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, void (*func)(QPCIDevice *dev, int devfn, void *da= ta), @@ -402,3 +403,10 @@ void qpci_plug_device_test(const char *driver, const c= har *id, qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot, opts ? ", " : "", opts ? opts : ""); } + +static void qpci(void) +{ + qos_node_create_interface("pci-bus"); +} + +libqos_init(qpci); --=20 2.17.1 From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531127871882446.22408676679754; Mon, 9 Jul 2018 02:17:51 -0700 (PDT) Received: from localhost ([::1]:40008 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSIm-0000g3-LX for importer@patchew.org; Mon, 09 Jul 2018 05:17:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38410) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSDz-0005RB-W0 for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSDy-0007IX-Fi for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:51 -0400 Received: from mail-ed1-x543.google.com ([2a00:1450:4864:20::543]:38462) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSDx-0007I4-Vf for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:50 -0400 Received: by mail-ed1-x543.google.com with SMTP id a5-v6so13346650edt.5 for ; Mon, 09 Jul 2018 02:12:49 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tEfedZKczeSk2U5xtlxu0lvx3hYJMd2Wwwdtq72a6cs=; b=PQQ+bTRLi6qErPz3FPEc267VJujUNpwFQXPoLW62CuHVCDmTUXWUvmnIVIbtCjN3Vb BH9w5FkCnuEUkA2z1gvPfrm2ZLXIEH1Mspvl05lY5P+HvQtGhIfXWm/vBmEGDqZJAAAD 2kzLxbzr2+ksScytOje94W98FXUZ62TS9rzHdsBS59qgurGs0uzj0434OyWXv4hhHlct b3HCGVy3kZO9PO01bwYik+/VmpdOyRmLXgi780lrwjJ0VmNG20r/NkBU8r8LhC49vGmI wsG9RML34V03lI6RHm7OJir/LglRnQmWzwwKPztggt3hkyd8hnADFLMiuLVK+zEBqt+y gySw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tEfedZKczeSk2U5xtlxu0lvx3hYJMd2Wwwdtq72a6cs=; b=e2gFO4NrK04FuGVKC4P/nq82YaNgSBxt+scR1han6WSornYw93mVcdOaM7e6rXTPZn de+P2feFwVSzj6Xt65Y8ByjD6ZxK7QS6uBJxrbHsMOxO/bEkeYbJBlhSNMtJ5YfhM1ng SZn8jMr5r748IufpzWTmjMENl/7mqMX6OMPLwWZngFbb2fuRTDRy1cB2zWI1l5OxBTRd HGvIqANgxS207vutgwJFuuaOwGMn4EfZeMiLPcNdMmHbaUiIu1/Zbg2izwcAZ18408Rr Ej5Wggv2RFy72doupCzxcra23Y7BX//QwPENHLT4QOOZLI0j2sAbSD40HOZEDDOYNj1r O+Ew== X-Gm-Message-State: APt69E3GRGF2U3x9F1bSBdIMFBy5B9cQGZ9xXnY1hEzR4zInom9lafpN 76uee8UxOh+CQjJnb0pN4Dg= X-Google-Smtp-Source: AAOMgpcAbtW5pwpf6l7A3yvK8h70Y7Y0XSohGQ8WFDGVOP/W//fAs+hE9YysGoF7Dvwr0+db2T3t+g== X-Received: by 2002:a50:87a8:: with SMTP id a37-v6mr21301049eda.31.1531127569003; Mon, 09 Jul 2018 02:12:49 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:32 +0200 Message-Id: <20180709091136.28849-4-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::543 Subject: [Qemu-devel] [PATCH 3/7] tests/qgraph: sdhci driver and interface nodes X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add qgraph nodes for sdhci-pci and generic-sdhci (memory mapped) drivers. Both drivers implement (produce) the same interface sdhci, that provides the readw - readq - writeq functions. Signed-off-by: Emanuele Giuseppe Esposito --- tests/Makefile.include | 1 + tests/libqos/sdhci.c | 142 +++++++++++++++++++++++++++++++++++++++++ tests/libqos/sdhci.h | 68 ++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 tests/libqos/sdhci.c create mode 100644 tests/libqos/sdhci.h diff --git a/tests/Makefile.include b/tests/Makefile.include index b16bbd55df..acbf704a8a 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -770,6 +770,7 @@ libqos-usb-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-= obj-y) tests/libqos/usb.o libqos-virtio-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/lib= qos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/lib= qos/malloc-generic.o =20 libqgraph-obj-y =3D tests/libqos/qgraph.o +libqgraph-pc-obj-y =3D $(libqos-pc-obj-y) tests/libqos/sdhci.o =20 check-unit-y +=3D tests/test-qgraph$(EXESUF) tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y) diff --git a/tests/libqos/sdhci.c b/tests/libqos/sdhci.c new file mode 100644 index 0000000000..213c2657c3 --- /dev/null +++ b/tests/libqos/sdhci.c @@ -0,0 +1,142 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "pci.h" +#include "pci-pc.h" +#include "qgraph.h" +#include "sdhci.h" +#include "hw/pci/pci.h" + +static void set_qsdhci_fields(QSDHCI *s, uint8_t version, uint8_t basecloc= k, + bool sdma, uint64_t reg) +{ + s->props.version =3D version; + s->props.baseclock =3D baseclock; + s->props.capab.sdma =3D sdma; + s->props.capab.reg =3D reg; +} + +/* Memory mapped implementation of QSDHCI */ + +static uint16_t sdhci_mm_readw(QSDHCI *s, uint32_t reg) +{ + QSDHCI_MemoryMapped *smm =3D container_of(s, QSDHCI_MemoryMapped, sdhc= i); + return qtest_readw(global_qtest, smm->addr + reg); +} + +static uint64_t sdhci_mm_readq(QSDHCI *s, uint32_t reg) +{ + QSDHCI_MemoryMapped *smm =3D container_of(s, QSDHCI_MemoryMapped, sdhc= i); + return qtest_readq(global_qtest, smm->addr + reg); +} + +static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val) +{ + QSDHCI_MemoryMapped *smm =3D container_of(s, QSDHCI_MemoryMapped, sdhc= i); + qtest_writeq(global_qtest, smm->addr + reg, val); +} + +static void *sdhci_mm_get_driver(void *obj, const char *interface) +{ + QSDHCI_MemoryMapped *spci =3D obj; + if (!g_strcmp0(interface, "sdhci")) { + return &spci->sdhci; + } + printf("%s not present in generic-sdhci\n", interface); + abort(); +} + +void qos_create_sdhci_mm(QSDHCI_MemoryMapped *sdhci, uint32_t addr, + QSDHCIProperties *common) +{ + sdhci->obj.get_driver =3D sdhci_mm_get_driver; + sdhci->sdhci.sdhci_readw =3D sdhci_mm_readw; + sdhci->sdhci.sdhci_readq =3D sdhci_mm_readq; + sdhci->sdhci.sdhci_writeq =3D sdhci_mm_writeq; + memcpy(&sdhci->sdhci.props, common, sizeof(QSDHCIProperties)); + sdhci->addr =3D addr; +} + +/* PCI implementation of QSDHCI */ + +static uint16_t sdhci_pci_readw(QSDHCI *s, uint32_t reg) +{ + QSDHCI_PCI *spci =3D container_of(s, QSDHCI_PCI, sdhci); + return qpci_io_readw(&spci->dev, spci->mem_bar, reg); +} + +static uint64_t sdhci_readq(QSDHCI *s, uint32_t reg) +{ + QSDHCI_PCI *spci =3D container_of(s, QSDHCI_PCI, sdhci); + return qpci_io_readq(&spci->dev, spci->mem_bar, reg); +} + +static void sdhci_writeq(QSDHCI *s, uint32_t reg, uint64_t val) +{ + QSDHCI_PCI *spci =3D container_of(s, QSDHCI_PCI, sdhci); + return qpci_io_writeq(&spci->dev, spci->mem_bar, reg, val); +} + +static void *sdhci_pci_get_driver(void *object, const char *interface) +{ + QSDHCI_PCI *spci =3D object; + if (!g_strcmp0(interface, "sdhci")) { + return &spci->sdhci; + } + + printf("%s not present in sdhci-pci\n", interface); + abort(); +} + +static void sdhci_destroy(QOSGraphObject *obj) +{ + g_free(obj); +} + +static void *sdhci_pci_create(void *pci_bus, QOSGraphObject *alloc) +{ + QSDHCI_PCI *spci =3D g_new0(QSDHCI_PCI, 1); + QPCIBus *bus =3D pci_bus; + uint64_t barsize; + + qpci_device_init(&spci->dev, bus, QPCI_DEVFN(4, 0)); + if (bus) { + spci->mem_bar =3D qpci_iomap(&spci->dev, 0, &barsize); + } + spci->obj.get_driver =3D sdhci_pci_get_driver; + spci->obj.destructor =3D sdhci_destroy; + spci->sdhci.sdhci_readw =3D sdhci_pci_readw; + spci->sdhci.sdhci_readq =3D sdhci_readq; + spci->sdhci.sdhci_writeq =3D sdhci_writeq; + set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4); + return &spci->obj; +} + +static void qsdhci(void) +{ + qos_node_create_interface("sdhci"); + qos_node_create_driver("generic-sdhci", NULL); + qos_node_produces("generic-sdhci", "sdhci"); + qos_node_create_driver("sdhci-pci", sdhci_pci_create); + qos_node_produces("sdhci-pci", "sdhci"); + qos_node_consumes_arg("sdhci-pci", "pci-bus", "addr=3D04.0"); +} + +libqos_init(qsdhci); diff --git a/tests/libqos/sdhci.h b/tests/libqos/sdhci.h new file mode 100644 index 0000000000..dfd043f160 --- /dev/null +++ b/tests/libqos/sdhci.h @@ -0,0 +1,68 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#ifndef QGRAPH_QSDHCI +#define QGRAPH_QSDHCI +#include "pci.h" + +typedef struct QSDHCI QSDHCI; +typedef struct QSDHCI_MemoryMapped QSDHCI_MemoryMapped; +typedef struct QSDHCI_PCI QSDHCI_PCI; +typedef struct QSDHCIProperties QSDHCIProperties; + +/* Properties common to all QSDHCI devices */ +struct QSDHCIProperties { + uint8_t version; + uint8_t baseclock; + struct { + bool sdma; + uint64_t reg; + } capab; +}; + +struct QSDHCI { + QOSGraphObject obj; + uint16_t (*sdhci_readw)(QSDHCI *s, uint32_t reg); + uint64_t (*sdhci_readq)(QSDHCI *s, uint32_t reg); + void (*sdhci_writeq)(QSDHCI *s, uint32_t reg, uint64_t val); + QSDHCIProperties props; +}; + +/* Memory Mapped implementation of QSDHCI */ +struct QSDHCI_MemoryMapped { + QOSGraphObject obj; + QSDHCI sdhci; + uint64_t addr; +}; + +/* PCI implementation of QSDHCI */ +struct QSDHCI_PCI { + QOSGraphObject obj; + QPCIDevice dev; + QSDHCI sdhci; + QPCIBar mem_bar; +}; + +/** + * qos_create_sdhci_mm(): external constructor used by all drivers/machines + * that "contain" a #QSDHCI_MemoryMapped driver + */ +void qos_create_sdhci_mm(QSDHCI_MemoryMapped *sdhci, uint32_t addr, + QSDHCIProperties *common); + +#endif --=20 2.17.1 From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531127694073106.77266611004939; Mon, 9 Jul 2018 02:14:54 -0700 (PDT) Received: from localhost ([::1]:39993 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSFv-0006bn-5Y for importer@patchew.org; Mon, 09 Jul 2018 05:14:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38425) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSE0-0005RD-Jt for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSDz-0007Iv-8h for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:52 -0400 Received: from mail-ed1-x543.google.com ([2a00:1450:4864:20::543]:44034) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSDz-0007IS-1n for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:51 -0400 Received: by mail-ed1-x543.google.com with SMTP id d17-v6so1280331eds.11 for ; Mon, 09 Jul 2018 02:12:51 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=MN/6uPFsSUmJo97MLGcJ1wTzpriKuT3kmibyuLoIX+o=; b=L0t6x0JQ3BJ09lK3Fnre9o6viJqyBAAgncqS2SWE77/VUaox1e94XoZ9St56WZBJ6h KDbWcXEMsvGTwiJCpZPDQzvrG6Qw/gOg60buUYcxuBsdc6hnRHXk/6f+nW2H6FWNuahE Grp8fEFgklGbGz83OWBSkQE6VT/SxpDb0g3h48IHEjPUQGvtjkZ2GxNZBdmyL9RKylij skkzsK2kWdefhU7I2bsq2RCm4ZAnjDz81WkYyMHrEoL6NiaooKwbzxox+ME6jZzZREo0 Mvxmbo/xpSMj2OerReTl9Ap8fcDf4RY/jaFehZxHGqAN8Quq1+c7dm4bPnp6cT55ul38 GVKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=MN/6uPFsSUmJo97MLGcJ1wTzpriKuT3kmibyuLoIX+o=; b=gGuydkmxizc2O6QB5qyzJ3C2c3uamErFSdFvHIM6N5u7Bzuxf/F4EHxUNFGkjjByQA Njce7EzQ9BOmfAzmNOcPDiF+ugt39UpnoM05k5nCY2nxZebWHIO0julYBZ9vJSsQkKNa 046S2NZoj2+2BRJUx1gSbsxYkHF5CKaKP/BhqUV9nKz/MbIBGMkZhHYOdbdg+l7jXUCb Ww6wWgOsTFYWjIoH+V+Td69j3OSPKMoixwbS2nxGmTsxBImfnjqz0heJphyPOUO/831m JHQhGp0+iuT4BQIK/wO/fyzpdcm0cd8ajkh7KxiNtKvO66f7POS0EOx/oxMNZbVPLy7G 2/Rg== X-Gm-Message-State: APt69E2vucgx9+GlTpiCNPbfXA7GNzWONGb+UVwklg+ZAj+Vg71KXUF3 iJc2g48vtzjB4q2EvWO60xo= X-Google-Smtp-Source: AAOMgpehTG+ZP4u8/CZhTP3lQnhv74wgCLmvGA7si8APY3LHYhpyrZ1AEsCeE+Gb2v+Lp2XRjY6V8g== X-Received: by 2002:a50:e40d:: with SMTP id d13-v6mr8834414edm.263.1531127570090; Mon, 09 Jul 2018 02:12:50 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:33 +0200 Message-Id: <20180709091136.28849-5-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::543 Subject: [Qemu-devel] [PATCH 4/7] tests/qgraph: arm/raspi2 machine node X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add arm/raspi2 machine to the graph. This machine contains a generic-sdhci,= so its constructor must take care of setting it properly when called. Signed-off-by: Emanuele Giuseppe Esposito --- tests/Makefile.include | 3 +- tests/libqos/raspi2-machine.c | 68 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/libqos/raspi2-machine.c diff --git a/tests/Makefile.include b/tests/Makefile.include index acbf704a8a..de75a7394e 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -770,7 +770,8 @@ libqos-usb-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-= obj-y) tests/libqos/usb.o libqos-virtio-obj-y =3D $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/lib= qos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/lib= qos/malloc-generic.o =20 libqgraph-obj-y =3D tests/libqos/qgraph.o -libqgraph-pc-obj-y =3D $(libqos-pc-obj-y) tests/libqos/sdhci.o +libqgraph-pc-obj-y =3D $(libqos-pc-obj-y) $(libqgraph-obj-y) tests/libqos/= sdhci.o +libqgraph-pc-obj-y +=3D tests/libqos/raspi2-machine.o =20 check-unit-y +=3D tests/test-qgraph$(EXESUF) tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y) diff --git a/tests/libqos/raspi2-machine.c b/tests/libqos/raspi2-machine.c new file mode 100644 index 0000000000..47f024076f --- /dev/null +++ b/tests/libqos/raspi2-machine.c @@ -0,0 +1,68 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qgraph.h" +#include "sdhci.h" + +typedef struct QRaspi2Machine QRaspi2Machine; + +struct QRaspi2Machine { + QOSGraphObject obj; + QSDHCI_MemoryMapped sdhci; +}; + +static void raspi2_destroy(QOSGraphObject *obj) +{ + g_free(obj); +} + +static QOSGraphObject *raspi2_get_device(void *obj, const char *device) +{ + QRaspi2Machine *machine =3D obj; + if (!g_strcmp0(device, "generic-sdhci")) { + return &machine->sdhci.obj; + } + + printf("%s not present in arm/raspi2", device); + abort(); +} + +static void *qos_create_machine_arm_raspi2(void) +{ + QRaspi2Machine *machine =3D g_new0(QRaspi2Machine, 1); + + machine->obj.get_device =3D raspi2_get_device; + machine->obj.destructor =3D raspi2_destroy; + qos_create_sdhci_mm(&machine->sdhci, 0x3f300000, &(QSDHCIProperties) { + .version =3D 3, + .baseclock =3D 52, + .capab.sdma =3D false, + .capab.reg =3D 0x052134b4 + }); + return &machine->obj; +} + +static void raspi2(void) +{ + qos_node_create_machine("arm/raspi2", qos_create_machine_arm_raspi2); + qos_node_contains("arm/raspi2", "generic-sdhci"); +} + +libqos_init(raspi2); --=20 2.17.1 From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531127872624584.1238045733458; Mon, 9 Jul 2018 02:17:52 -0700 (PDT) Received: from localhost ([::1]:40011 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSIo-0000iW-1k for importer@patchew.org; Mon, 09 Jul 2018 05:17:50 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38443) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSE1-0005RT-Jz for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSE0-0007Jl-Cb for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:53 -0400 Received: from mail-ed1-x543.google.com ([2a00:1450:4864:20::543]:38463) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSE0-0007J6-5W for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:52 -0400 Received: by mail-ed1-x543.google.com with SMTP id a5-v6so13346736edt.5 for ; Mon, 09 Jul 2018 02:12:52 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PRrLBb//RNiIQ5HAMG0VPE7b5IppsBjHnGBSCmwZono=; b=nrPtD9xR6ki9DxjUT2fH9sPeVf11cWqZttd7lUstG98ONLuGQ4NYHHoPACfsVgnK36 ZnzAOQ2nQq0Eic0AG3LqEJey+68ZJ4yvKNWwsPSvaKlhiJ920C67Xww1huYBR/oFM7Yg nequfZA9W/N83EbB1L2dlYSNteopmxkhfbihQ0pL64XpXmFGA7ZF51JyRFKOV+l/j5PN 6z03g88amIho8wq0x+5qm53sODW4SIJ0pu8agOuY8vuEsBWgpxHElGOAlhkoQEzLO4Ad UpPa0ZNG2j+WsHWn1UJaFi79rvMjyycsQEae0HJpU+jK40D8Y3RfZyDv81+MWfmjDRh7 eYiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=PRrLBb//RNiIQ5HAMG0VPE7b5IppsBjHnGBSCmwZono=; b=iobF7NxWtj1EdeDYZmletacYl8g0LU9jhH1ujBeO1MJSq2QaY78g7+ufMBbi/sWTeV nWtytJ4Bod5hixlBjSGvP0PFFuBTg+oKiVZk+ufdoQMPt4tmfoX5HLK4Eg55Q/IW4olR En6aDN849Qfu4klElsmgsdzH0N+VdJs1D714q79qW1vrP05NMoLblkbXV1fDFVWUGEw9 3i0pE9YpBItsAiA2GBplRRZgXODVWexnLN9DnG2e/zCNamRgf9MwuCSLp3/CJ8tNB/na +WarEz24I+p/BYNyU8iuFNHOY4BnR98hvkeKINr9KHXtvk80F+u37EGXCkeN+pKAtvbz FzHw== X-Gm-Message-State: APt69E1VHshHTJOuBKCV6w878mwotPWg0ec5qy2OQ+NKDpMV/4ophiLm N/Dljkf+hl671GGxzr8g7pw= X-Google-Smtp-Source: AAOMgpfFuGFPWwgtoe2s5cw1fOIGOVSNYqEkwlVicc+4cWdXz5Yr7TlVIDbhNyhgnI/AtdIYxQ6ZXg== X-Received: by 2002:a50:a804:: with SMTP id j4-v6mr22466996edc.61.1531127571201; Mon, 09 Jul 2018 02:12:51 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:34 +0200 Message-Id: <20180709091136.28849-6-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::543 Subject: [Qemu-devel] [PATCH 5/7] tests/qgraph: x86_64/pc machine node X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add pc machine for the x86_64 QEMU binary. This machine contains an i440FX-= pcihost driver, that contains itself a pci-bus-pc that produces the pci-bus interfa= ce. Signed-off-by: Emanuele Giuseppe Esposito --- tests/Makefile.include | 2 +- tests/libqos/x86_64_pc-machine.c | 93 ++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/libqos/x86_64_pc-machine.c diff --git a/tests/Makefile.include b/tests/Makefile.include index de75a7394e..706ac39ea5 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -771,7 +771,7 @@ libqos-virtio-obj-y =3D $(libqos-spapr-obj-y) $(libqos-= pc-obj-y) tests/libqos/virt =20 libqgraph-obj-y =3D tests/libqos/qgraph.o libqgraph-pc-obj-y =3D $(libqos-pc-obj-y) $(libqgraph-obj-y) tests/libqos/= sdhci.o -libqgraph-pc-obj-y +=3D tests/libqos/raspi2-machine.o +libqgraph-pc-obj-y +=3D tests/libqos/raspi2-machine.o tests/libqos/x86_64_= pc-machine.o =20 check-unit-y +=3D tests/test-qgraph$(EXESUF) tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y) diff --git a/tests/libqos/x86_64_pc-machine.c b/tests/libqos/x86_64_pc-mach= ine.c new file mode 100644 index 0000000000..626e8d7d70 --- /dev/null +++ b/tests/libqos/x86_64_pc-machine.c @@ -0,0 +1,93 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qgraph.h" +#include "sdhci.h" +#include "pci-pc.h" + +typedef struct QX86_64_PCMachine QX86_64_PCMachine; +typedef struct i440FX_pcihost i440FX_pcihost; +typedef struct QSDHCI_PCI QSDHCI_PCI; + +struct i440FX_pcihost { + QOSGraphObject obj; + QPCIBusPC pci; +}; + +struct QX86_64_PCMachine { + QOSGraphObject obj; + i440FX_pcihost bridge; +}; + +/* i440FX_pcihost */ + +static QOSGraphObject *i440FX_host_get_device(void *obj, const char *devic= e) +{ + i440FX_pcihost *host =3D obj; + if (!g_strcmp0(device, "pci-bus-pc")) { + return &host->pci.obj; + } + printf("%s not present in i440FX-pcihost", device); + abort(); +} + +static void qos_create_i440FX_host(i440FX_pcihost *host) +{ + host->obj.get_device =3D i440FX_host_get_device; + qpci_set_pc(&host->pci, global_qtest, NULL); +} + +/* x86_64/pc machine */ + +static void pc_destroy(QOSGraphObject *obj) +{ + g_free(obj); +} + +static QOSGraphObject *pc_get_device(void *obj, const char *device) +{ + QX86_64_PCMachine *machine =3D obj; + if (!g_strcmp0(device, "i440FX-pcihost")) { + return &machine->bridge.obj; + } + + printf("%s not present in x86_64/pc", device); + abort(); +} + +static void *qos_create_machine_pc(void) +{ + QX86_64_PCMachine *machine =3D g_new0(QX86_64_PCMachine, 1); + machine->obj.get_device =3D pc_get_device; + machine->obj.destructor =3D pc_destroy; + qos_create_i440FX_host(&machine->bridge); + + return &machine->obj; +} + +static void pc_machine(void) +{ + qos_node_create_machine("x86_64/pc", qos_create_machine_pc); + qos_node_create_driver("i440FX-pcihost", NULL); + qos_node_contains("x86_64/pc", "i440FX-pcihost"); + qos_node_contains("i440FX-pcihost", "pci-bus-pc"); +} + +libqos_init(pc_machine); --=20 2.17.1 From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531127872492831.8056094756763; Mon, 9 Jul 2018 02:17:52 -0700 (PDT) Received: from localhost ([::1]:40010 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSIn-0000hA-Ui for importer@patchew.org; Mon, 09 Jul 2018 05:17:49 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38468) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSE3-0005Tg-Ul for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSE1-0007Kg-VU for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:55 -0400 Received: from mail-ed1-x541.google.com ([2a00:1450:4864:20::541]:40822) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSE1-0007K5-KF for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:53 -0400 Received: by mail-ed1-x541.google.com with SMTP id e19-v6so13341184edq.7 for ; Mon, 09 Jul 2018 02:12:53 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xPlnjz0xU33vk3wXlhFlf0VVxHs5haKv+NiZ8a+Tb10=; b=lLM0e3iNG2NvPL6YapipAk5PuekGDR7J2SlkbPYIZQwty5XC0pSCfRT2I9MRqCgsIn VruPpVZs+YEClk/fYsxiM9WHD/ELYj+NVwndsYziMv/YX6a4S8XDIibUC1wXrkF4iUOw GaqtWDwt58l+QT1hUKrkZo8MwWvNEC+qetIFCxbRJ883VnmKEe/KA+Ev1udr571fDrzt Z6S9nZQJm5Dh73jVYCkYpEpl2+QAJAKuDGFpcYcJR4TOThrYqZfLSKTokFU4Al5XNkPm 0u9XSBlF8j3TcPEXwBMJgpq13OZGleImleTvPZb9gRGR5v1/tjo2rAZ2BhpTCTTYnME7 A+ZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xPlnjz0xU33vk3wXlhFlf0VVxHs5haKv+NiZ8a+Tb10=; b=pX45gppKS+gcN+29pkpSoclNglCJ+OAc6mfcBeIE2/caD5mTNVYQCy25kYPhbl/zGP J4l0akny2toOUJgYeYXiNtFPRC1pgr5W+Xqtk6y3V2nFCOnqYv2WynU2NjpFDCVUWuMF c1FCN6WOjpuCZwZU/hJvev1MMxRdXF7moYnp0sxXzwcVj9IhHxloVxbtUWtY2xCD79Vo 4GVjwW+rpqmcxK/Y2XQblG/iFVj2UEDdvKKQ+7OIxbGhyexKHPzXwVD4enVTlV3gTNYD vre28+Jf4yRnr5IB85I6jkZN8hQqsAFXSw3jSey2HxxS5HQcF8zwiYKxrTaYs5bqTfAH Sp3Q== X-Gm-Message-State: APt69E2Cw5oLRkF+y13Bzc43BVQUHc8eaw6660Ob197qxqYVGMgfgpvo Xu1DkajyYELz9ZC0KO+wQzQ= X-Google-Smtp-Source: AAOMgpeE7rDVlmxdfx14FVk0B56JAi4EcwNhnvJJyhpNl65m5UVpcPbS8XzJbXPFyJ0pjgp+fORSbA== X-Received: by 2002:a50:8327:: with SMTP id 36-v6mr1606704edh.305.1531127572508; Mon, 09 Jul 2018 02:12:52 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:35 +0200 Message-Id: <20180709091136.28849-7-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::541 Subject: [Qemu-devel] [PATCH 6/7] tests/qgraph: gtest integration X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add main executable that takes care of starting the framework, create the nodes, set the available drivers/machines, discover the path and run tests. Signed-off-by: Emanuele Giuseppe Esposito --- tests/Makefile.include | 3 + tests/qos-test.c | 310 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 tests/qos-test.c diff --git a/tests/Makefile.include b/tests/Makefile.include index 706ac39ea5..e2db3e9d09 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -776,6 +776,9 @@ libqgraph-pc-obj-y +=3D tests/libqos/raspi2-machine.o t= ests/libqos/x86_64_pc-machi check-unit-y +=3D tests/test-qgraph$(EXESUF) tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y) =20 +check-qtest-pci-y +=3D tests/qos-test$(EXESUF) +tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-pc-obj-y) + tests/qmp-test$(EXESUF): tests/qmp-test.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o tests/rtc-test$(EXESUF): tests/rtc-test.o diff --git a/tests/qos-test.c b/tests/qos-test.c new file mode 100644 index 0000000000..f4748c44a4 --- /dev/null +++ b/tests/qos-test.c @@ -0,0 +1,310 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qlist.h" +#include "libqos/qgraph.h" +#include "libqos/qgraph_extra.h" + +/** + * create_machine_name(): appends the architecture to @name if + * @is_machine is valid. + */ +static void create_machine_name(const char **name, bool is_machine) +{ + const char *arch; + if (!is_machine) { + return; + } + arch =3D qtest_get_arch(); + *name =3D g_strconcat(arch, "/", *name, NULL); +} + +/** + * destroy_machine_name(): frees the given @name if + * @is_machine is valid. + */ +static void destroy_machine_name(const char *name, bool is_machine) +{ + if (!is_machine) { + return; + } + g_free((char *)name); +} + +/** + * apply_to_qlist(): using QMP queries QEMU for a list of + * machines and devices available, and sets the respective node + * as TRUE. If a node is found, also all its produced and contained + * child are marked available. + * + * See qos_graph_node_set_availability() for more info + */ +static void apply_to_qlist(QList *list, bool is_machine) +{ + const QListEntry *p; + const char *name; + QDict *minfo; + QObject *qobj; + QString *qstr; + + for (p =3D qlist_first(list); p; p =3D qlist_next(p)) { + minfo =3D qobject_to(QDict, qlist_entry_obj(p)); + g_assert(minfo); + qobj =3D qdict_get(minfo, "name"); + g_assert(qobj); + qstr =3D qobject_to(QString, qobj); + g_assert(qstr); + name =3D qstring_get_str(qstr); + create_machine_name(&name, is_machine); + qos_graph_node_set_availability(name, TRUE); + destroy_machine_name(name, is_machine); + qobj =3D qdict_get(minfo, "alias"); + if (qobj) { + g_assert(qobj); + qstr =3D qobject_to(QString, qobj); + g_assert(qstr); + name =3D qstring_get_str(qstr); + create_machine_name(&name, is_machine); + qos_graph_node_set_availability(name, TRUE); + destroy_machine_name(name, is_machine); + } + } +} + +/** + * qos_set_machines_devices_available(): sets availability of qgraph + * machines and devices. + * + * This function firstly starts QEMU with "-machine none" option, + * and then executes the QMP protocol asking for the list of devices + * and machines available. + * + * for each of these items, it looks up the corresponding qgraph node, + * setting it as available. The list currently returns all devices that + * are either machines or CONSUMED_BY other nodes. + * Therefore, in order to mark all other nodes, it recursively sets + * all its CONTAINS and PRODUCES child as available too. + */ +static void qos_set_machines_devices_available(void) +{ + QDict *response; + QDict *args =3D qdict_new(); + QList *list; + + qtest_start("-machine none"); + response =3D qmp("{ 'execute': 'query-machines' }"); + g_assert(response); + list =3D qdict_get_qlist(response, "return"); + g_assert(list); + + apply_to_qlist(list, TRUE); + + qobject_unref(response); + + qdict_put_bool(args, "abstract", TRUE); + qdict_put_str(args, "implements", "device"); + + response =3D qmp("{'execute': 'qom-list-types'," + " 'arguments': %p }", args); + g_assert(qdict_haskey(response, "return")); + list =3D qdict_get_qlist(response, "return"); + + apply_to_qlist(list, FALSE); + + qtest_end(); + qobject_unref(response); + +} + +/** + * allocate_objects(): given an array of nodes @arg, + * walks the path invoking all constructors and + * passing the corresponding parameter in order to + * continue the objects allocation. + * Once the test is reached, its function is executed. + * + * Since only the machine and CONSUMED_BY nodes actually + * allocate something in the constructor, a garbage collector + * saves their pointer in an array, so that after execution + * they can be safely free'd. + * + * Note: as specified in walk_path() too, @arg is an array of + * char *, where arg[0] is a pointer to the command line + * string that will be used to properly start QEMU when executing + * the test, and the remaining elements represent the actual objects + * that will be allocated. + */ +static void allocate_objects(const void *arg) +{ + QOSGraphObject *garbage_collector[(QOS_PATH_MAX_ELEMENT_SIZE * 2)]; + int garbage_size =3D 0; + QOSEdgeType etype; + QOSGraphNode *node; + QOSGraphObject *o; + int current =3D 1, has_to_allocate =3D 0; + void *obj =3D NULL; + char **path =3D (char **) arg; + + node =3D qos_graph_get_node(path[current]); + + while (current < QOS_PATH_MAX_ELEMENT_SIZE) { + + if (node->type =3D=3D MACHINE) { + global_qtest =3D qtest_start(path[0]); + + obj =3D node->u.machine.constructor(); + garbage_collector[garbage_size++] =3D obj; + + } else if (has_to_allocate && node->type =3D=3D DRIVER) { + obj =3D node->u.driver.constructor(obj, NULL); + garbage_collector[garbage_size++] =3D obj; + + } else if (!path[(current + 1)] && node->type =3D=3D TEST) { + node->u.test.function(obj, node->u.test.arg); + break; + } + + etype =3D qos_graph_get_edge_type(path[current], path[(current + 1= )]); + current++; + node =3D qos_graph_get_node(path[current]); + + o =3D obj; + + switch (etype) { + case PRODUCES: + obj =3D o->get_driver(obj, path[current]); + break; + case CONSUMED_BY: + has_to_allocate =3D 1; + break; + case CONTAINS: + obj =3D o->get_device(obj, path[current]); + break; + } + + } + + g_free(path[0]); + g_free(path); + for (int i =3D 0; i < garbage_size; i++) { + garbage_collector[i]->destructor(garbage_collector[i]); + } + qtest_end(); +} + +/* + * in this function, 2 path will be built: + * str_path, a one-string path (ex "pc/i440FX-pcihost/...") + * ro_path, a string-array path (ex [0] =3D "pc", [1] =3D "i440FX-pcihost"= ). + * + * str_path will be only used to build the test name, and won't need the + * architecture name at beginning, since it will be added by qtest_add_fun= c(). + * + * ro_path is used to allocate all constructors of the path nodes. + * Each name in this array except position 0 must correspond to a valid + * QOSGraphNode name. + * Position 0 is special, initially contains just the name of + * the node, (ex for "x86_64/pc" it will be "pc"), used to build the test + * path (see below). After it will contain the command line used to start + * qemu with all required devices. + * + * Note that the machine node name must be with format / + * (ex "x86_64/pc"), because it will identify the node "x86_64/pc" + * and start QEMU with "-M pc". For this reason, + * when building str_path, ro_path + * initially contains the at position 0 ("pc"), + * and the node name at position 1 (/) + * ("x86_64/pc"), followed by the rest of the nodes. + */ +static void walk_path(QOSGraphNode *orig_path, int len) +{ + QOSGraphNode *path; + /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */ + char **ro_path =3D g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2)); + int ro_path_size =3D 0; + char *machine =3D NULL, *arch =3D NULL, *tmp_cmd =3D NULL, *str_path; + char *tmp =3D orig_path->name, *gfreed; + GString *cmd_line =3D g_string_new(""); + + do { + path =3D qos_graph_get_node(tmp); + tmp =3D qos_graph_get_edge_dest(path->path_edge); + + /* append node command line + previous edge command line */ + if (path->command_line && tmp_cmd) { + g_string_append(cmd_line, path->command_line); + g_string_append_printf(cmd_line, "%s ", tmp_cmd); + } + + if (path->type =3D=3D MACHINE) { + qos_separate_arch_machine(path->name, &arch, &machine); + ro_path[ro_path_size++] =3D arch; + ro_path[ro_path_size++] =3D machine; + g_string_append_printf(cmd_line, "%s ", path->command_line); + } else { + /* detect if edge has command line args */ + ro_path[ro_path_size++] =3D path->name; + tmp_cmd =3D qos_graph_get_edge_arg(path->path_edge); + } + + } while (path->path_edge); + + + /* here position 0 has /, position 1 . + * the path must not have the , that's why ro_path + 1 + */ + str_path =3D g_strjoinv("/", (ro_path + 1)); + gfreed =3D g_string_free(cmd_line, FALSE); + /* put arch/machine in position 1 so allocate_objects can do its work + * and add the command line at position 0. + */ + ro_path[0] =3D g_strdup(gfreed); + ro_path[1] =3D arch; + + qtest_add_data_func(str_path, ro_path, allocate_objects); + g_free(str_path); +} + +/** + * main(): heart of the qgraph framework. + * + * - Initializes the glib test framework + * - Creates the graph by invoking the various _init constructors + * - Starts QEMU to mark the available devices + * - Walks the graph, and each path is added to + * the glib test framework (walk_path) + * - Runs the tests, calling allocate_object() and allocating the + * machine/drivers/test objects + * - Cleans up everything + */ +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + qos_graph_init(); + module_call_init(MODULE_INIT_LIBQOS); + qos_set_machines_devices_available(); + + qos_graph_foreach_test_path(walk_path); + g_test_run(); + qos_graph_destroy(); + return 0; +} --=20 2.17.1 From nobody Tue Nov 4 19:07:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531128001335962.4683490276733; Mon, 9 Jul 2018 02:20:01 -0700 (PDT) Received: from localhost ([::1]:40019 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSKu-0002K6-81 for importer@patchew.org; Mon, 09 Jul 2018 05:20:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38492) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fcSE4-0005Uc-Ql for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:13:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fcSE3-0007LP-3E for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:56 -0400 Received: from mail-ed1-x541.google.com ([2a00:1450:4864:20::541]:44033) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fcSE2-0007Ko-PV for qemu-devel@nongnu.org; Mon, 09 Jul 2018 05:12:55 -0400 Received: by mail-ed1-x541.google.com with SMTP id d17-v6so1280454eds.11 for ; Mon, 09 Jul 2018 02:12:54 -0700 (PDT) Received: from localhost.localdomain ([194.230.159.64]) by smtp.gmail.com with ESMTPSA id c6-v6sm6865091edt.41.2018.07.09.02.12.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Jul 2018 02:12:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=L3MGEq/bWigfuGfy3gKs/ykULKGHE2R6T5p40t04p+I=; b=jHB90RxV39auCN0kU9+SaGw26RhNuaHagvEbah1VxKixZ2bGh4qLzHjHS9HkNB/oP4 ByuAq9Qb6t1so6MTqoroJyPRq0RtISFQf9rqph9JmqYc+/z1weRhSNrytT6WbvdgTah6 PPZs77WNkZY2aFj66jHBuVBXyJZCVrOOxAyOgFUqy1+gyi1/K41KEHx7isNKy5g2wujo DIHetUR1u+L0ZnJHIjT6YtDhEqS/dyhpaDyFMyJcisrSvj2ls8hmgAvMcU6plK6XcKb6 n8S5nEX2o9/qqNwWgaEx38XC000F3UvDXBPVtjXrh27hfl077rKWgjKtDChHzWgn4hl0 fctQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=L3MGEq/bWigfuGfy3gKs/ykULKGHE2R6T5p40t04p+I=; b=tC3CillaCdprwdnpyDD7OkZdYp5binSWig0I9bM7Y55SARlQe3eZr4C/ca3i63sEKC v/vPUMz6TmiVRsgQwIBM53An3XPhJSeQcojpj8lMYEB9IEW6yKQ39i02cZKW2sTjotMP 14JqaUBhxJjy/Hhk8JHEeAFEXD2xc9c5fzXMWfwDmfXGCTJBitgKObuiA3WyYBf9JvgF HBK5AvUrHetx10xwkKOihJ/qRAnuykcfk3ptkn13JU+8QLDTKBrY0HbyA5CkgygiO7o1 HgwlnZLl2Y1X4wmb8Sr2C1ldRjB4YmA2hbV5OCmqUKFULyY5yrWkuH/CT8gSt3xoxzoG 788g== X-Gm-Message-State: APt69E0iJij8BC2MZNt94rnzJkRKCWD36wx54nXw4lNMckNUwl7aU0dt 5YnULm/JVSejlh17d/uOuJ4= X-Google-Smtp-Source: AAOMgpcZAmby0q7Yl4CDURb7sScQkNWGxQvw7v35YZY41YaAmwZhzU58VbJcxU0yVuEwJ2PQj+SWoQ== X-Received: by 2002:a50:95c2:: with SMTP id x2-v6mr21170732eda.99.1531127573769; Mon, 09 Jul 2018 02:12:53 -0700 (PDT) From: Emanuele Giuseppe Esposito To: Paolo Bonzini Date: Mon, 9 Jul 2018 11:11:36 +0200 Message-Id: <20180709091136.28849-8-e.emanuelegiuseppe@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> References: <20180709091136.28849-1-e.emanuelegiuseppe@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::541 Subject: [Qemu-devel] [PATCH 7/7] tests/qgraph: sdhci test node X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Emanuele Giuseppe Esposito , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Convert tests/sdhci-test in first qgraph test node, sdhci-test. This test consumes an sdhci interface and checks that its function return the expected values. Note that this test does not allocate any sdhci structure, it's all done by= the qtest walking graph mechanism Signed-off-by: Emanuele Giuseppe Esposito --- tests/Makefile.include | 8 +- tests/sdhci-test.c | 222 ++++++++++++----------------------------- 2 files changed, 67 insertions(+), 163 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index e2db3e9d09..790abe8c6e 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -311,7 +311,6 @@ check-qtest-i386-y +=3D tests/migration-test$(EXESUF) check-qtest-i386-y +=3D tests/test-x86-cpuid-compat$(EXESUF) check-qtest-i386-y +=3D tests/numa-test$(EXESUF) check-qtest-x86_64-y +=3D $(check-qtest-i386-y) -check-qtest-x86_64-y +=3D tests/sdhci-test$(EXESUF) gcov-files-i386-y +=3D i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y =3D $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files= -i386-y)) =20 @@ -385,10 +384,8 @@ gcov-files-arm-y +=3D arm-softmmu/hw/block/virtio-blk.c check-qtest-arm-y +=3D tests/test-arm-mptimer$(EXESUF) gcov-files-arm-y +=3D hw/timer/arm_mptimer.c check-qtest-arm-y +=3D tests/boot-serial-test$(EXESUF) -check-qtest-arm-y +=3D tests/sdhci-test$(EXESUF) =20 check-qtest-aarch64-y =3D tests/numa-test$(EXESUF) -check-qtest-aarch64-y +=3D tests/sdhci-test$(EXESUF) check-qtest-aarch64-y +=3D tests/boot-serial-test$(EXESUF) =20 check-qtest-microblazeel-y =3D $(check-qtest-microblaze-y) @@ -773,11 +770,13 @@ libqgraph-obj-y =3D tests/libqos/qgraph.o libqgraph-pc-obj-y =3D $(libqos-pc-obj-y) $(libqgraph-obj-y) tests/libqos/= sdhci.o libqgraph-pc-obj-y +=3D tests/libqos/raspi2-machine.o tests/libqos/x86_64_= pc-machine.o =20 +libqgraph-tests-obj-y =3D $(libqgraph-pc-obj-y) tests/sdhci-test.o + check-unit-y +=3D tests/test-qgraph$(EXESUF) tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y) =20 check-qtest-pci-y +=3D tests/qos-test$(EXESUF) -tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-pc-obj-y) +tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-tests-obj-y) =20 tests/qmp-test$(EXESUF): tests/qmp-test.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o @@ -863,7 +862,6 @@ tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer= .o tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y) tests/numa-test$(EXESUF): tests/numa-test.o tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o test= s/acpi-utils.o -tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y) tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos= -obj-y) =20 tests/migration/stress$(EXESUF): tests/migration/stress.o diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c index 1d825eb010..3e16c036f4 100644 --- a/tests/sdhci-test.c +++ b/tests/sdhci-test.c @@ -12,6 +12,8 @@ #include "libqtest.h" #include "libqos/pci-pc.h" #include "hw/pci/pci.h" +#include "libqos/qgraph.h" +#include "libqos/sdhci.h" =20 #define SDHC_CAPAB 0x40 FIELD(SDHC_CAPAB, BASECLKFREQ, 8, 8); /* since v2 */ @@ -20,99 +22,60 @@ FIELD(SDHC_CAPAB, SDR, 32, 3); /* = since v3 */ FIELD(SDHC_CAPAB, DRIVER, 36, 3); /* since v3 */ #define SDHC_HCVER 0xFE =20 -static const struct sdhci_t { - const char *arch, *machine; - struct { - uintptr_t addr; - uint8_t version; - uint8_t baseclock; +/** + * Old sdhci_t structure: + * + struct sdhci_t { + const char *arch, *machine; struct { - bool sdma; - uint64_t reg; - } capab; - } sdhci; - struct { - uint16_t vendor_id, device_id; - } pci; -} models[] =3D { - /* PC via PCI */ - { "x86_64", "pc", - {-1, 2, 0, {1, 0x057834b4} }, - .pci =3D { PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_SDHCI } }, - - /* Exynos4210 */ - { "arm", "smdkc210", - {0x12510000, 2, 0, {1, 0x5e80080} } }, - - /* i.MX 6 */ - { "arm", "sabrelite", - {0x02190000, 3, 0, {1, 0x057834b4} } }, - - /* BCM2835 */ - { "arm", "raspi2", - {0x3f300000, 3, 52, {0, 0x052134b4} } }, - - /* Zynq-7000 */ - { "arm", "xilinx-zynq-a9", /* Datasheet: UG585 (v1.12.1) */ - {0xe0100000, 2, 0, {1, 0x69ec0080} } }, - - /* ZynqMP */ - { "aarch64", "xlnx-zcu102", /* Datasheet: UG1085 (v1.7) */ - {0xff160000, 3, 0, {1, 0x280737ec6481} } }, - -}; - -typedef struct QSDHCI { - struct { - QPCIBus *bus; - QPCIDevice *dev; - } pci; - union { - QPCIBar mem_bar; - uint64_t addr; - }; -} QSDHCI; - -static uint16_t sdhci_readw(QSDHCI *s, uint32_t reg) -{ - uint16_t val; - - if (s->pci.dev) { - val =3D qpci_io_readw(s->pci.dev, s->mem_bar, reg); - } else { - val =3D qtest_readw(global_qtest, s->addr + reg); + uintptr_t addr; + uint8_t version; + uint8_t baseclock; + struct { + bool sdma; + uint64_t reg; + } capab; + } sdhci; + struct { + uint16_t vendor_id, device_id; + } pci; } + * + * implemented drivers: + * + PC via PCI + { "x86_64", "pc", + {-1, 2, 0, {1, 0x057834b4} }, + .pci =3D { PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_SDHCI } = }, + + BCM2835 + { "arm", "raspi2", + {0x3f300000, 3, 52, {0, 0x052134b4} } }, + * + * FIXME: the following drivers are missing: + * + Exynos4210 + { "arm", "smdkc210", + {0x12510000, 2, 0, {1, 0x5e80080} } }, =20 - return val; -} - -static uint64_t sdhci_readq(QSDHCI *s, uint32_t reg) -{ - uint64_t val; - - if (s->pci.dev) { - val =3D qpci_io_readq(s->pci.dev, s->mem_bar, reg); - } else { - val =3D qtest_readq(global_qtest, s->addr + reg); - } + i.MX 6 + { "arm", "sabrelite", + {0x02190000, 3, 0, {1, 0x057834b4} } }, =20 - return val; -} + Zynq-7000 + { "arm", "xilinx-zynq-a9", Datasheet: UG585 (v1.12.1) + {0xe0100000, 2, 0, {1, 0x69ec0080} } }, =20 -static void sdhci_writeq(QSDHCI *s, uint32_t reg, uint64_t val) -{ - if (s->pci.dev) { - qpci_io_writeq(s->pci.dev, s->mem_bar, reg, val); - } else { - qtest_writeq(global_qtest, s->addr + reg, val); - } -} + ZynqMP + { "aarch64", "xlnx-zcu102", Datasheet: UG1085 (v1.7) + {0xff160000, 3, 0, {1, 0x280737ec6481} } }, + */ =20 static void check_specs_version(QSDHCI *s, uint8_t version) { uint32_t v; =20 - v =3D sdhci_readw(s, SDHC_HCVER); + v =3D s->sdhci_readw(s, SDHC_HCVER); v &=3D 0xff; v +=3D 1; g_assert_cmpuint(v, =3D=3D, version); @@ -122,7 +85,7 @@ static void check_capab_capareg(QSDHCI *s, uint64_t expe= c_capab) { uint64_t capab; =20 - capab =3D sdhci_readq(s, SDHC_CAPAB); + capab =3D s->sdhci_readq(s, SDHC_CAPAB); g_assert_cmphex(capab, =3D=3D, expec_capab); } =20 @@ -131,11 +94,11 @@ static void check_capab_readonly(QSDHCI *s) const uint64_t vrand =3D 0x123456789abcdef; uint64_t capab0, capab1; =20 - capab0 =3D sdhci_readq(s, SDHC_CAPAB); + capab0 =3D s->sdhci_readq(s, SDHC_CAPAB); g_assert_cmpuint(capab0, !=3D, vrand); =20 - sdhci_writeq(s, SDHC_CAPAB, vrand); - capab1 =3D sdhci_readq(s, SDHC_CAPAB); + s->sdhci_writeq(s, SDHC_CAPAB, vrand); + capab1 =3D s->sdhci_readq(s, SDHC_CAPAB); g_assert_cmpuint(capab1, !=3D, vrand); g_assert_cmpuint(capab1, =3D=3D, capab0); } @@ -147,7 +110,7 @@ static void check_capab_baseclock(QSDHCI *s, uint8_t ex= pec_freq) if (!expec_freq) { return; } - capab =3D sdhci_readq(s, SDHC_CAPAB); + capab =3D s->sdhci_readq(s, SDHC_CAPAB); capab_freq =3D FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ); g_assert_cmpuint(capab_freq, =3D=3D, expec_freq); } @@ -156,7 +119,7 @@ static void check_capab_sdma(QSDHCI *s, bool supported) { uint64_t capab, capab_sdma; =20 - capab =3D sdhci_readq(s, SDHC_CAPAB); + capab =3D s->sdhci_readq(s, SDHC_CAPAB); capab_sdma =3D FIELD_EX64(capab, SDHC_CAPAB, SDMA); g_assert_cmpuint(capab_sdma, =3D=3D, supported); } @@ -167,7 +130,7 @@ static void check_capab_v3(QSDHCI *s, uint8_t version) =20 if (version < 3) { /* before v3 those fields are RESERVED */ - capab =3D sdhci_readq(s, SDHC_CAPAB); + capab =3D s->sdhci_readq(s, SDHC_CAPAB); capab_v3 =3D FIELD_EX64(capab, SDHC_CAPAB, SDR); g_assert_cmpuint(capab_v3, =3D=3D, 0); capab_v3 =3D FIELD_EX64(capab, SDHC_CAPAB, DRIVER); @@ -175,78 +138,21 @@ static void check_capab_v3(QSDHCI *s, uint8_t version) } } =20 -static QSDHCI *machine_start(const struct sdhci_t *test) -{ - QSDHCI *s =3D g_new0(QSDHCI, 1); - - if (test->pci.vendor_id) { - /* PCI */ - uint16_t vendor_id, device_id; - uint64_t barsize; - - global_qtest =3D qtest_startf("-machine %s -device sdhci-pci", - test->machine); - - s->pci.bus =3D qpci_init_pc(global_qtest, NULL); - - /* Find PCI device and verify it's the right one */ - s->pci.dev =3D qpci_device_find(s->pci.bus, QPCI_DEVFN(4, 0)); - g_assert_nonnull(s->pci.dev); - vendor_id =3D qpci_config_readw(s->pci.dev, PCI_VENDOR_ID); - device_id =3D qpci_config_readw(s->pci.dev, PCI_DEVICE_ID); - g_assert(vendor_id =3D=3D test->pci.vendor_id); - g_assert(device_id =3D=3D test->pci.device_id); - s->mem_bar =3D qpci_iomap(s->pci.dev, 0, &barsize); - qpci_device_enable(s->pci.dev); - } else { - /* SysBus */ - global_qtest =3D qtest_startf("-machine %s", test->machine); - s->addr =3D test->sdhci.addr; - } - - return s; -} - -static void machine_stop(QSDHCI *s) +static void test_machine(void *obj, void *data) { - qpci_free_pc(s->pci.bus); - g_free(s->pci.dev); - qtest_quit(global_qtest); - g_free(s); -} + QSDHCI *s =3D (QSDHCI *)obj; =20 -static void test_machine(const void *data) -{ - const struct sdhci_t *test =3D data; - QSDHCI *s; - - s =3D machine_start(test); - - check_specs_version(s, test->sdhci.version); - check_capab_capareg(s, test->sdhci.capab.reg); + check_specs_version(s, s->props.version); + check_capab_capareg(s, s->props.capab.reg); check_capab_readonly(s); - check_capab_v3(s, test->sdhci.version); - check_capab_sdma(s, test->sdhci.capab.sdma); - check_capab_baseclock(s, test->sdhci.baseclock); - - machine_stop(s); + check_capab_v3(s, s->props.version); + check_capab_sdma(s, s->props.capab.sdma); + check_capab_baseclock(s, s->props.baseclock); } =20 -int main(int argc, char *argv[]) +static void sdhci_test(void) { - const char *arch =3D qtest_get_arch(); - char *name; - int i; - - g_test_init(&argc, &argv, NULL); - for (i =3D 0; i < ARRAY_SIZE(models); i++) { - if (strcmp(arch, models[i].arch)) { - continue; - } - name =3D g_strdup_printf("sdhci/%s", models[i].machine); - qtest_add_data_func(name, &models[i], test_machine); - g_free(name); - } - - return g_test_run(); + qos_add_test("sdhci-test", "sdhci", test_machine); } + +libqos_init(sdhci_test); --=20 2.17.1