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