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 "qtest.h"
  15#include "hw/qdev.h"
  16#include "qemu-char.h"
  17#include "ioport.h"
  18#include "memory.h"
  19#include "hw/irq.h"
  20#include "sysemu.h"
  21#include "cpus.h"
  22
  23#define MAX_IRQ 256
  24
  25const char *qtest_chrdev;
  26const char *qtest_log;
  27int qtest_allowed = 0;
  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 *  > read ADDR SIZE
  91 *  < OK DATA
  92 *
  93 *  > write ADDR SIZE DATA
  94 *  < OK
  95 *
  96 * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
  97 *
  98 * DATA is an arbitrarily long hex number prefixed with '0x'.  If it's smaller
  99 * than the expected size, the value will be zero filled at the end of the data
 100 * sequence.
 101 *
 102 * IRQ management:
 103 *
 104 *  > irq_intercept_in QOM-PATH
 105 *  < OK
 106 *
 107 *  > irq_intercept_out QOM-PATH
 108 *  < OK
 109 *
 110 * Attach to the gpio-in (resp. gpio-out) pins exported by the device at
 111 * QOM-PATH.  When the pin is triggered, one of the following async messages
 112 * will be printed to the qtest stream:
 113 *
 114 *  IRQ raise NUM
 115 *  IRQ lower NUM
 116 *
 117 * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
 118 * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
 119 * NUM=0 even though it is remapped to GSI 2).
 120 */
 121
 122static int hex2nib(char ch)
 123{
 124    if (ch >= '0' && ch <= '9') {
 125        return ch - '0';
 126    } else if (ch >= 'a' && ch <= 'f') {
 127        return 10 + (ch - 'a');
 128    } else if (ch >= 'A' && ch <= 'F') {
 129        return 10 + (ch - 'a');
 130    } else {
 131        return -1;
 132    }
 133}
 134
 135static void qtest_get_time(qemu_timeval *tv)
 136{
 137    qemu_gettimeofday(tv);
 138    tv->tv_sec -= start_time.tv_sec;
 139    tv->tv_usec -= start_time.tv_usec;
 140    if (tv->tv_usec < 0) {
 141        tv->tv_usec += 1000000;
 142        tv->tv_sec -= 1;
 143    }
 144}
 145
 146static void qtest_send_prefix(CharDriverState *chr)
 147{
 148    qemu_timeval tv;
 149
 150    if (!qtest_log_fp || !qtest_opened) {
 151        return;
 152    }
 153
 154    qtest_get_time(&tv);
 155    fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
 156            tv.tv_sec, (long) tv.tv_usec);
 157}
 158
 159static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
 160                                          const char *fmt, ...)
 161{
 162    va_list ap;
 163    char buffer[1024];
 164    size_t len;
 165
 166    va_start(ap, fmt);
 167    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
 168    va_end(ap);
 169
 170    qemu_chr_fe_write(chr, (uint8_t *)buffer, len);
 171    if (qtest_log_fp && qtest_opened) {
 172        fprintf(qtest_log_fp, "%s", buffer);
 173    }
 174}
 175
 176static void qtest_irq_handler(void *opaque, int n, int level)
 177{
 178    qemu_irq *old_irqs = opaque;
 179    qemu_set_irq(old_irqs[n], level);
 180
 181    if (irq_levels[n] != level) {
 182        CharDriverState *chr = qtest_chr;
 183        irq_levels[n] = level;
 184        qtest_send_prefix(chr);
 185        qtest_send(chr, "IRQ %s %d\n",
 186                   level ? "raise" : "lower", n);
 187    }
 188}
 189
 190static void qtest_process_command(CharDriverState *chr, gchar **words)
 191{
 192    const gchar *command;
 193
 194    g_assert(words);
 195
 196    command = words[0];
 197
 198    if (qtest_log_fp) {
 199        qemu_timeval tv;
 200        int i;
 201
 202        qtest_get_time(&tv);
 203        fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
 204                tv.tv_sec, (long) tv.tv_usec);
 205        for (i = 0; words[i]; i++) {
 206            fprintf(qtest_log_fp, " %s", words[i]);
 207        }
 208        fprintf(qtest_log_fp, "\n");
 209    }
 210
 211    g_assert(command);
 212    if (strcmp(words[0], "irq_intercept_out") == 0
 213        || strcmp(words[0], "irq_intercept_in") == 0) {
 214        DeviceState *dev;
 215
 216        g_assert(words[1]);
 217        dev = DEVICE(object_resolve_path(words[1], NULL));
 218        if (!dev) {
 219            qtest_send_prefix(chr);
 220            qtest_send(chr, "FAIL Unknown device\n");
 221            return;
 222        }
 223
 224        if (irq_intercept_dev) {
 225            qtest_send_prefix(chr);
 226            if (irq_intercept_dev != dev) {
 227                qtest_send(chr, "FAIL IRQ intercept already enabled\n");
 228            } else {
 229                qtest_send(chr, "OK\n");
 230            }
 231            return;
 232        }
 233
 234        if (words[0][14] == 'o') {
 235            qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
 236        } else {
 237            qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
 238        }
 239        irq_intercept_dev = dev;
 240        qtest_send_prefix(chr);
 241        qtest_send(chr, "OK\n");
 242
 243    } else if (strcmp(words[0], "outb") == 0 ||
 244               strcmp(words[0], "outw") == 0 ||
 245               strcmp(words[0], "outl") == 0) {
 246        uint16_t addr;
 247        uint32_t value;
 248
 249        g_assert(words[1] && words[2]);
 250        addr = strtol(words[1], NULL, 0);
 251        value = strtol(words[2], NULL, 0);
 252
 253        if (words[0][3] == 'b') {
 254            cpu_outb(addr, value);
 255        } else if (words[0][3] == 'w') {
 256            cpu_outw(addr, value);
 257        } else if (words[0][3] == 'l') {
 258            cpu_outl(addr, value);
 259        }
 260        qtest_send_prefix(chr);
 261        qtest_send(chr, "OK\n");
 262    } else if (strcmp(words[0], "inb") == 0 ||
 263        strcmp(words[0], "inw") == 0 ||
 264        strcmp(words[0], "inl") == 0) {
 265        uint16_t addr;
 266        uint32_t value = -1U;
 267
 268        g_assert(words[1]);
 269        addr = strtol(words[1], NULL, 0);
 270
 271        if (words[0][2] == 'b') {
 272            value = cpu_inb(addr);
 273        } else if (words[0][2] == 'w') {
 274            value = cpu_inw(addr);
 275        } else if (words[0][2] == 'l') {
 276            value = cpu_inl(addr);
 277        }
 278        qtest_send_prefix(chr);
 279        qtest_send(chr, "OK 0x%04x\n", value);
 280    } else if (strcmp(words[0], "read") == 0) {
 281        uint64_t addr, len, i;
 282        uint8_t *data;
 283
 284        g_assert(words[1] && words[2]);
 285        addr = strtoul(words[1], NULL, 0);
 286        len = strtoul(words[2], NULL, 0);
 287
 288        data = g_malloc(len);
 289        cpu_physical_memory_read(addr, data, len);
 290
 291        qtest_send_prefix(chr);
 292        qtest_send(chr, "OK 0x");
 293        for (i = 0; i < len; i++) {
 294            qtest_send(chr, "%02x", data[i]);
 295        }
 296        qtest_send(chr, "\n");
 297
 298        g_free(data);
 299    } else if (strcmp(words[0], "write") == 0) {
 300        uint64_t addr, len, i;
 301        uint8_t *data;
 302        size_t data_len;
 303
 304        g_assert(words[1] && words[2] && words[3]);
 305        addr = strtoul(words[1], NULL, 0);
 306        len = strtoul(words[2], NULL, 0);
 307
 308        data_len = strlen(words[3]);
 309        if (data_len < 3) {
 310            qtest_send(chr, "ERR invalid argument size\n");
 311            return;
 312        }
 313
 314        data = g_malloc(len);
 315        for (i = 0; i < len; i++) {
 316            if ((i * 2 + 4) <= data_len) {
 317                data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
 318                data[i] |= hex2nib(words[3][i * 2 + 3]);
 319            } else {
 320                data[i] = 0;
 321            }
 322        }
 323        cpu_physical_memory_write(addr, data, len);
 324        g_free(data);
 325
 326        qtest_send_prefix(chr);
 327        qtest_send(chr, "OK\n");
 328    } else if (strcmp(words[0], "clock_step") == 0) {
 329        int64_t ns;
 330
 331        if (words[1]) {
 332            ns = strtoll(words[1], NULL, 0);
 333        } else {
 334            ns = qemu_clock_deadline(vm_clock);
 335        }
 336        qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
 337        qtest_send_prefix(chr);
 338        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
 339    } else if (strcmp(words[0], "clock_set") == 0) {
 340        int64_t ns;
 341
 342        g_assert(words[1]);
 343        ns = strtoll(words[1], NULL, 0);
 344        qtest_clock_warp(ns);
 345        qtest_send_prefix(chr);
 346        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
 347    } else {
 348        qtest_send_prefix(chr);
 349        qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
 350    }
 351}
 352
 353static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
 354{
 355    char *end;
 356
 357    while ((end = strchr(inbuf->str, '\n')) != NULL) {
 358        size_t offset;
 359        GString *cmd;
 360        gchar **words;
 361
 362        offset = end - inbuf->str;
 363
 364        cmd = g_string_new_len(inbuf->str, offset);
 365        g_string_erase(inbuf, 0, offset + 1);
 366
 367        words = g_strsplit(cmd->str, " ", 0);
 368        qtest_process_command(chr, words);
 369        g_strfreev(words);
 370
 371        g_string_free(cmd, TRUE);
 372    }
 373}
 374
 375static void qtest_read(void *opaque, const uint8_t *buf, int size)
 376{
 377    CharDriverState *chr = opaque;
 378
 379    g_string_append_len(inbuf, (const gchar *)buf, size);
 380    qtest_process_inbuf(chr, inbuf);
 381}
 382
 383static int qtest_can_read(void *opaque)
 384{
 385    return 1024;
 386}
 387
 388static void qtest_event(void *opaque, int event)
 389{
 390    int i;
 391
 392    switch (event) {
 393    case CHR_EVENT_OPENED:
 394        qemu_system_reset(false);
 395        for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
 396            irq_levels[i] = 0;
 397        }
 398        qemu_gettimeofday(&start_time);
 399        qtest_opened = true;
 400        if (qtest_log_fp) {
 401            fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
 402                    start_time.tv_sec, (long) start_time.tv_usec);
 403        }
 404        break;
 405    case CHR_EVENT_CLOSED:
 406        qtest_opened = false;
 407        if (qtest_log_fp) {
 408            qemu_timeval tv;
 409            qtest_get_time(&tv);
 410            fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
 411                    tv.tv_sec, (long) tv.tv_usec);
 412        }
 413        break;
 414    default:
 415        break;
 416    }
 417}
 418
 419int qtest_init(void)
 420{
 421    CharDriverState *chr;
 422
 423    g_assert(qtest_chrdev != NULL);
 424
 425    configure_icount("0");
 426    chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
 427
 428    qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
 429    qemu_chr_fe_set_echo(chr, true);
 430
 431    inbuf = g_string_new("");
 432
 433    if (qtest_log) {
 434        if (strcmp(qtest_log, "none") != 0) {
 435            qtest_log_fp = fopen(qtest_log, "w+");
 436        }
 437    } else {
 438        qtest_log_fp = stderr;
 439    }
 440
 441    qtest_chr = chr;
 442
 443    return 0;
 444}
 445