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