|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.