qemu/qtest.c
<<
>>
Prefs
   1/*
   2 * Test Server
   3 *
   4 * Copyright IBM, Corp. 2011
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 *
  12 */
  13
  14#include "sysemu/qtest.h"
  15#include "hw/qdev.h"
  16#include "sysemu/char.h"
  17#include "exec/ioport.h"
  18#include "exec/memory.h"
  19#include "hw/irq.h"
  20#include "sysemu/sysemu.h"
  21#include "sysemu/cpus.h"
  22
  23#define MAX_IRQ 256
  24
  25bool qtest_allowed;
  26
  27static DeviceState *irq_intercept_dev;
  28static FILE *qtest_log_fp;
  29static CharDriverState *qtest_chr;
  30static GString *inbuf;
  31static int irq_levels[MAX_IRQ];
  32static qemu_timeval start_time;
  33static bool qtest_opened;
  34
  35#define FMT_timeval "%ld.%06ld"
  36
  37/**
  38 * QTest Protocol
  39 *
  40 * Line based protocol, request/response based.  Server can send async messages
  41 * so clients should always handle many async messages before the response
  42 * comes in.
  43 *
  44 * Valid requests
  45 *
  46 * Clock management:
  47 *
  48 * The qtest client is completely in charge of the QEMU_CLOCK_VIRTUAL.  qtest commands
  49 * let you adjust the value of the clock (monotonically).  All the commands
  50 * return the current value of the clock in nanoseconds.
  51 *
  52 *  > clock_step
  53 *  < OK VALUE
  54 *
  55 *     Advance the clock to the next deadline.  Useful when waiting for
  56 *     asynchronous events.
  57 *
  58 *  > clock_step NS
  59 *  < OK VALUE
  60 *
  61 *     Advance the clock by NS nanoseconds.
  62 *
  63 *  > clock_set NS
  64 *  < OK VALUE
  65 *
  66 *     Advance the clock to NS nanoseconds (do nothing if it's already past).
  67 *
  68 * PIO and memory access:
  69 *
  70 *  > outb ADDR VALUE
  71 *  < OK
  72 *
  73 *  > outw ADDR VALUE
  74 *  < OK
  75 *
  76 *  > outl ADDR VALUE
  77 *  < OK
  78 *
  79 *  > inb ADDR
  80 *  < OK VALUE
  81 *
  82 *  > inw ADDR
  83 *  < OK VALUE
  84 *
  85 *  > inl ADDR
  86 *  < OK VALUE
  87 *
  88 *  > writeb ADDR VALUE
  89 *  < OK
  90 *
  91 *  > writew ADDR VALUE
  92 *  < OK
  93 *
  94 *  > writel ADDR VALUE
  95 *  < OK
  96 *
  97 *  > writeq ADDR VALUE
  98 *  < OK
  99 *
 100 *  > readb ADDR
 101 *  < OK VALUE
 102 *
 103 *  > readw ADDR
 104 *  < OK VALUE
 105 *
 106 *  > readl ADDR
 107 *  < OK VALUE
 108 *
 109 *  > readq ADDR
 110 *  < OK VALUE
 111 *
 112 *  > read ADDR SIZE
 113 *  < OK DATA
 114 *
 115 *  > write ADDR SIZE DATA
 116 *  < OK
 117 *
 118 * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
 119 *
 120 * DATA is an arbitrarily long hex number prefixed with '0x'.  If it's smaller
 121 * than the expected size, the value will be zero filled at the end of the data
 122 * sequence.
 123 *
 124 * IRQ management:
 125 *
 126 *  > irq_intercept_in QOM-PATH
 127 *  < OK
 128 *
 129 *  > irq_intercept_out QOM-PATH
 130 *  < OK
 131 *
 132 * Attach to the gpio-in (resp. gpio-out) pins exported by the device at
 133 * QOM-PATH.  When the pin is triggered, one of the following async messages
 134 * will be printed to the qtest stream:
 135 *
 136 *  IRQ raise NUM
 137 *  IRQ lower NUM
 138 *
 139 * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
 140 * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
 141 * NUM=0 even though it is remapped to GSI 2).
 142 */
 143
 144static int hex2nib(char ch)
 145{
 146    if (ch >= '0' && ch <= '9') {
 147        return ch - '0';
 148    } else if (ch >= 'a' && ch <= 'f') {
 149        return 10 + (ch - 'a');
 150    } else if (ch >= 'A' && ch <= 'F') {
 151        return 10 + (ch - 'A');
 152    } else {
 153        return -1;
 154    }
 155}
 156
 157static void qtest_get_time(qemu_timeval *tv)
 158{
 159    qemu_gettimeofday(tv);
 160    tv->tv_sec -= start_time.tv_sec;
 161    tv->tv_usec -= start_time.tv_usec;
 162    if (tv->tv_usec < 0) {
 163        tv->tv_usec += 1000000;
 164        tv->tv_sec -= 1;
 165    }
 166}
 167
 168static void qtest_send_prefix(CharDriverState *chr)
 169{
 170    qemu_timeval tv;
 171
 172    if (!qtest_log_fp || !qtest_opened) {
 173        return;
 174    }
 175
 176    qtest_get_time(&tv);
 177    fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
 178            (long) tv.tv_sec, (long) tv.tv_usec);
 179}
 180
 181static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
 182                                          const char *fmt, ...)
 183{
 184    va_list ap;
 185    char buffer[1024];
 186    size_t len;
 187
 188    va_start(ap, fmt);
 189    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
 190    va_end(ap);
 191
 192    qemu_chr_fe_write_all(chr, (uint8_t *)buffer, len);
 193    if (qtest_log_fp && qtest_opened) {
 194        fprintf(qtest_log_fp, "%s", buffer);
 195    }
 196}
 197
 198static void qtest_irq_handler(void *opaque, int n, int level)
 199{
 200    qemu_irq *old_irqs = opaque;
 201    qemu_set_irq(old_irqs[n], level);
 202
 203    if (irq_levels[n] != level) {
 204        CharDriverState *chr = qtest_chr;
 205        irq_levels[n] = level;
 206        qtest_send_prefix(chr);
 207        qtest_send(chr, "IRQ %s %d\n",
 208                   level ? "raise" : "lower", n);
 209    }
 210}
 211
 212static void qtest_process_command(CharDriverState *chr, gchar **words)
 213{
 214    const gchar *command;
 215
 216    g_assert(words);
 217
 218    command = words[0];
 219
 220    if (qtest_log_fp) {
 221        qemu_timeval tv;
 222        int i;
 223
 224        qtest_get_time(&tv);
 225        fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
 226                (long) tv.tv_sec, (long) tv.tv_usec);
 227        for (i = 0; words[i]; i++) {
 228            fprintf(qtest_log_fp, " %s", words[i]);
 229        }
 230        fprintf(qtest_log_fp, "\n");
 231    }
 232
 233    g_assert(command);
 234    if (strcmp(words[0], "irq_intercept_out") == 0
 235        || strcmp(words[0], "irq_intercept_in") == 0) {
 236        DeviceState *dev;
 237        NamedGPIOList *ngl;
 238
 239        g_assert(words[1]);
 240        dev = DEVICE(object_resolve_path(words[1], NULL));
 241        if (!dev) {
 242            qtest_send_prefix(chr);
 243            qtest_send(chr, "FAIL Unknown device\n");
 244            return;
 245        }
 246
 247        if (irq_intercept_dev) {
 248            qtest_send_prefix(chr);
 249            if (irq_intercept_dev != dev) {
 250                qtest_send(chr, "FAIL IRQ intercept already enabled\n");
 251            } else {
 252                qtest_send(chr, "OK\n");
 253            }
 254            return;
 255        }
 256
 257        QLIST_FOREACH(ngl, &dev->gpios, node) {
 258            /* We don't support intercept of named GPIOs yet */
 259            if (ngl->name) {
 260                continue;
 261            }
 262            if (words[0][14] == 'o') {
 263                qemu_irq_intercept_out(&ngl->out, qtest_irq_handler,
 264                                       ngl->num_out);
 265            } else {
 266                qemu_irq_intercept_in(ngl->in, qtest_irq_handler,
 267                                      ngl->num_in);
 268            }
 269        }
 270        irq_intercept_dev = dev;
 271        qtest_send_prefix(chr);
 272        qtest_send(chr, "OK\n");
 273
 274    } else if (strcmp(words[0], "outb") == 0 ||
 275               strcmp(words[0], "outw") == 0 ||
 276               strcmp(words[0], "outl") == 0) {
 277        uint16_t addr;
 278        uint32_t value;
 279
 280        g_assert(words[1] && words[2]);
 281        addr = strtoul(words[1], NULL, 0);
 282        value = strtoul(words[2], NULL, 0);
 283
 284        if (words[0][3] == 'b') {
 285            cpu_outb(addr, value);
 286        } else if (words[0][3] == 'w') {
 287            cpu_outw(addr, value);
 288        } else if (words[0][3] == 'l') {
 289            cpu_outl(addr, value);
 290        }
 291        qtest_send_prefix(chr);
 292        qtest_send(chr, "OK\n");
 293    } else if (strcmp(words[0], "inb") == 0 ||
 294        strcmp(words[0], "inw") == 0 ||
 295        strcmp(words[0], "inl") == 0) {
 296        uint16_t addr;
 297        uint32_t value = -1U;
 298
 299        g_assert(words[1]);
 300        addr = strtoul(words[1], NULL, 0);
 301
 302        if (words[0][2] == 'b') {
 303            value = cpu_inb(addr);
 304        } else if (words[0][2] == 'w') {
 305            value = cpu_inw(addr);
 306        } else if (words[0][2] == 'l') {
 307            value = cpu_inl(addr);
 308        }
 309        qtest_send_prefix(chr);
 310        qtest_send(chr, "OK 0x%04x\n", value);
 311    } else if (strcmp(words[0], "writeb") == 0 ||
 312               strcmp(words[0], "writew") == 0 ||
 313               strcmp(words[0], "writel") == 0 ||
 314               strcmp(words[0], "writeq") == 0) {
 315        uint64_t addr;
 316        uint64_t value;
 317
 318        g_assert(words[1] && words[2]);
 319        addr = strtoull(words[1], NULL, 0);
 320        value = strtoull(words[2], NULL, 0);
 321
 322        if (words[0][5] == 'b') {
 323            uint8_t data = value;
 324            cpu_physical_memory_write(addr, &data, 1);
 325        } else if (words[0][5] == 'w') {
 326            uint16_t data = value;
 327            tswap16s(&data);
 328            cpu_physical_memory_write(addr, &data, 2);
 329        } else if (words[0][5] == 'l') {
 330            uint32_t data = value;
 331            tswap32s(&data);
 332            cpu_physical_memory_write(addr, &data, 4);
 333        } else if (words[0][5] == 'q') {
 334            uint64_t data = value;
 335            tswap64s(&data);
 336            cpu_physical_memory_write(addr, &data, 8);
 337        }
 338        qtest_send_prefix(chr);
 339        qtest_send(chr, "OK\n");
 340    } else if (strcmp(words[0], "readb") == 0 ||
 341               strcmp(words[0], "readw") == 0 ||
 342               strcmp(words[0], "readl") == 0 ||
 343               strcmp(words[0], "readq") == 0) {
 344        uint64_t addr;
 345        uint64_t value = UINT64_C(-1);
 346
 347        g_assert(words[1]);
 348        addr = strtoull(words[1], NULL, 0);
 349
 350        if (words[0][4] == 'b') {
 351            uint8_t data;
 352            cpu_physical_memory_read(addr, &data, 1);
 353            value = data;
 354        } else if (words[0][4] == 'w') {
 355            uint16_t data;
 356            cpu_physical_memory_read(addr, &data, 2);
 357            value = tswap16(data);
 358        } else if (words[0][4] == 'l') {
 359            uint32_t data;
 360            cpu_physical_memory_read(addr, &data, 4);
 361            value = tswap32(data);
 362        } else if (words[0][4] == 'q') {
 363            cpu_physical_memory_read(addr, &value, 8);
 364            tswap64s(&value);
 365        }
 366        qtest_send_prefix(chr);
 367        qtest_send(chr, "OK 0x%016" PRIx64 "\n", value);
 368    } else if (strcmp(words[0], "read") == 0) {
 369        uint64_t addr, len, i;
 370        uint8_t *data;
 371
 372        g_assert(words[1] && words[2]);
 373        addr = strtoull(words[1], NULL, 0);
 374        len = strtoull(words[2], NULL, 0);
 375
 376        data = g_malloc(len);
 377        cpu_physical_memory_read(addr, data, len);
 378
 379        qtest_send_prefix(chr);
 380        qtest_send(chr, "OK 0x");
 381        for (i = 0; i < len; i++) {
 382            qtest_send(chr, "%02x", data[i]);
 383        }
 384        qtest_send(chr, "\n");
 385
 386        g_free(data);
 387    } else if (strcmp(words[0], "write") == 0) {
 388        uint64_t addr, len, i;
 389        uint8_t *data;
 390        size_t data_len;
 391
 392        g_assert(words[1] && words[2] && words[3]);
 393        addr = strtoull(words[1], NULL, 0);
 394        len = strtoull(words[2], NULL, 0);
 395
 396        data_len = strlen(words[3]);
 397        if (data_len < 3) {
 398            qtest_send(chr, "ERR invalid argument size\n");
 399            return;
 400        }
 401
 402        data = g_malloc(len);
 403        for (i = 0; i < len; i++) {
 404            if ((i * 2 + 4) <= data_len) {
 405                data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
 406                data[i] |= hex2nib(words[3][i * 2 + 3]);
 407            } else {
 408                data[i] = 0;
 409            }
 410        }
 411        cpu_physical_memory_write(addr, data, len);
 412        g_free(data);
 413
 414        qtest_send_prefix(chr);
 415        qtest_send(chr, "OK\n");
 416    } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
 417        int64_t ns;
 418
 419        if (words[1]) {
 420            ns = strtoll(words[1], NULL, 0);
 421        } else {
 422            ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
 423        }
 424        qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns);
 425        qtest_send_prefix(chr);
 426        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 427    } else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
 428        int64_t ns;
 429
 430        g_assert(words[1]);
 431        ns = strtoll(words[1], NULL, 0);
 432        qtest_clock_warp(ns);
 433        qtest_send_prefix(chr);
 434        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 435    } else {
 436        qtest_send_prefix(chr);
 437        qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
 438    }
 439}
 440
 441static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
 442{
 443    char *end;
 444
 445    while ((end = strchr(inbuf->str, '\n')) != NULL) {
 446        size_t offset;
 447        GString *cmd;
 448        gchar **words;
 449
 450        offset = end - inbuf->str;
 451
 452        cmd = g_string_new_len(inbuf->str, offset);
 453        g_string_erase(inbuf, 0, offset + 1);
 454
 455        words = g_strsplit(cmd->str, " ", 0);
 456        qtest_process_command(chr, words);
 457        g_strfreev(words);
 458
 459        g_string_free(cmd, TRUE);
 460    }
 461}
 462
 463static void qtest_read(void *opaque, const uint8_t *buf, int size)
 464{
 465    CharDriverState *chr = opaque;
 466
 467    g_string_append_len(inbuf, (const gchar *)buf, size);
 468    qtest_process_inbuf(chr, inbuf);
 469}
 470
 471static int qtest_can_read(void *opaque)
 472{
 473    return 1024;
 474}
 475
 476static void qtest_event(void *opaque, int event)
 477{
 478    int i;
 479
 480    switch (event) {
 481    case CHR_EVENT_OPENED:
 482        /*
 483         * We used to call qemu_system_reset() here, hoping we could
 484         * use the same process for multiple tests that way.  Never
 485         * used.  Injects an extra reset even when it's not used, and
 486         * that can mess up tests, e.g. -boot once.
 487         */
 488        for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
 489            irq_levels[i] = 0;
 490        }
 491        qemu_gettimeofday(&start_time);
 492        qtest_opened = true;
 493        if (qtest_log_fp) {
 494            fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
 495                    (long) start_time.tv_sec, (long) start_time.tv_usec);
 496        }
 497        break;
 498    case CHR_EVENT_CLOSED:
 499        qtest_opened = false;
 500        if (qtest_log_fp) {
 501            qemu_timeval tv;
 502            qtest_get_time(&tv);
 503            fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
 504                    (long) tv.tv_sec, (long) tv.tv_usec);
 505        }
 506        break;
 507    default:
 508        break;
 509    }
 510}
 511
 512int qtest_init_accel(MachineClass *mc)
 513{
 514    configure_icount("0");
 515
 516    return 0;
 517}
 518
 519void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
 520{
 521    CharDriverState *chr;
 522
 523    chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
 524
 525    if (chr == NULL) {
 526        error_setg(errp, "Failed to initialize device for qtest: \"%s\"",
 527                   qtest_chrdev);
 528        return;
 529    }
 530
 531    qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
 532    qemu_chr_fe_set_echo(chr, true);
 533
 534    inbuf = g_string_new("");
 535
 536    if (qtest_log) {
 537        if (strcmp(qtest_log, "none") != 0) {
 538            qtest_log_fp = fopen(qtest_log, "w+");
 539        }
 540    } else {
 541        qtest_log_fp = stderr;
 542    }
 543
 544    qtest_chr = chr;
 545}
 546
 547bool qtest_driver(void)
 548{
 549    return qtest_chr;
 550}
 551