qemu/tests/libqtest.c
<<
>>
Prefs
   1/*
   2 * QTest
   3 *
   4 * Copyright IBM, Corp. 2012
   5 * Copyright Red Hat, Inc. 2012
   6 *
   7 * Authors:
   8 *  Anthony Liguori   <aliguori@us.ibm.com>
   9 *  Paolo Bonzini     <pbonzini@redhat.com>
  10 *
  11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12 * See the COPYING file in the top-level directory.
  13 *
  14 */
  15#include "libqtest.h"
  16
  17#include <glib.h>
  18#include <sys/types.h>
  19#include <sys/socket.h>
  20#include <sys/wait.h>
  21#include <sys/un.h>
  22#include <inttypes.h>
  23#include <errno.h>
  24#include <stdio.h>
  25#include <stdlib.h>
  26#include <unistd.h>
  27#include <string.h>
  28
  29#include "compiler.h"
  30#include "osdep.h"
  31
  32#define MAX_IRQ 256
  33
  34QTestState *global_qtest;
  35
  36struct QTestState
  37{
  38    int fd;
  39    int qmp_fd;
  40    bool irq_level[MAX_IRQ];
  41    GString *rx;
  42    gchar *pid_file;
  43};
  44
  45#define g_assert_no_errno(ret) do { \
  46    g_assert_cmpint(ret, !=, -1); \
  47} while (0)
  48
  49static int init_socket(const char *socket_path)
  50{
  51    struct sockaddr_un addr;
  52    int sock;
  53    int ret;
  54
  55    sock = socket(PF_UNIX, SOCK_STREAM, 0);
  56    g_assert_no_errno(sock);
  57
  58    addr.sun_family = AF_UNIX;
  59    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
  60    qemu_set_cloexec(sock);
  61
  62    do {
  63        ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
  64    } while (ret == -1 && errno == EINTR);
  65    g_assert_no_errno(ret);
  66    listen(sock, 1);
  67
  68    return sock;
  69}
  70
  71static int socket_accept(int sock)
  72{
  73    struct sockaddr_un addr;
  74    socklen_t addrlen;
  75    int ret;
  76
  77    do {
  78        ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
  79    } while (ret == -1 && errno == EINTR);
  80    g_assert_no_errno(ret);
  81    close(sock);
  82
  83    return ret;
  84}
  85
  86QTestState *qtest_init(const char *extra_args)
  87{
  88    QTestState *s;
  89    int sock, qmpsock, ret, i;
  90    gchar *socket_path;
  91    gchar *qmp_socket_path;
  92    gchar *pid_file;
  93    gchar *command;
  94    const char *qemu_binary;
  95    pid_t pid;
  96
  97    qemu_binary = getenv("QTEST_QEMU_BINARY");
  98    g_assert(qemu_binary != NULL);
  99
 100    socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
 101    qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
 102    pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
 103
 104    s = g_malloc(sizeof(*s));
 105
 106    sock = init_socket(socket_path);
 107    qmpsock = init_socket(qmp_socket_path);
 108
 109    pid = fork();
 110    if (pid == 0) {
 111        command = g_strdup_printf("%s "
 112                                  "-qtest unix:%s,nowait "
 113                                  "-qtest-log /dev/null "
 114                                  "-qmp unix:%s,nowait "
 115                                  "-pidfile %s "
 116                                  "-machine accel=qtest "
 117                                  "%s", qemu_binary, socket_path,
 118                                  qmp_socket_path, pid_file,
 119                                  extra_args ?: "");
 120
 121        ret = system(command);
 122        exit(ret);
 123        g_free(command);
 124    }
 125
 126    s->fd = socket_accept(sock);
 127    s->qmp_fd = socket_accept(qmpsock);
 128
 129    s->rx = g_string_new("");
 130    s->pid_file = pid_file;
 131    for (i = 0; i < MAX_IRQ; i++) {
 132        s->irq_level[i] = false;
 133    }
 134
 135    g_free(socket_path);
 136    g_free(qmp_socket_path);
 137
 138    /* Read the QMP greeting and then do the handshake */
 139    qtest_qmp(s, "");
 140    qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }");
 141
 142    return s;
 143}
 144
 145void qtest_quit(QTestState *s)
 146{
 147    FILE *f;
 148    char buffer[1024];
 149
 150    f = fopen(s->pid_file, "r");
 151    if (f) {
 152        if (fgets(buffer, sizeof(buffer), f)) {
 153            pid_t pid = atoi(buffer);
 154            int status = 0;
 155
 156            kill(pid, SIGTERM);
 157            waitpid(pid, &status, 0);
 158        }
 159
 160        fclose(f);
 161    }
 162}
 163
 164static void socket_sendf(int fd, const char *fmt, va_list ap)
 165{
 166    gchar *str;
 167    size_t size, offset;
 168
 169    str = g_strdup_vprintf(fmt, ap);
 170    size = strlen(str);
 171
 172    offset = 0;
 173    while (offset < size) {
 174        ssize_t len;
 175
 176        len = write(fd, str + offset, size - offset);
 177        if (len == -1 && errno == EINTR) {
 178            continue;
 179        }
 180
 181        g_assert_no_errno(len);
 182        g_assert_cmpint(len, >, 0);
 183
 184        offset += len;
 185    }
 186}
 187
 188static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
 189{
 190    va_list ap;
 191
 192    va_start(ap, fmt);
 193    socket_sendf(s->fd, fmt, ap);
 194    va_end(ap);
 195}
 196
 197static GString *qtest_recv_line(QTestState *s)
 198{
 199    GString *line;
 200    size_t offset;
 201    char *eol;
 202
 203    while ((eol = strchr(s->rx->str, '\n')) == NULL) {
 204        ssize_t len;
 205        char buffer[1024];
 206
 207        len = read(s->fd, buffer, sizeof(buffer));
 208        if (len == -1 && errno == EINTR) {
 209            continue;
 210        }
 211
 212        if (len == -1 || len == 0) {
 213            fprintf(stderr, "Broken pipe\n");
 214            exit(1);
 215        }
 216
 217        g_string_append_len(s->rx, buffer, len);
 218    }
 219
 220    offset = eol - s->rx->str;
 221    line = g_string_new_len(s->rx->str, offset);
 222    g_string_erase(s->rx, 0, offset + 1);
 223
 224    return line;
 225}
 226
 227static gchar **qtest_rsp(QTestState *s, int expected_args)
 228{
 229    GString *line;
 230    gchar **words;
 231    int i;
 232
 233redo:
 234    line = qtest_recv_line(s);
 235    words = g_strsplit(line->str, " ", 0);
 236    g_string_free(line, TRUE);
 237
 238    if (strcmp(words[0], "IRQ") == 0) {
 239        int irq;
 240
 241        g_assert(words[1] != NULL);
 242        g_assert(words[2] != NULL);
 243
 244        irq = strtoul(words[2], NULL, 0);
 245        g_assert_cmpint(irq, >=, 0);
 246        g_assert_cmpint(irq, <, MAX_IRQ);
 247
 248        if (strcmp(words[1], "raise") == 0) {
 249            s->irq_level[irq] = true;
 250        } else {
 251            s->irq_level[irq] = false;
 252        }
 253
 254        g_strfreev(words);
 255        goto redo;
 256    }
 257
 258    g_assert(words[0] != NULL);
 259    g_assert_cmpstr(words[0], ==, "OK");
 260
 261    if (expected_args) {
 262        for (i = 0; i < expected_args; i++) {
 263            g_assert(words[i] != NULL);
 264        }
 265    } else {
 266        g_strfreev(words);
 267    }
 268
 269    return words;
 270}
 271
 272void qtest_qmp(QTestState *s, const char *fmt, ...)
 273{
 274    va_list ap;
 275    bool has_reply = false;
 276    int nesting = 0;
 277
 278    /* Send QMP request */
 279    va_start(ap, fmt);
 280    socket_sendf(s->qmp_fd, fmt, ap);
 281    va_end(ap);
 282
 283    /* Receive reply */
 284    while (!has_reply || nesting > 0) {
 285        ssize_t len;
 286        char c;
 287
 288        len = read(s->qmp_fd, &c, 1);
 289        if (len == -1 && errno == EINTR) {
 290            continue;
 291        }
 292
 293        switch (c) {
 294        case '{':
 295            nesting++;
 296            has_reply = true;
 297            break;
 298        case '}':
 299            nesting--;
 300            break;
 301        }
 302    }
 303}
 304
 305const char *qtest_get_arch(void)
 306{
 307    const char *qemu = getenv("QTEST_QEMU_BINARY");
 308    const char *end = strrchr(qemu, '/');
 309
 310    return end + strlen("/qemu-system-");
 311}
 312
 313bool qtest_get_irq(QTestState *s, int num)
 314{
 315    /* dummy operation in order to make sure irq is up to date */
 316    qtest_inb(s, 0);
 317
 318    return s->irq_level[num];
 319}
 320
 321static int64_t qtest_clock_rsp(QTestState *s)
 322{
 323    gchar **words;
 324    int64_t clock;
 325    words = qtest_rsp(s, 2);
 326    clock = g_ascii_strtoll(words[1], NULL, 0);
 327    g_strfreev(words);
 328    return clock;
 329}
 330
 331int64_t qtest_clock_step_next(QTestState *s)
 332{
 333    qtest_sendf(s, "clock_step\n");
 334    return qtest_clock_rsp(s);
 335}
 336
 337int64_t qtest_clock_step(QTestState *s, int64_t step)
 338{
 339    qtest_sendf(s, "clock_step %"PRIi64"\n", step);
 340    return qtest_clock_rsp(s);
 341}
 342
 343int64_t qtest_clock_set(QTestState *s, int64_t val)
 344{
 345    qtest_sendf(s, "clock_set %"PRIi64"\n", val);
 346    return qtest_clock_rsp(s);
 347}
 348
 349void qtest_irq_intercept_out(QTestState *s, const char *qom_path)
 350{
 351    qtest_sendf(s, "irq_intercept_out %s\n", qom_path);
 352    qtest_rsp(s, 0);
 353}
 354
 355void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
 356{
 357    qtest_sendf(s, "irq_intercept_in %s\n", qom_path);
 358    qtest_rsp(s, 0);
 359}
 360
 361static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
 362{
 363    qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
 364    qtest_rsp(s, 0);
 365}
 366
 367void qtest_outb(QTestState *s, uint16_t addr, uint8_t value)
 368{
 369    qtest_out(s, "outb", addr, value);
 370}
 371
 372void qtest_outw(QTestState *s, uint16_t addr, uint16_t value)
 373{
 374    qtest_out(s, "outw", addr, value);
 375}
 376
 377void qtest_outl(QTestState *s, uint16_t addr, uint32_t value)
 378{
 379    qtest_out(s, "outl", addr, value);
 380}
 381
 382static uint32_t qtest_in(QTestState *s, const char *cmd, uint16_t addr)
 383{
 384    gchar **args;
 385    uint32_t value;
 386
 387    qtest_sendf(s, "%s 0x%x\n", cmd, addr);
 388    args = qtest_rsp(s, 2);
 389    value = strtoul(args[1], NULL, 0);
 390    g_strfreev(args);
 391
 392    return value;
 393}
 394
 395uint8_t qtest_inb(QTestState *s, uint16_t addr)
 396{
 397    return qtest_in(s, "inb", addr);
 398}
 399
 400uint16_t qtest_inw(QTestState *s, uint16_t addr)
 401{
 402    return qtest_in(s, "inw", addr);
 403}
 404
 405uint32_t qtest_inl(QTestState *s, uint16_t addr)
 406{
 407    return qtest_in(s, "inl", addr);
 408}
 409
 410static int hex2nib(char ch)
 411{
 412    if (ch >= '0' && ch <= '9') {
 413        return ch - '0';
 414    } else if (ch >= 'a' && ch <= 'f') {
 415        return 10 + (ch - 'a');
 416    } else if (ch >= 'A' && ch <= 'F') {
 417        return 10 + (ch - 'a');
 418    } else {
 419        return -1;
 420    }
 421}
 422
 423void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
 424{
 425    uint8_t *ptr = data;
 426    gchar **args;
 427    size_t i;
 428
 429    qtest_sendf(s, "read 0x%" PRIx64 " 0x%zx\n", addr, size);
 430    args = qtest_rsp(s, 2);
 431
 432    for (i = 0; i < size; i++) {
 433        ptr[i] = hex2nib(args[1][2 + (i * 2)]) << 4;
 434        ptr[i] |= hex2nib(args[1][2 + (i * 2) + 1]);
 435    }
 436
 437    g_strfreev(args);
 438}
 439
 440void qtest_add_func(const char *str, void (*fn))
 441{
 442    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
 443    g_test_add_func(path, fn);
 444}
 445
 446void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
 447{
 448    const uint8_t *ptr = data;
 449    size_t i;
 450
 451    qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x", addr, size);
 452    for (i = 0; i < size; i++) {
 453        qtest_sendf(s, "%02x", ptr[i]);
 454    }
 455    qtest_sendf(s, "\n");
 456    qtest_rsp(s, 0);
 457}
 458