Statistics
| Branch: | Revision:

root / qtest.c @ feature-archipelago

History | View | Annotate | Download (13.8 kB)

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 "sysemu/qtest.h"
15
#include "hw/qdev.h"
16
#include "sysemu/char.h"
17
#include "exec/ioport.h"
18
#include "exec/memory.h"
19
#include "hw/irq.h"
20
#include "sysemu/sysemu.h"
21
#include "sysemu/cpus.h"
22

    
23
#define MAX_IRQ 256
24

    
25
bool qtest_allowed;
26

    
27
static DeviceState *irq_intercept_dev;
28
static FILE *qtest_log_fp;
29
static CharDriverState *qtest_chr;
30
static GString *inbuf;
31
static int irq_levels[MAX_IRQ];
32
static qemu_timeval start_time;
33
static bool qtest_opened;
34

    
35
#define FMT_timeval "%ld.%06ld"
36

    
37
/**
38
 * QTest Protocol
39
 *
40
 * Line based protocol, request/response based.  Server can send async messages
41
 * so clients should always handle many async messages before the response
42
 * comes in.
43
 *
44
 * Valid requests
45
 *
46
 * Clock management:
47
 *
48
 * The qtest client is completely in charge of the QEMU_CLOCK_VIRTUAL.  qtest commands
49
 * let you adjust the value of the clock (monotonically).  All the commands
50
 * return the current value of the clock in nanoseconds.
51
 *
52
 *  > clock_step
53
 *  < OK VALUE
54
 *
55
 *     Advance the clock to the next deadline.  Useful when waiting for
56
 *     asynchronous events.
57
 *
58
 *  > clock_step NS
59
 *  < OK VALUE
60
 *
61
 *     Advance the clock by NS nanoseconds.
62
 *
63
 *  > clock_set NS
64
 *  < OK VALUE
65
 *
66
 *     Advance the clock to NS nanoseconds (do nothing if it's already past).
67
 *
68
 * PIO and memory access:
69
 *
70
 *  > outb ADDR VALUE
71
 *  < OK
72
 *
73
 *  > outw ADDR VALUE
74
 *  < OK
75
 *
76
 *  > outl ADDR VALUE
77
 *  < OK
78
 *
79
 *  > inb ADDR
80
 *  < OK VALUE
81
 *
82
 *  > inw ADDR
83
 *  < OK VALUE
84
 *
85
 *  > inl ADDR
86
 *  < OK VALUE
87
 *
88
 *  > writeb ADDR VALUE
89
 *  < OK
90
 *
91
 *  > writew ADDR VALUE
92
 *  < OK
93
 *
94
 *  > writel ADDR VALUE
95
 *  < OK
96
 *
97
 *  > writeq ADDR VALUE
98
 *  < OK
99
 *
100
 *  > readb ADDR
101
 *  < OK VALUE
102
 *
103
 *  > readw ADDR
104
 *  < OK VALUE
105
 *
106
 *  > readl ADDR
107
 *  < OK VALUE
108
 *
109
 *  > readq ADDR
110
 *  < OK VALUE
111
 *
112
 *  > read ADDR SIZE
113
 *  < OK DATA
114
 *
115
 *  > write ADDR SIZE DATA
116
 *  < OK
117
 *
118
 * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
119
 *
120
 * DATA is an arbitrarily long hex number prefixed with '0x'.  If it's smaller
121
 * than the expected size, the value will be zero filled at the end of the data
122
 * sequence.
123
 *
124
 * IRQ management:
125
 *
126
 *  > irq_intercept_in QOM-PATH
127
 *  < OK
128
 *
129
 *  > irq_intercept_out QOM-PATH
130
 *  < OK
131
 *
132
 * Attach to the gpio-in (resp. gpio-out) pins exported by the device at
133
 * QOM-PATH.  When the pin is triggered, one of the following async messages
134
 * will be printed to the qtest stream:
135
 *
136
 *  IRQ raise NUM
137
 *  IRQ lower NUM
138
 *
139
 * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
140
 * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
141
 * NUM=0 even though it is remapped to GSI 2).
142
 */
143

    
144
static int hex2nib(char ch)
145
{
146
    if (ch >= '0' && ch <= '9') {
147
        return ch - '0';
148
    } else if (ch >= 'a' && ch <= 'f') {
149
        return 10 + (ch - 'a');
150
    } else if (ch >= 'A' && ch <= 'F') {
151
        return 10 + (ch - 'a');
152
    } else {
153
        return -1;
154
    }
155
}
156

    
157
static void qtest_get_time(qemu_timeval *tv)
158
{
159
    qemu_gettimeofday(tv);
160
    tv->tv_sec -= start_time.tv_sec;
161
    tv->tv_usec -= start_time.tv_usec;
162
    if (tv->tv_usec < 0) {
163
        tv->tv_usec += 1000000;
164
        tv->tv_sec -= 1;
165
    }
166
}
167

    
168
static void qtest_send_prefix(CharDriverState *chr)
169
{
170
    qemu_timeval tv;
171

    
172
    if (!qtest_log_fp || !qtest_opened) {
173
        return;
174
    }
175

    
176
    qtest_get_time(&tv);
177
    fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
178
            (long) tv.tv_sec, (long) tv.tv_usec);
179
}
180

    
181
static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
182
                                          const char *fmt, ...)
183
{
184
    va_list ap;
185
    char buffer[1024];
186
    size_t len;
187

    
188
    va_start(ap, fmt);
189
    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
190
    va_end(ap);
191

    
192
    qemu_chr_fe_write_all(chr, (uint8_t *)buffer, len);
193
    if (qtest_log_fp && qtest_opened) {
194
        fprintf(qtest_log_fp, "%s", buffer);
195
    }
196
}
197

    
198
static void qtest_irq_handler(void *opaque, int n, int level)
199
{
200
    qemu_irq *old_irqs = opaque;
201
    qemu_set_irq(old_irqs[n], level);
202

    
203
    if (irq_levels[n] != level) {
204
        CharDriverState *chr = qtest_chr;
205
        irq_levels[n] = level;
206
        qtest_send_prefix(chr);
207
        qtest_send(chr, "IRQ %s %d\n",
208
                   level ? "raise" : "lower", n);
209
    }
210
}
211

    
212
static void qtest_process_command(CharDriverState *chr, gchar **words)
213
{
214
    const gchar *command;
215

    
216
    g_assert(words);
217

    
218
    command = words[0];
219

    
220
    if (qtest_log_fp) {
221
        qemu_timeval tv;
222
        int i;
223

    
224
        qtest_get_time(&tv);
225
        fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
226
                (long) tv.tv_sec, (long) tv.tv_usec);
227
        for (i = 0; words[i]; i++) {
228
            fprintf(qtest_log_fp, " %s", words[i]);
229
        }
230
        fprintf(qtest_log_fp, "\n");
231
    }
232

    
233
    g_assert(command);
234
    if (strcmp(words[0], "irq_intercept_out") == 0
235
        || strcmp(words[0], "irq_intercept_in") == 0) {
236
        DeviceState *dev;
237

    
238
        g_assert(words[1]);
239
        dev = DEVICE(object_resolve_path(words[1], NULL));
240
        if (!dev) {
241
            qtest_send_prefix(chr);
242
            qtest_send(chr, "FAIL Unknown device\n");
243
            return;
244
        }
245

    
246
        if (irq_intercept_dev) {
247
            qtest_send_prefix(chr);
248
            if (irq_intercept_dev != dev) {
249
                qtest_send(chr, "FAIL IRQ intercept already enabled\n");
250
            } else {
251
                qtest_send(chr, "OK\n");
252
            }
253
            return;
254
        }
255

    
256
        if (words[0][14] == 'o') {
257
            qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
258
        } else {
259
            qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
260
        }
261
        irq_intercept_dev = dev;
262
        qtest_send_prefix(chr);
263
        qtest_send(chr, "OK\n");
264

    
265
    } else if (strcmp(words[0], "outb") == 0 ||
266
               strcmp(words[0], "outw") == 0 ||
267
               strcmp(words[0], "outl") == 0) {
268
        uint16_t addr;
269
        uint32_t value;
270

    
271
        g_assert(words[1] && words[2]);
272
        addr = strtoul(words[1], NULL, 0);
273
        value = strtoul(words[2], NULL, 0);
274

    
275
        if (words[0][3] == 'b') {
276
            cpu_outb(addr, value);
277
        } else if (words[0][3] == 'w') {
278
            cpu_outw(addr, value);
279
        } else if (words[0][3] == 'l') {
280
            cpu_outl(addr, value);
281
        }
282
        qtest_send_prefix(chr);
283
        qtest_send(chr, "OK\n");
284
    } else if (strcmp(words[0], "inb") == 0 ||
285
        strcmp(words[0], "inw") == 0 ||
286
        strcmp(words[0], "inl") == 0) {
287
        uint16_t addr;
288
        uint32_t value = -1U;
289

    
290
        g_assert(words[1]);
291
        addr = strtoul(words[1], NULL, 0);
292

    
293
        if (words[0][2] == 'b') {
294
            value = cpu_inb(addr);
295
        } else if (words[0][2] == 'w') {
296
            value = cpu_inw(addr);
297
        } else if (words[0][2] == 'l') {
298
            value = cpu_inl(addr);
299
        }
300
        qtest_send_prefix(chr);
301
        qtest_send(chr, "OK 0x%04x\n", value);
302
    } else if (strcmp(words[0], "writeb") == 0 ||
303
               strcmp(words[0], "writew") == 0 ||
304
               strcmp(words[0], "writel") == 0 ||
305
               strcmp(words[0], "writeq") == 0) {
306
        uint64_t addr;
307
        uint64_t value;
308

    
309
        g_assert(words[1] && words[2]);
310
        addr = strtoull(words[1], NULL, 0);
311
        value = strtoull(words[2], NULL, 0);
312

    
313
        if (words[0][5] == 'b') {
314
            uint8_t data = value;
315
            cpu_physical_memory_write(addr, &data, 1);
316
        } else if (words[0][5] == 'w') {
317
            uint16_t data = value;
318
            tswap16s(&data);
319
            cpu_physical_memory_write(addr, &data, 2);
320
        } else if (words[0][5] == 'l') {
321
            uint32_t data = value;
322
            tswap32s(&data);
323
            cpu_physical_memory_write(addr, &data, 4);
324
        } else if (words[0][5] == 'q') {
325
            uint64_t data = value;
326
            tswap64s(&data);
327
            cpu_physical_memory_write(addr, &data, 8);
328
        }
329
        qtest_send_prefix(chr);
330
        qtest_send(chr, "OK\n");
331
    } else if (strcmp(words[0], "readb") == 0 ||
332
               strcmp(words[0], "readw") == 0 ||
333
               strcmp(words[0], "readl") == 0 ||
334
               strcmp(words[0], "readq") == 0) {
335
        uint64_t addr;
336
        uint64_t value = UINT64_C(-1);
337

    
338
        g_assert(words[1]);
339
        addr = strtoull(words[1], NULL, 0);
340

    
341
        if (words[0][4] == 'b') {
342
            uint8_t data;
343
            cpu_physical_memory_read(addr, &data, 1);
344
            value = data;
345
        } else if (words[0][4] == 'w') {
346
            uint16_t data;
347
            cpu_physical_memory_read(addr, &data, 2);
348
            value = tswap16(data);
349
        } else if (words[0][4] == 'l') {
350
            uint32_t data;
351
            cpu_physical_memory_read(addr, &data, 4);
352
            value = tswap32(data);
353
        } else if (words[0][4] == 'q') {
354
            cpu_physical_memory_read(addr, &value, 8);
355
            tswap64s(&value);
356
        }
357
        qtest_send_prefix(chr);
358
        qtest_send(chr, "OK 0x%016" PRIx64 "\n", value);
359
    } else if (strcmp(words[0], "read") == 0) {
360
        uint64_t addr, len, i;
361
        uint8_t *data;
362

    
363
        g_assert(words[1] && words[2]);
364
        addr = strtoull(words[1], NULL, 0);
365
        len = strtoull(words[2], NULL, 0);
366

    
367
        data = g_malloc(len);
368
        cpu_physical_memory_read(addr, data, len);
369

    
370
        qtest_send_prefix(chr);
371
        qtest_send(chr, "OK 0x");
372
        for (i = 0; i < len; i++) {
373
            qtest_send(chr, "%02x", data[i]);
374
        }
375
        qtest_send(chr, "\n");
376

    
377
        g_free(data);
378
    } else if (strcmp(words[0], "write") == 0) {
379
        uint64_t addr, len, i;
380
        uint8_t *data;
381
        size_t data_len;
382

    
383
        g_assert(words[1] && words[2] && words[3]);
384
        addr = strtoull(words[1], NULL, 0);
385
        len = strtoull(words[2], NULL, 0);
386

    
387
        data_len = strlen(words[3]);
388
        if (data_len < 3) {
389
            qtest_send(chr, "ERR invalid argument size\n");
390
            return;
391
        }
392

    
393
        data = g_malloc(len);
394
        for (i = 0; i < len; i++) {
395
            if ((i * 2 + 4) <= data_len) {
396
                data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
397
                data[i] |= hex2nib(words[3][i * 2 + 3]);
398
            } else {
399
                data[i] = 0;
400
            }
401
        }
402
        cpu_physical_memory_write(addr, data, len);
403
        g_free(data);
404

    
405
        qtest_send_prefix(chr);
406
        qtest_send(chr, "OK\n");
407
    } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
408
        int64_t ns;
409

    
410
        if (words[1]) {
411
            ns = strtoll(words[1], NULL, 0);
412
        } else {
413
            ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
414
        }
415
        qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns);
416
        qtest_send_prefix(chr);
417
        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
418
    } else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
419
        int64_t ns;
420

    
421
        g_assert(words[1]);
422
        ns = strtoll(words[1], NULL, 0);
423
        qtest_clock_warp(ns);
424
        qtest_send_prefix(chr);
425
        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
426
    } else {
427
        qtest_send_prefix(chr);
428
        qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
429
    }
430
}
431

    
432
static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
433
{
434
    char *end;
435

    
436
    while ((end = strchr(inbuf->str, '\n')) != NULL) {
437
        size_t offset;
438
        GString *cmd;
439
        gchar **words;
440

    
441
        offset = end - inbuf->str;
442

    
443
        cmd = g_string_new_len(inbuf->str, offset);
444
        g_string_erase(inbuf, 0, offset + 1);
445

    
446
        words = g_strsplit(cmd->str, " ", 0);
447
        qtest_process_command(chr, words);
448
        g_strfreev(words);
449

    
450
        g_string_free(cmd, TRUE);
451
    }
452
}
453

    
454
static void qtest_read(void *opaque, const uint8_t *buf, int size)
455
{
456
    CharDriverState *chr = opaque;
457

    
458
    g_string_append_len(inbuf, (const gchar *)buf, size);
459
    qtest_process_inbuf(chr, inbuf);
460
}
461

    
462
static int qtest_can_read(void *opaque)
463
{
464
    return 1024;
465
}
466

    
467
static void qtest_event(void *opaque, int event)
468
{
469
    int i;
470

    
471
    switch (event) {
472
    case CHR_EVENT_OPENED:
473
        /*
474
         * We used to call qemu_system_reset() here, hoping we could
475
         * use the same process for multiple tests that way.  Never
476
         * used.  Injects an extra reset even when it's not used, and
477
         * that can mess up tests, e.g. -boot once.
478
         */
479
        for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
480
            irq_levels[i] = 0;
481
        }
482
        qemu_gettimeofday(&start_time);
483
        qtest_opened = true;
484
        if (qtest_log_fp) {
485
            fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
486
                    (long) start_time.tv_sec, (long) start_time.tv_usec);
487
        }
488
        break;
489
    case CHR_EVENT_CLOSED:
490
        qtest_opened = false;
491
        if (qtest_log_fp) {
492
            qemu_timeval tv;
493
            qtest_get_time(&tv);
494
            fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
495
                    (long) tv.tv_sec, (long) tv.tv_usec);
496
        }
497
        break;
498
    default:
499
        break;
500
    }
501
}
502

    
503
int qtest_init_accel(void)
504
{
505
    configure_icount("0");
506

    
507
    return 0;
508
}
509

    
510
void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
511
{
512
    CharDriverState *chr;
513

    
514
    chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
515

    
516
    if (chr == NULL) {
517
        error_setg(errp, "Failed to initialize device for qtest: \"%s\"",
518
                   qtest_chrdev);
519
        return;
520
    }
521

    
522
    qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
523
    qemu_chr_fe_set_echo(chr, true);
524

    
525
    inbuf = g_string_new("");
526

    
527
    if (qtest_log) {
528
        if (strcmp(qtest_log, "none") != 0) {
529
            qtest_log_fp = fopen(qtest_log, "w+");
530
        }
531
    } else {
532
        qtest_log_fp = stderr;
533
    }
534

    
535
    qtest_chr = chr;
536
}
537

    
538
bool qtest_driver(void)
539
{
540
    return qtest_chr;
541
}