Annotation of qemu/qtest.c, revision 1.1.1.1

1.1       root        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: 
                     25: const char *qtest_chrdev;
                     26: const char *qtest_log;
                     27: int qtest_allowed = 0;
                     28: 
                     29: static DeviceState *irq_intercept_dev;
                     30: static FILE *qtest_log_fp;
                     31: static CharDriverState *qtest_chr;
                     32: static GString *inbuf;
                     33: static int irq_levels[MAX_IRQ];
                     34: static qemu_timeval start_time;
                     35: static 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: 
                    122: static 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: 
                    135: static 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: 
                    146: static 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: 
                    159: static 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: 
                    176: static 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: 
                    190: static 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: 
                    353: static 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: 
                    375: static 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: 
                    383: static int qtest_can_read(void *opaque)
                    384: {
                    385:     return 1024;
                    386: }
                    387: 
                    388: static 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: 
                    419: int 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: }

unix.superglobalmegacorp.com