]> Git Repo - qemu.git/blob - qtest.c
Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
[qemu.git] / qtest.c
1 /*
2  * Test Server
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <[email protected]>
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 struct 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(struct timeval *tv)
136 {
137     gettimeofday(tv, NULL);
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     struct 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, tv.tv_usec);
157 }
158
159 static void qtest_send(CharDriverState *chr, const char *fmt, ...)
160 {
161     va_list ap;
162     char buffer[1024];
163     size_t len;
164
165     va_start(ap, fmt);
166     len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
167     va_end(ap);
168
169     qemu_chr_fe_write(chr, (uint8_t *)buffer, len);
170     if (qtest_log_fp && qtest_opened) {
171         fprintf(qtest_log_fp, "%s", buffer);
172     }
173 }
174
175 static void qtest_irq_handler(void *opaque, int n, int level)
176 {
177     qemu_irq *old_irqs = opaque;
178     qemu_set_irq(old_irqs[n], level);
179
180     if (irq_levels[n] != level) {
181         CharDriverState *chr = qtest_chr;
182         irq_levels[n] = level;
183         qtest_send_prefix(chr);
184         qtest_send(chr, "IRQ %s %d\n",
185                    level ? "raise" : "lower", n);
186     }
187 }
188
189 static void qtest_process_command(CharDriverState *chr, gchar **words)
190 {
191     const gchar *command;
192
193     g_assert(words);
194
195     command = words[0];
196
197     if (qtest_log_fp) {
198         struct timeval tv;
199         int i;
200
201         qtest_get_time(&tv);
202         fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
203                 tv.tv_sec, tv.tv_usec);
204         for (i = 0; words[i]; i++) {
205             fprintf(qtest_log_fp, " %s", words[i]);
206         }
207         fprintf(qtest_log_fp, "\n");
208     }
209
210     g_assert(command);
211     if (strcmp(words[0], "irq_intercept_out") == 0
212         || strcmp(words[0], "irq_intercept_in") == 0) {
213         DeviceState *dev;
214
215         g_assert(words[1]);
216         dev = DEVICE(object_resolve_path(words[1], NULL));
217         if (!dev) {
218             qtest_send_prefix(chr);
219             qtest_send(chr, "FAIL Unknown device\n");
220             return;
221         }
222
223         if (irq_intercept_dev) {
224             qtest_send_prefix(chr);
225             if (irq_intercept_dev != dev) {
226                 qtest_send(chr, "FAIL IRQ intercept already enabled\n");
227             } else {
228                 qtest_send(chr, "OK\n");
229             }
230             return;
231         }
232
233         if (words[0][14] == 'o') {
234             qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
235         } else {
236             qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
237         }
238         irq_intercept_dev = dev;
239         qtest_send_prefix(chr);
240         qtest_send(chr, "OK\n");
241
242     } else if (strcmp(words[0], "outb") == 0 ||
243                strcmp(words[0], "outw") == 0 ||
244                strcmp(words[0], "outl") == 0) {
245         uint16_t addr;
246         uint32_t value;
247
248         g_assert(words[1] && words[2]);
249         addr = strtol(words[1], NULL, 0);
250         value = strtol(words[2], NULL, 0);
251
252         if (words[0][3] == 'b') {
253             cpu_outb(addr, value);
254         } else if (words[0][3] == 'w') {
255             cpu_outw(addr, value);
256         } else if (words[0][3] == 'l') {
257             cpu_outl(addr, value);
258         }
259         qtest_send_prefix(chr);
260         qtest_send(chr, "OK\n");
261     } else if (strcmp(words[0], "inb") == 0 ||
262         strcmp(words[0], "inw") == 0 ||
263         strcmp(words[0], "inl") == 0) {
264         uint16_t addr;
265         uint32_t value = -1U;
266
267         g_assert(words[1]);
268         addr = strtol(words[1], NULL, 0);
269
270         if (words[0][2] == 'b') {
271             value = cpu_inb(addr);
272         } else if (words[0][2] == 'w') {
273             value = cpu_inw(addr);
274         } else if (words[0][2] == 'l') {
275             value = cpu_inl(addr);
276         }
277         qtest_send_prefix(chr);
278         qtest_send(chr, "OK 0x%04x\n", value);
279     } else if (strcmp(words[0], "read") == 0) {
280         uint64_t addr, len, i;
281         uint8_t *data;
282
283         g_assert(words[1] && words[2]);
284         addr = strtoul(words[1], NULL, 0);
285         len = strtoul(words[2], NULL, 0);
286
287         data = g_malloc(len);
288         cpu_physical_memory_read(addr, data, len);
289
290         qtest_send_prefix(chr);
291         qtest_send(chr, "OK 0x");
292         for (i = 0; i < len; i++) {
293             qtest_send(chr, "%02x", data[i]);
294         }
295         qtest_send(chr, "\n");
296
297         g_free(data);
298     } else if (strcmp(words[0], "write") == 0) {
299         uint64_t addr, len, i;
300         uint8_t *data;
301         size_t data_len;
302
303         g_assert(words[1] && words[2] && words[3]);
304         addr = strtoul(words[1], NULL, 0);
305         len = strtoul(words[2], NULL, 0);
306
307         data_len = strlen(words[3]);
308         if (data_len < 3) {
309             qtest_send(chr, "ERR invalid argument size\n");
310             return;
311         }
312
313         data = g_malloc(len);
314         for (i = 0; i < len; i++) {
315             if ((i * 2 + 4) <= data_len) {
316                 data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
317                 data[i] |= hex2nib(words[3][i * 2 + 3]);
318             } else {
319                 data[i] = 0;
320             }
321         }
322         cpu_physical_memory_write(addr, data, len);
323         g_free(data);
324
325         qtest_send_prefix(chr);
326         qtest_send(chr, "OK\n");
327     } else if (strcmp(words[0], "clock_step") == 0) {
328         int64_t ns;
329
330         if (words[1]) {
331             ns = strtoll(words[1], NULL, 0);
332         } else {
333             ns = qemu_clock_deadline(vm_clock);
334         }
335         qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
336         qtest_send_prefix(chr);
337         qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
338     } else if (strcmp(words[0], "clock_set") == 0) {
339         int64_t ns;
340
341         g_assert(words[1]);
342         ns = strtoll(words[1], NULL, 0);
343         qtest_clock_warp(ns);
344         qtest_send_prefix(chr);
345         qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
346     } else {
347         qtest_send_prefix(chr);
348         qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
349     }
350 }
351
352 static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
353 {
354     char *end;
355
356     while ((end = strchr(inbuf->str, '\n')) != NULL) {
357         size_t offset;
358         GString *cmd;
359         gchar **words;
360
361         offset = end - inbuf->str;
362
363         cmd = g_string_new_len(inbuf->str, offset);
364         g_string_erase(inbuf, 0, offset + 1);
365
366         words = g_strsplit(cmd->str, " ", 0);
367         qtest_process_command(chr, words);
368         g_strfreev(words);
369
370         g_string_free(cmd, TRUE);
371     }
372 }
373
374 static void qtest_read(void *opaque, const uint8_t *buf, int size)
375 {
376     CharDriverState *chr = opaque;
377
378     g_string_append_len(inbuf, (const gchar *)buf, size);
379     qtest_process_inbuf(chr, inbuf);
380 }
381
382 static int qtest_can_read(void *opaque)
383 {
384     return 1024;
385 }
386
387 static void qtest_event(void *opaque, int event)
388 {
389     int i;
390
391     switch (event) {
392     case CHR_EVENT_OPENED:
393         qemu_system_reset(false);
394         for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
395             irq_levels[i] = 0;
396         }
397         gettimeofday(&start_time, NULL);
398         qtest_opened = true;
399         if (qtest_log_fp) {
400             fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
401                     start_time.tv_sec, start_time.tv_usec);
402         }
403         break;
404     case CHR_EVENT_CLOSED:
405         qtest_opened = false;
406         if (qtest_log_fp) {
407             struct timeval tv;
408             qtest_get_time(&tv);
409             fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
410                     tv.tv_sec, tv.tv_usec);
411         }
412         break;
413     default:
414         break;
415     }
416 }
417
418 int qtest_init(void)
419 {
420     CharDriverState *chr;
421
422     g_assert(qtest_chrdev != NULL);
423
424     configure_icount("0");
425     chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
426
427     qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
428     qemu_chr_fe_set_echo(chr, true);
429
430     inbuf = g_string_new("");
431
432     if (qtest_log) {
433         if (strcmp(qtest_log, "none") != 0) {
434             qtest_log_fp = fopen(qtest_log, "w+");
435         }
436     } else {
437         qtest_log_fp = stderr;
438     }
439
440     qtest_chr = chr;
441
442     return 0;
443 }
This page took 0.048099 seconds and 4 git commands to generate.