]>
git.proxmox.com Git - qemu.git/blob - qtest.c
a1eca4988826edd117a059473cb23f00057c87d5
4 * Copyright IBM, Corp. 2011
7 * Anthony Liguori <aliguori@us.ibm.com>
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.
16 #include "qemu-char.h"
24 const char *qtest_chrdev
;
25 const char *qtest_log
;
26 int qtest_allowed
= 0;
28 static DeviceState
*irq_intercept_dev
;
29 static FILE *qtest_log_fp
;
30 static CharDriverState
*qtest_chr
;
31 static GString
*inbuf
;
32 static int irq_levels
[MAX_IRQ
];
33 static struct timeval start_time
;
34 static bool qtest_opened
;
36 #define FMT_timeval "%" PRId64 ".%06" PRId64
41 * Line based protocol, request/response based. Server can send async messages
42 * so clients should always handle many async messages before the response
68 * > write ADDR SIZE DATA
71 * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
73 * DATA is an arbitrarily long hex number prefixed with '0x'. If it's smaller
74 * than the expected size, the value will be zero filled at the end of the data
79 * > irq_intercept_in QOM-PATH
82 * > irq_intercept_out QOM-PATH
85 * Attach to the gpio-in (resp. gpio-out) pins exported by the device at
86 * QOM-PATH. When the pin is triggered, one of the following async messages
87 * will be printed to the qtest stream:
92 * where NUM is an IRQ number. For the PC, interrupts can be intercepted
93 * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
94 * NUM=0 even though it is remapped to GSI 2).
97 static int hex2nib(char ch
)
99 if (ch
>= '0' && ch
<= '9') {
101 } else if (ch
>= 'a' && ch
<= 'f') {
102 return 10 + (ch
- 'a');
103 } else if (ch
>= 'A' && ch
<= 'F') {
104 return 10 + (ch
- 'a');
110 static void qtest_get_time(struct timeval
*tv
)
112 gettimeofday(tv
, NULL
);
113 tv
->tv_sec
-= start_time
.tv_sec
;
114 tv
->tv_usec
-= start_time
.tv_usec
;
115 if (tv
->tv_usec
< 0) {
116 tv
->tv_usec
+= 1000000;
121 static void qtest_send_prefix(CharDriverState
*chr
)
125 if (!qtest_log_fp
|| !qtest_opened
) {
130 fprintf(qtest_log_fp
, "[S +" FMT_timeval
"] ",
131 tv
.tv_sec
, tv
.tv_usec
);
134 static void qtest_send(CharDriverState
*chr
, const char *fmt
, ...)
141 len
= vsnprintf(buffer
, sizeof(buffer
), fmt
, ap
);
144 qemu_chr_fe_write(chr
, (uint8_t *)buffer
, len
);
145 if (qtest_log_fp
&& qtest_opened
) {
146 fprintf(qtest_log_fp
, "%s", buffer
);
150 static void qtest_irq_handler(void *opaque
, int n
, int level
)
152 qemu_irq
*old_irqs
= opaque
;
153 qemu_set_irq(old_irqs
[n
], level
);
155 if (irq_levels
[n
] != level
) {
156 CharDriverState
*chr
= qtest_chr
;
157 irq_levels
[n
] = level
;
158 qtest_send_prefix(chr
);
159 qtest_send(chr
, "IRQ %s %d\n",
160 level
? "raise" : "lower", n
);
164 static void qtest_process_command(CharDriverState
*chr
, gchar
**words
)
166 const gchar
*command
;
177 fprintf(qtest_log_fp
, "[R +" FMT_timeval
"]",
178 tv
.tv_sec
, tv
.tv_usec
);
179 for (i
= 0; words
[i
]; i
++) {
180 fprintf(qtest_log_fp
, " %s", words
[i
]);
182 fprintf(qtest_log_fp
, "\n");
186 if (strcmp(words
[0], "irq_intercept_out") == 0
187 || strcmp(words
[0], "irq_intercept_in") == 0) {
191 dev
= DEVICE(object_resolve_path(words
[1], NULL
));
193 qtest_send_prefix(chr
);
194 qtest_send(chr
, "FAIL Unknown device\n");
198 if (irq_intercept_dev
) {
199 qtest_send_prefix(chr
);
200 if (irq_intercept_dev
!= dev
) {
201 qtest_send(chr
, "FAIL IRQ intercept already enabled\n");
203 qtest_send(chr
, "OK\n");
208 if (words
[0][14] == 'o') {
209 qemu_irq_intercept_out(&dev
->gpio_out
, qtest_irq_handler
, dev
->num_gpio_out
);
211 qemu_irq_intercept_in(dev
->gpio_in
, qtest_irq_handler
, dev
->num_gpio_in
);
213 irq_intercept_dev
= dev
;
214 qtest_send_prefix(chr
);
215 qtest_send(chr
, "OK\n");
217 } else if (strcmp(words
[0], "outb") == 0 ||
218 strcmp(words
[0], "outw") == 0 ||
219 strcmp(words
[0], "outl") == 0) {
223 g_assert(words
[1] && words
[2]);
224 addr
= strtol(words
[1], NULL
, 0);
225 value
= strtol(words
[2], NULL
, 0);
227 if (words
[0][3] == 'b') {
228 cpu_outb(addr
, value
);
229 } else if (words
[0][3] == 'w') {
230 cpu_outw(addr
, value
);
231 } else if (words
[0][3] == 'l') {
232 cpu_outl(addr
, value
);
234 qtest_send_prefix(chr
);
235 qtest_send(chr
, "OK\n");
236 } else if (strcmp(words
[0], "inb") == 0 ||
237 strcmp(words
[0], "inw") == 0 ||
238 strcmp(words
[0], "inl") == 0) {
240 uint32_t value
= -1U;
243 addr
= strtol(words
[1], NULL
, 0);
245 if (words
[0][2] == 'b') {
246 value
= cpu_inb(addr
);
247 } else if (words
[0][2] == 'w') {
248 value
= cpu_inw(addr
);
249 } else if (words
[0][2] == 'l') {
250 value
= cpu_inl(addr
);
252 qtest_send_prefix(chr
);
253 qtest_send(chr
, "OK 0x%04x\n", value
);
254 } else if (strcmp(words
[0], "read") == 0) {
255 uint64_t addr
, len
, i
;
258 g_assert(words
[1] && words
[2]);
259 addr
= strtoul(words
[1], NULL
, 0);
260 len
= strtoul(words
[2], NULL
, 0);
262 data
= g_malloc(len
);
263 cpu_physical_memory_read(addr
, data
, len
);
265 qtest_send_prefix(chr
);
266 qtest_send(chr
, "OK 0x");
267 for (i
= 0; i
< len
; i
++) {
268 qtest_send(chr
, "%02x", data
[i
]);
270 qtest_send(chr
, "\n");
273 } else if (strcmp(words
[0], "write") == 0) {
274 uint64_t addr
, len
, i
;
278 g_assert(words
[1] && words
[2] && words
[3]);
279 addr
= strtoul(words
[1], NULL
, 0);
280 len
= strtoul(words
[2], NULL
, 0);
282 data_len
= strlen(words
[3]);
284 qtest_send(chr
, "ERR invalid argument size\n");
288 data
= g_malloc(len
);
289 for (i
= 0; i
< len
; i
++) {
290 if ((i
* 2 + 4) <= data_len
) {
291 data
[i
] = hex2nib(words
[3][i
* 2 + 2]) << 4;
292 data
[i
] |= hex2nib(words
[3][i
* 2 + 3]);
297 cpu_physical_memory_write(addr
, data
, len
);
300 qtest_send_prefix(chr
);
301 qtest_send(chr
, "OK\n");
303 qtest_send_prefix(chr
);
304 qtest_send(chr
, "FAIL Unknown command `%s'\n", words
[0]);
308 static void qtest_process_inbuf(CharDriverState
*chr
, GString
*inbuf
)
312 while ((end
= strchr(inbuf
->str
, '\n')) != NULL
) {
317 offset
= end
- inbuf
->str
;
319 cmd
= g_string_new_len(inbuf
->str
, offset
);
320 g_string_erase(inbuf
, 0, offset
+ 1);
322 words
= g_strsplit(cmd
->str
, " ", 0);
323 qtest_process_command(chr
, words
);
326 g_string_free(cmd
, TRUE
);
330 static void qtest_read(void *opaque
, const uint8_t *buf
, int size
)
332 CharDriverState
*chr
= opaque
;
334 g_string_append_len(inbuf
, (const gchar
*)buf
, size
);
335 qtest_process_inbuf(chr
, inbuf
);
338 static int qtest_can_read(void *opaque
)
343 static void qtest_event(void *opaque
, int event
)
348 case CHR_EVENT_OPENED
:
349 qemu_system_reset(false);
350 for (i
= 0; i
< ARRAY_SIZE(irq_levels
); i
++) {
353 gettimeofday(&start_time
, NULL
);
356 fprintf(qtest_log_fp
, "[I " FMT_timeval
"] OPENED\n",
357 start_time
.tv_sec
, start_time
.tv_usec
);
360 case CHR_EVENT_CLOSED
:
361 qtest_opened
= false;
365 fprintf(qtest_log_fp
, "[I +" FMT_timeval
"] CLOSED\n",
366 tv
.tv_sec
, tv
.tv_usec
);
376 CharDriverState
*chr
;
378 g_assert(qtest_chrdev
!= NULL
);
380 chr
= qemu_chr_new("qtest", qtest_chrdev
, NULL
);
382 qemu_chr_add_handlers(chr
, qtest_can_read
, qtest_read
, qtest_event
, chr
);
383 qemu_chr_fe_set_echo(chr
, true);
385 inbuf
= g_string_new("");
388 if (strcmp(qtest_log
, "none") != 0) {
389 qtest_log_fp
= fopen(qtest_log
, "w+");
392 qtest_log_fp
= stderr
;