summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/acpi-utils.h10
-rw-r--r--tests/bios-tables-test.c23
-rw-r--r--tests/test-char.c366
-rw-r--r--tests/vhost-user-test.c2
4 files changed, 390 insertions, 11 deletions
diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h
index 348e4d7931..f8d87236c6 100644
--- a/tests/acpi-utils.h
+++ b/tests/acpi-utils.h
@@ -87,6 +87,16 @@ typedef struct {
     g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
 } while (0)
 
+#define ACPI_READ_GENERIC_ADDRESS(field, addr)       \
+    do {                                             \
+        ACPI_READ_FIELD((field).space_id, addr);     \
+        ACPI_READ_FIELD((field).bit_width, addr);    \
+        ACPI_READ_FIELD((field).bit_offset, addr);   \
+        ACPI_READ_FIELD((field).access_width, addr); \
+        ACPI_READ_FIELD((field).address, addr);      \
+    } while (0);
+
+
 uint8_t acpi_calc_checksum(const uint8_t *data, int len);
 uint32_t acpi_find_rsdp_address(void);
 void acpi_parse_rsdp_table(uint32_t addr, AcpiRsdpDescriptor *rsdp_table);
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 88dbf97853..9c96a67053 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -29,7 +29,7 @@ typedef struct {
     uint32_t rsdp_addr;
     AcpiRsdpDescriptor rsdp_table;
     AcpiRsdtDescriptorRev1 rsdt_table;
-    AcpiFadtDescriptorRev1 fadt_table;
+    AcpiFadtDescriptorRev3 fadt_table;
     AcpiFacsDescriptorRev1 facs_table;
     uint32_t *rsdt_tables_addr;
     int rsdt_tables_nr;
@@ -126,7 +126,7 @@ static void test_acpi_rsdt_table(test_data *data)
 
 static void test_acpi_fadt_table(test_data *data)
 {
-    AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table;
+    AcpiFadtDescriptorRev3 *fadt_table = &data->fadt_table;
     uint32_t addr;
 
     /* FADT table comes first */
@@ -168,10 +168,23 @@ static void test_acpi_fadt_table(test_data *data)
     ACPI_READ_FIELD(fadt_table->day_alrm, addr);
     ACPI_READ_FIELD(fadt_table->mon_alrm, addr);
     ACPI_READ_FIELD(fadt_table->century, addr);
-    ACPI_READ_FIELD(fadt_table->reserved4, addr);
-    ACPI_READ_FIELD(fadt_table->reserved4a, addr);
-    ACPI_READ_FIELD(fadt_table->reserved4b, addr);
+    ACPI_READ_FIELD(fadt_table->boot_flags, addr);
+    ACPI_READ_FIELD(fadt_table->reserved, addr);
     ACPI_READ_FIELD(fadt_table->flags, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->reset_register, addr);
+    ACPI_READ_FIELD(fadt_table->reset_value, addr);
+    ACPI_READ_FIELD(fadt_table->arm_boot_flags, addr);
+    ACPI_READ_FIELD(fadt_table->minor_revision, addr);
+    ACPI_READ_FIELD(fadt_table->Xfacs, addr);
+    ACPI_READ_FIELD(fadt_table->Xdsdt, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1a_event_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1b_event_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1a_control_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1b_control_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm2_control_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm_timer_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xgpe0_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xgpe1_block, addr);
 
     ACPI_ASSERT_CMP(fadt_table->signature, "FACP");
     g_assert(!acpi_calc_checksum((uint8_t *)fadt_table, fadt_table->length));
diff --git a/tests/test-char.c b/tests/test-char.c
index da69f110e4..773a1c36ba 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -1,18 +1,35 @@
 #include "qemu/osdep.h"
+#include <glib/gstdio.h>
 
 #include "qemu-common.h"
 #include "qemu/config-file.h"
+#include "qemu/sockets.h"
 #include "sysemu/char.h"
 #include "sysemu/sysemu.h"
 #include "qapi/error.h"
+#include "qom/qom-qobject.h"
 #include "qmp-commands.h"
 
+static bool quit;
+
 typedef struct FeHandler {
     int read_count;
     int last_event;
     char read_buf[128];
 } FeHandler;
 
+static void main_loop(void)
+{
+    bool nonblocking;
+    int last_io = 0;
+
+    quit = false;
+    do {
+        nonblocking = last_io > 0;
+        last_io = main_loop_wait(nonblocking);
+    } while (!quit);
+}
+
 static int fe_can_read(void *opaque)
 {
     FeHandler *h = opaque;
@@ -28,6 +45,7 @@ static void fe_read(void *opaque, const uint8_t *buf, int size)
 
     memcpy(h->read_buf + h->read_count, buf, size);
     h->read_count += size;
+    quit = true;
 }
 
 static void fe_event(void *opaque, int event)
@@ -35,9 +53,36 @@ static void fe_event(void *opaque, int event)
     FeHandler *h = opaque;
 
     h->last_event = event;
+    quit = true;
 }
 
 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+#ifdef _WIN32
+static void char_console_test_subprocess(void)
+{
+    QemuOpts *opts;
+    Chardev *chr;
+
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "console", &error_abort);
+
+    chr = qemu_chr_new_from_opts(opts, NULL);
+    g_assert_nonnull(chr);
+
+    qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
+
+    qemu_opts_del(opts);
+    object_unparent(OBJECT(chr));
+}
+
+static void char_console_test(void)
+{
+    g_test_trap_subprocess("/char/console/subprocess", 0, 0);
+    g_test_trap_assert_passed();
+    g_test_trap_assert_stdout("CONSOLE");
+}
+#endif
 static void char_stdio_test_subprocess(void)
 {
     Chardev *chr;
@@ -53,7 +98,7 @@ static void char_stdio_test_subprocess(void)
     g_assert_cmpint(ret, ==, 4);
 
     qemu_chr_fe_deinit(&be);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 }
 
 static void char_stdio_test(void)
@@ -64,7 +109,6 @@ static void char_stdio_test(void)
 }
 #endif
 
-
 static void char_ringbuf_test(void)
 {
     QemuOpts *opts;
@@ -103,7 +147,17 @@ static void char_ringbuf_test(void)
     g_free(data);
 
     qemu_chr_fe_deinit(&be);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
+
+    /* check alias */
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "memory", &error_abort);
+    qemu_opt_set(opts, "size", "2", &error_abort);
+    chr = qemu_chr_new_from_opts(opts, NULL);
+    g_assert_nonnull(chr);
+    object_unparent(OBJECT(chr));
+    qemu_opts_del(opts);
 }
 
 static void char_mux_test(void)
@@ -179,7 +233,296 @@ static void char_mux_test(void)
 
     qemu_chr_fe_deinit(&chr_be1);
     qemu_chr_fe_deinit(&chr_be2);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
+}
+
+typedef struct SocketIdleData {
+    GMainLoop *loop;
+    Chardev *chr;
+    bool conn_expected;
+    CharBackend *be;
+    CharBackend *client_be;
+} SocketIdleData;
+
+static gboolean char_socket_test_idle(gpointer user_data)
+{
+    SocketIdleData *data = user_data;
+
+    if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
+        == data->conn_expected) {
+        quit = true;
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void socket_read(void *opaque, const uint8_t *buf, int size)
+{
+    SocketIdleData *data = opaque;
+
+    g_assert_cmpint(size, ==, 1);
+    g_assert_cmpint(*buf, ==, 'Z');
+
+    size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
+    g_assert_cmpint(size, ==, 5);
+}
+
+static int socket_can_read(void *opaque)
+{
+    return 10;
+}
+
+static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
+{
+    g_assert_cmpint(size, ==, 5);
+    g_assert(strncmp((char *)buf, "hello", 5) == 0);
+
+    quit = true;
+}
+
+static int socket_can_read_hello(void *opaque)
+{
+    return 10;
+}
+
+static void char_socket_test(void)
+{
+    Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
+    Chardev *chr_client;
+    QObject *addr;
+    QDict *qdict, *data;
+    const char *port;
+    SocketIdleData d = { .chr = chr };
+    CharBackend be;
+    CharBackend client_be;
+    char *tmp;
+
+    d.be = &be;
+    d.client_be = &be;
+
+    g_assert_nonnull(chr);
+    g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
+
+    addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
+    qdict = qobject_to_qdict(addr);
+    data = qdict_get_qdict(qdict, "data");
+    port = qdict_get_str(data, "port");
+    tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
+    QDECREF(qdict);
+
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
+                             NULL, &d, NULL, true);
+
+    chr_client = qemu_chr_new("client", tmp);
+    qemu_chr_fe_init(&client_be, chr_client, &error_abort);
+    qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
+                             socket_read_hello,
+                             NULL, &d, NULL, true);
+    g_free(tmp);
+
+    d.conn_expected = true;
+    guint id = g_idle_add(char_socket_test_idle, &d);
+    g_source_set_name_by_id(id, "test-idle");
+    g_assert_cmpint(id, >, 0);
+    main_loop();
+
+    g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
+    g_assert(object_property_get_bool(OBJECT(chr_client),
+                                      "connected", &error_abort));
+
+    qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
+    main_loop();
+
+    object_unparent(OBJECT(chr_client));
+
+    d.conn_expected = false;
+    g_idle_add(char_socket_test_idle, &d);
+    main_loop();
+
+    object_unparent(OBJECT(chr));
+}
+
+#ifndef _WIN32
+static void char_pipe_test(void)
+{
+    gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+    gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
+    Chardev *chr;
+    CharBackend be;
+    int ret, fd;
+    char buf[10];
+    FeHandler fe = { 0, };
+
+    in = g_strdup_printf("%s.in", pipe);
+    if (mkfifo(in, 0600) < 0) {
+        abort();
+    }
+    out = g_strdup_printf("%s.out", pipe);
+    if (mkfifo(out, 0600) < 0) {
+        abort();
+    }
+
+    tmp = g_strdup_printf("pipe:%s", pipe);
+    chr = qemu_chr_new("pipe", tmp);
+    g_assert_nonnull(chr);
+    g_free(tmp);
+
+    qemu_chr_fe_init(&be, chr, &error_abort);
+
+    ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
+    g_assert_cmpint(ret, ==, 9);
+
+    fd = open(out, O_RDWR);
+    ret = read(fd, buf, sizeof(buf));
+    g_assert_cmpint(ret, ==, 9);
+    g_assert_cmpstr(buf, ==, "pipe-out");
+    close(fd);
+
+    fd = open(in, O_WRONLY);
+    ret = write(fd, "pipe-in", 8);
+    g_assert_cmpint(ret, ==, 8);
+    close(fd);
+
+    qemu_chr_fe_set_handlers(&be,
+                             fe_can_read,
+                             fe_read,
+                             fe_event,
+                             &fe,
+                             NULL, true);
+
+    main_loop();
+
+    g_assert_cmpint(fe.read_count, ==, 8);
+    g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
+
+    qemu_chr_fe_deinit(&be);
+    object_unparent(OBJECT(chr));
+
+    g_assert(g_unlink(in) == 0);
+    g_assert(g_unlink(out) == 0);
+    g_assert(g_rmdir(tmp_path) == 0);
+    g_free(in);
+    g_free(out);
+    g_free(tmp_path);
+    g_free(pipe);
+}
+#endif
+
+static void char_udp_test(void)
+{
+    struct sockaddr_in addr = { 0, }, other;
+    SocketIdleData d = { 0, };
+    Chardev *chr;
+    CharBackend be;
+    socklen_t alen = sizeof(addr);
+    int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
+    char buf[10];
+    char *tmp;
+
+    g_assert_cmpint(sock, >, 0);
+    addr.sin_family = AF_INET ;
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin_port = 0;
+    ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+    g_assert_cmpint(ret, ==, 0);
+    ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
+    g_assert_cmpint(ret, ==, 0);
+
+    tmp = g_strdup_printf("udp:127.0.0.1:%d",
+                          ntohs(addr.sin_port));
+    chr = qemu_chr_new("client", tmp);
+    g_assert_nonnull(chr);
+
+    d.chr = chr;
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&be, socket_can_read_hello, socket_read_hello,
+                             NULL, &d, NULL, true);
+    ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
+    g_assert_cmpint(ret, ==, 5);
+
+    alen = sizeof(addr);
+    ret = recvfrom(sock, buf, sizeof(buf), 0,
+                   (struct sockaddr *)&other, &alen);
+    g_assert_cmpint(ret, ==, 5);
+    ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
+    g_assert_cmpint(ret, ==, 5);
+
+    main_loop();
+
+    close(sock);
+    g_free(tmp);
+}
+
+static void char_file_test(void)
+{
+    char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+    char *out = g_build_filename(tmp_path, "out", NULL);
+    char *contents = NULL;
+    ChardevFile file = { .out = out };
+    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
+                               .u.file.data = &file };
+    Chardev *chr;
+    gsize length;
+    int ret;
+
+    chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+                           &error_abort);
+    ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
+    g_assert_cmpint(ret, ==, 6);
+    object_unref(OBJECT(chr));
+
+    ret = g_file_get_contents(out, &contents, &length, NULL);
+    g_assert(ret == TRUE);
+    g_assert_cmpint(length, ==, 6);
+    g_assert(strncmp(contents, "hello!", 6) == 0);
+    g_free(contents);
+
+#ifndef _WIN32
+    {
+        CharBackend be;
+        FeHandler fe = { 0, };
+        char *fifo = g_build_filename(tmp_path, "fifo", NULL);
+        int fd;
+
+        if (mkfifo(fifo, 0600) < 0) {
+            abort();
+        }
+
+        fd = open(fifo, O_RDWR);
+        ret = write(fd, "fifo-in", 8);
+        g_assert_cmpint(ret, ==, 8);
+
+        file.in = fifo;
+        file.has_in = true;
+        chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+                               &error_abort);
+
+        qemu_chr_fe_init(&be, chr, &error_abort);
+        qemu_chr_fe_set_handlers(&be,
+                                 fe_can_read,
+                                 fe_read,
+                                 fe_event,
+                                 &fe, NULL, true);
+
+        main_loop();
+
+        close(fd);
+
+        g_assert_cmpint(fe.read_count, ==, 8);
+        g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
+        qemu_chr_fe_deinit(&be);
+        object_unref(OBJECT(chr));
+        g_unlink(fifo);
+        g_free(fifo);
+    }
+#endif
+
+    g_unlink(out);
+    g_rmdir(tmp_path);
+    g_free(tmp_path);
+    g_free(out);
 }
 
 static void char_null_test(void)
@@ -222,7 +565,7 @@ static void char_null_test(void)
     g_assert_cmpint(ret, ==, 4);
 
     qemu_chr_fe_deinit(&be);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 }
 
 static void char_invalid_test(void)
@@ -235,6 +578,9 @@ static void char_invalid_test(void)
 
 int main(int argc, char **argv)
 {
+    qemu_init_main_loop(&error_abort);
+    socket_init();
+
     g_test_init(&argc, &argv, NULL);
 
     module_call_init(MODULE_INIT_QOM);
@@ -245,9 +591,19 @@ int main(int argc, char **argv)
     g_test_add_func("/char/ringbuf", char_ringbuf_test);
     g_test_add_func("/char/mux", char_mux_test);
 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+#ifdef _WIN32
+    g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
+    g_test_add_func("/char/console", char_console_test);
+#endif
     g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
     g_test_add_func("/char/stdio", char_stdio_test);
 #endif
+#ifndef _WIN32
+    g_test_add_func("/char/pipe", char_pipe_test);
+#endif
+    g_test_add_func("/char/file", char_file_test);
+    g_test_add_func("/char/socket", char_socket_test);
+    g_test_add_func("/char/udp", char_udp_test);
 
     return g_test_run();
 }
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index a61896c32d..9095af267e 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -491,7 +491,7 @@ static gboolean _test_server_free(TestServer *server)
     Chardev *chr = qemu_chr_fe_get_driver(&server->chr);
 
     qemu_chr_fe_deinit(&server->chr);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 
     for (i = 0; i < server->fds_num; i++) {
         close(server->fds[i]);