Annotation of qemu/tests/libqtest.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.