1
2
3
4
5
6
7
8
9
10
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
25const char *qtest_chrdev;
26const char *qtest_log;
27bool qtest_allowed;
28
29static DeviceState *irq_intercept_dev;
30static FILE *qtest_log_fp;
31static CharDriverState *qtest_chr;
32static GString *inbuf;
33static int irq_levels[MAX_IRQ];
34static qemu_timeval start_time;
35static bool qtest_opened;
36
37#define FMT_timeval "%ld.%06ld"
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146static int hex2nib(char ch)
147{
148 if (ch >= '0' && ch <= '9') {
149 return ch - '0';
150 } else if (ch >= 'a' && ch <= 'f') {
151 return 10 + (ch - 'a');
152 } else if (ch >= 'A' && ch <= 'F') {
153 return 10 + (ch - 'a');
154 } else {
155 return -1;
156 }
157}
158
159static void qtest_get_time(qemu_timeval *tv)
160{
161 qemu_gettimeofday(tv);
162 tv->tv_sec -= start_time.tv_sec;
163 tv->tv_usec -= start_time.tv_usec;
164 if (tv->tv_usec < 0) {
165 tv->tv_usec += 1000000;
166 tv->tv_sec -= 1;
167 }
168}
169
170static void qtest_send_prefix(CharDriverState *chr)
171{
172 qemu_timeval tv;
173
174 if (!qtest_log_fp || !qtest_opened) {
175 return;
176 }
177
178 qtest_get_time(&tv);
179 fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
180 tv.tv_sec, (long) tv.tv_usec);
181}
182
183static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
184 const char *fmt, ...)
185{
186 va_list ap;
187 char buffer[1024];
188 size_t len;
189
190 va_start(ap, fmt);
191 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
192 va_end(ap);
193
194 qemu_chr_fe_write_all(chr, (uint8_t *)buffer, len);
195 if (qtest_log_fp && qtest_opened) {
196 fprintf(qtest_log_fp, "%s", buffer);
197 }
198}
199
200static void qtest_irq_handler(void *opaque, int n, int level)
201{
202 qemu_irq *old_irqs = opaque;
203 qemu_set_irq(old_irqs[n], level);
204
205 if (irq_levels[n] != level) {
206 CharDriverState *chr = qtest_chr;
207 irq_levels[n] = level;
208 qtest_send_prefix(chr);
209 qtest_send(chr, "IRQ %s %d\n",
210 level ? "raise" : "lower", n);
211 }
212}
213
214static void qtest_process_command(CharDriverState *chr, gchar **words)
215{
216 const gchar *command;
217
218 g_assert(words);
219
220 command = words[0];
221
222 if (qtest_log_fp) {
223 qemu_timeval tv;
224 int i;
225
226 qtest_get_time(&tv);
227 fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
228 tv.tv_sec, (long) tv.tv_usec);
229 for (i = 0; words[i]; i++) {
230 fprintf(qtest_log_fp, " %s", words[i]);
231 }
232 fprintf(qtest_log_fp, "\n");
233 }
234
235 g_assert(command);
236 if (strcmp(words[0], "irq_intercept_out") == 0
237 || strcmp(words[0], "irq_intercept_in") == 0) {
238 DeviceState *dev;
239
240 g_assert(words[1]);
241 dev = DEVICE(object_resolve_path(words[1], NULL));
242 if (!dev) {
243 qtest_send_prefix(chr);
244 qtest_send(chr, "FAIL Unknown device\n");
245 return;
246 }
247
248 if (irq_intercept_dev) {
249 qtest_send_prefix(chr);
250 if (irq_intercept_dev != dev) {
251 qtest_send(chr, "FAIL IRQ intercept already enabled\n");
252 } else {
253 qtest_send(chr, "OK\n");
254 }
255 return;
256 }
257
258 if (words[0][14] == 'o') {
259 qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
260 } else {
261 qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
262 }
263 irq_intercept_dev = dev;
264 qtest_send_prefix(chr);
265 qtest_send(chr, "OK\n");
266
267 } else if (strcmp(words[0], "outb") == 0 ||
268 strcmp(words[0], "outw") == 0 ||
269 strcmp(words[0], "outl") == 0) {
270 uint16_t addr;
271 uint32_t value;
272
273 g_assert(words[1] && words[2]);
274 addr = strtoul(words[1], NULL, 0);
275 value = strtoul(words[2], NULL, 0);
276
277 if (words[0][3] == 'b') {
278 cpu_outb(addr, value);
279 } else if (words[0][3] == 'w') {
280 cpu_outw(addr, value);
281 } else if (words[0][3] == 'l') {
282 cpu_outl(addr, value);
283 }
284 qtest_send_prefix(chr);
285 qtest_send(chr, "OK\n");
286 } else if (strcmp(words[0], "inb") == 0 ||
287 strcmp(words[0], "inw") == 0 ||
288 strcmp(words[0], "inl") == 0) {
289 uint16_t addr;
290 uint32_t value = -1U;
291
292 g_assert(words[1]);
293 addr = strtoul(words[1], NULL, 0);
294
295 if (words[0][2] == 'b') {
296 value = cpu_inb(addr);
297 } else if (words[0][2] == 'w') {
298 value = cpu_inw(addr);
299 } else if (words[0][2] == 'l') {
300 value = cpu_inl(addr);
301 }
302 qtest_send_prefix(chr);
303 qtest_send(chr, "OK 0x%04x\n", value);
304 } else if (strcmp(words[0], "writeb") == 0 ||
305 strcmp(words[0], "writew") == 0 ||
306 strcmp(words[0], "writel") == 0 ||
307 strcmp(words[0], "writeq") == 0) {
308 uint64_t addr;
309 uint64_t value;
310
311 g_assert(words[1] && words[2]);
312 addr = strtoull(words[1], NULL, 0);
313 value = strtoull(words[2], NULL, 0);
314
315 if (words[0][5] == 'b') {
316 uint8_t data = value;
317 cpu_physical_memory_write(addr, &data, 1);
318 } else if (words[0][5] == 'w') {
319 uint16_t data = value;
320 tswap16s(&data);
321 cpu_physical_memory_write(addr, &data, 2);
322 } else if (words[0][5] == 'l') {
323 uint32_t data = value;
324 tswap32s(&data);
325 cpu_physical_memory_write(addr, &data, 4);
326 } else if (words[0][5] == 'q') {
327 uint64_t data = value;
328 tswap64s(&data);
329 cpu_physical_memory_write(addr, &data, 8);
330 }
331 qtest_send_prefix(chr);
332 qtest_send(chr, "OK\n");
333 } else if (strcmp(words[0], "readb") == 0 ||
334 strcmp(words[0], "readw") == 0 ||
335 strcmp(words[0], "readl") == 0 ||
336 strcmp(words[0], "readq") == 0) {
337 uint64_t addr;
338 uint64_t value = UINT64_C(-1);
339
340 g_assert(words[1]);
341 addr = strtoull(words[1], NULL, 0);
342
343 if (words[0][4] == 'b') {
344 uint8_t data;
345 cpu_physical_memory_read(addr, &data, 1);
346 value = data;
347 } else if (words[0][4] == 'w') {
348 uint16_t data;
349 cpu_physical_memory_read(addr, &data, 2);
350 value = tswap16(data);
351 } else if (words[0][4] == 'l') {
352 uint32_t data;
353 cpu_physical_memory_read(addr, &data, 4);
354 value = tswap32(data);
355 } else if (words[0][4] == 'q') {
356 cpu_physical_memory_read(addr, &value, 8);
357 tswap64s(&value);
358 }
359 qtest_send_prefix(chr);
360 qtest_send(chr, "OK 0x%016" PRIx64 "\n", value);
361 } else if (strcmp(words[0], "read") == 0) {
362 uint64_t addr, len, i;
363 uint8_t *data;
364
365 g_assert(words[1] && words[2]);
366 addr = strtoull(words[1], NULL, 0);
367 len = strtoull(words[2], NULL, 0);
368
369 data = g_malloc(len);
370 cpu_physical_memory_read(addr, data, len);
371
372 qtest_send_prefix(chr);
373 qtest_send(chr, "OK 0x");
374 for (i = 0; i < len; i++) {
375 qtest_send(chr, "%02x", data[i]);
376 }
377 qtest_send(chr, "\n");
378
379 g_free(data);
380 } else if (strcmp(words[0], "write") == 0) {
381 uint64_t addr, len, i;
382 uint8_t *data;
383 size_t data_len;
384
385 g_assert(words[1] && words[2] && words[3]);
386 addr = strtoull(words[1], NULL, 0);
387 len = strtoull(words[2], NULL, 0);
388
389 data_len = strlen(words[3]);
390 if (data_len < 3) {
391 qtest_send(chr, "ERR invalid argument size\n");
392 return;
393 }
394
395 data = g_malloc(len);
396 for (i = 0; i < len; i++) {
397 if ((i * 2 + 4) <= data_len) {
398 data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
399 data[i] |= hex2nib(words[3][i * 2 + 3]);
400 } else {
401 data[i] = 0;
402 }
403 }
404 cpu_physical_memory_write(addr, data, len);
405 g_free(data);
406
407 qtest_send_prefix(chr);
408 qtest_send(chr, "OK\n");
409 } else if (strcmp(words[0], "clock_step") == 0) {
410 int64_t ns;
411
412 if (words[1]) {
413 ns = strtoll(words[1], NULL, 0);
414 } else {
415 ns = qemu_clock_deadline(vm_clock);
416 }
417 qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
418 qtest_send_prefix(chr);
419 qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
420 } else if (strcmp(words[0], "clock_set") == 0) {
421 int64_t ns;
422
423 g_assert(words[1]);
424 ns = strtoll(words[1], NULL, 0);
425 qtest_clock_warp(ns);
426 qtest_send_prefix(chr);
427 qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
428 } else {
429 qtest_send_prefix(chr);
430 qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
431 }
432}
433
434static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
435{
436 char *end;
437
438 while ((end = strchr(inbuf->str, '\n')) != NULL) {
439 size_t offset;
440 GString *cmd;
441 gchar **words;
442
443 offset = end - inbuf->str;
444
445 cmd = g_string_new_len(inbuf->str, offset);
446 g_string_erase(inbuf, 0, offset + 1);
447
448 words = g_strsplit(cmd->str, " ", 0);
449 qtest_process_command(chr, words);
450 g_strfreev(words);
451
452 g_string_free(cmd, TRUE);
453 }
454}
455
456static void qtest_read(void *opaque, const uint8_t *buf, int size)
457{
458 CharDriverState *chr = opaque;
459
460 g_string_append_len(inbuf, (const gchar *)buf, size);
461 qtest_process_inbuf(chr, inbuf);
462}
463
464static int qtest_can_read(void *opaque)
465{
466 return 1024;
467}
468
469static void qtest_event(void *opaque, int event)
470{
471 int i;
472
473 switch (event) {
474 case CHR_EVENT_OPENED:
475 qemu_system_reset(false);
476 for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
477 irq_levels[i] = 0;
478 }
479 qemu_gettimeofday(&start_time);
480 qtest_opened = true;
481 if (qtest_log_fp) {
482 fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
483 start_time.tv_sec, (long) start_time.tv_usec);
484 }
485 break;
486 case CHR_EVENT_CLOSED:
487 qtest_opened = false;
488 if (qtest_log_fp) {
489 qemu_timeval tv;
490 qtest_get_time(&tv);
491 fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
492 tv.tv_sec, (long) tv.tv_usec);
493 }
494 break;
495 default:
496 break;
497 }
498}
499
500int qtest_init(void)
501{
502 CharDriverState *chr;
503
504 g_assert(qtest_chrdev != NULL);
505
506 configure_icount("0");
507 chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
508
509 qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
510 qemu_chr_fe_set_echo(chr, true);
511
512 inbuf = g_string_new("");
513
514 if (qtest_log) {
515 if (strcmp(qtest_log, "none") != 0) {
516 qtest_log_fp = fopen(qtest_log, "w+");
517 }
518 } else {
519 qtest_log_fp = stderr;
520 }
521
522 qtest_chr = chr;
523
524 return 0;
525}
526