in softmmu/qtest.c [379:796]
static void qtest_process_command(CharBackend *chr, gchar **words)
{
const gchar *command;
g_assert(words);
command = words[0];
if (qtest_log_fp) {
qemu_timeval tv;
int i;
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
(long) tv.tv_sec, (long) tv.tv_usec);
for (i = 0; words[i]; i++) {
fprintf(qtest_log_fp, " %s", words[i]);
}
fprintf(qtest_log_fp, "\n");
}
g_assert(command);
if (strcmp(words[0], "irq_intercept_out") == 0
|| strcmp(words[0], "irq_intercept_in") == 0) {
DeviceState *dev;
NamedGPIOList *ngl;
g_assert(words[1]);
dev = DEVICE(object_resolve_path(words[1], NULL));
if (!dev) {
qtest_send_prefix(chr);
qtest_send(chr, "FAIL Unknown device\n");
return;
}
if (irq_intercept_dev) {
qtest_send_prefix(chr);
if (irq_intercept_dev != dev) {
qtest_send(chr, "FAIL IRQ intercept already enabled\n");
} else {
qtest_send(chr, "OK\n");
}
return;
}
QLIST_FOREACH(ngl, &dev->gpios, node) {
/* We don't support intercept of named GPIOs yet */
if (ngl->name) {
continue;
}
if (words[0][14] == 'o') {
int i;
for (i = 0; i < ngl->num_out; ++i) {
qemu_irq *disconnected = g_new0(qemu_irq, 1);
qemu_irq icpt = qemu_allocate_irq(qtest_irq_handler,
disconnected, i);
*disconnected = qdev_intercept_gpio_out(dev, icpt,
ngl->name, i);
}
} else {
qemu_irq_intercept_in(ngl->in, qtest_irq_handler,
ngl->num_in);
}
}
irq_intercept_dev = dev;
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "set_irq_in") == 0) {
DeviceState *dev;
qemu_irq irq;
char *name;
int ret;
int num;
int level;
g_assert(words[1] && words[2] && words[3] && words[4]);
dev = DEVICE(object_resolve_path(words[1], NULL));
if (!dev) {
qtest_send_prefix(chr);
qtest_send(chr, "FAIL Unknown device\n");
return;
}
if (strcmp(words[2], "unnamed-gpio-in") == 0) {
name = NULL;
} else {
name = words[2];
}
ret = qemu_strtoi(words[3], NULL, 0, &num);
g_assert(!ret);
ret = qemu_strtoi(words[4], NULL, 0, &level);
g_assert(!ret);
irq = qdev_get_gpio_in_named(dev, name, num);
qemu_set_irq(irq, level);
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "outb") == 0 ||
strcmp(words[0], "outw") == 0 ||
strcmp(words[0], "outl") == 0) {
unsigned long addr;
unsigned long value;
int ret;
g_assert(words[1] && words[2]);
ret = qemu_strtoul(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtoul(words[2], NULL, 0, &value);
g_assert(ret == 0);
g_assert(addr <= 0xffff);
if (words[0][3] == 'b') {
cpu_outb(addr, value);
} else if (words[0][3] == 'w') {
cpu_outw(addr, value);
} else if (words[0][3] == 'l') {
cpu_outl(addr, value);
}
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "inb") == 0 ||
strcmp(words[0], "inw") == 0 ||
strcmp(words[0], "inl") == 0) {
unsigned long addr;
uint32_t value = -1U;
int ret;
g_assert(words[1]);
ret = qemu_strtoul(words[1], NULL, 0, &addr);
g_assert(ret == 0);
g_assert(addr <= 0xffff);
if (words[0][2] == 'b') {
value = cpu_inb(addr);
} else if (words[0][2] == 'w') {
value = cpu_inw(addr);
} else if (words[0][2] == 'l') {
value = cpu_inl(addr);
}
qtest_send_prefix(chr);
qtest_sendf(chr, "OK 0x%04x\n", value);
} else if (strcmp(words[0], "writeb") == 0 ||
strcmp(words[0], "writew") == 0 ||
strcmp(words[0], "writel") == 0 ||
strcmp(words[0], "writeq") == 0) {
uint64_t addr;
uint64_t value;
int ret;
g_assert(words[1] && words[2]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtou64(words[2], NULL, 0, &value);
g_assert(ret == 0);
if (words[0][5] == 'b') {
uint8_t data = value;
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 1);
} else if (words[0][5] == 'w') {
uint16_t data = value;
tswap16s(&data);
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 2);
} else if (words[0][5] == 'l') {
uint32_t data = value;
tswap32s(&data);
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 4);
} else if (words[0][5] == 'q') {
uint64_t data = value;
tswap64s(&data);
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 8);
}
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "readb") == 0 ||
strcmp(words[0], "readw") == 0 ||
strcmp(words[0], "readl") == 0 ||
strcmp(words[0], "readq") == 0) {
uint64_t addr;
uint64_t value = UINT64_C(-1);
int ret;
g_assert(words[1]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
if (words[0][4] == 'b') {
uint8_t data;
address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 1);
value = data;
} else if (words[0][4] == 'w') {
uint16_t data;
address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 2);
value = tswap16(data);
} else if (words[0][4] == 'l') {
uint32_t data;
address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&data, 4);
value = tswap32(data);
} else if (words[0][4] == 'q') {
address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
&value, 8);
tswap64s(&value);
}
qtest_send_prefix(chr);
qtest_sendf(chr, "OK 0x%016" PRIx64 "\n", value);
} else if (strcmp(words[0], "read") == 0) {
uint64_t addr, len, i;
uint8_t *data;
char *enc;
int ret;
g_assert(words[1] && words[2]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtou64(words[2], NULL, 0, &len);
g_assert(ret == 0);
/* We'd send garbage to libqtest if len is 0 */
g_assert(len);
data = g_malloc(len);
address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,
len);
enc = g_malloc(2 * len + 1);
for (i = 0; i < len; i++) {
sprintf(&enc[i * 2], "%02x", data[i]);
}
qtest_send_prefix(chr);
qtest_sendf(chr, "OK 0x%s\n", enc);
g_free(data);
g_free(enc);
} else if (strcmp(words[0], "b64read") == 0) {
uint64_t addr, len;
uint8_t *data;
gchar *b64_data;
int ret;
g_assert(words[1] && words[2]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtou64(words[2], NULL, 0, &len);
g_assert(ret == 0);
data = g_malloc(len);
address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,
len);
b64_data = g_base64_encode(data, len);
qtest_send_prefix(chr);
qtest_sendf(chr, "OK %s\n", b64_data);
g_free(data);
g_free(b64_data);
} else if (strcmp(words[0], "write") == 0) {
uint64_t addr, len, i;
uint8_t *data;
size_t data_len;
int ret;
g_assert(words[1] && words[2] && words[3]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtou64(words[2], NULL, 0, &len);
g_assert(ret == 0);
data_len = strlen(words[3]);
if (data_len < 3) {
qtest_send(chr, "ERR invalid argument size\n");
return;
}
data = g_malloc(len);
for (i = 0; i < len; i++) {
if ((i * 2 + 4) <= data_len) {
data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
data[i] |= hex2nib(words[3][i * 2 + 3]);
} else {
data[i] = 0;
}
}
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,
len);
g_free(data);
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "memset") == 0) {
uint64_t addr, len;
uint8_t *data;
unsigned long pattern;
int ret;
g_assert(words[1] && words[2] && words[3]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtou64(words[2], NULL, 0, &len);
g_assert(ret == 0);
ret = qemu_strtoul(words[3], NULL, 0, &pattern);
g_assert(ret == 0);
if (len) {
data = g_malloc(len);
memset(data, pattern, len);
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,
data, len);
g_free(data);
}
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "b64write") == 0) {
uint64_t addr, len;
uint8_t *data;
size_t data_len;
gsize out_len;
int ret;
g_assert(words[1] && words[2] && words[3]);
ret = qemu_strtou64(words[1], NULL, 0, &addr);
g_assert(ret == 0);
ret = qemu_strtou64(words[2], NULL, 0, &len);
g_assert(ret == 0);
data_len = strlen(words[3]);
if (data_len < 3) {
qtest_send(chr, "ERR invalid argument size\n");
return;
}
data = g_base64_decode_inplace(words[3], &out_len);
if (out_len != len) {
qtest_log_send("b64write: data length mismatch (told %"PRIu64", "
"found %zu)\n",
len, out_len);
out_len = MIN(out_len, len);
}
address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,
len);
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "endianness") == 0) {
qtest_send_prefix(chr);
#if defined(TARGET_WORDS_BIGENDIAN)
qtest_sendf(chr, "OK big\n");
#else
qtest_sendf(chr, "OK little\n");
#endif
#ifdef CONFIG_PSERIES
} else if (strcmp(words[0], "rtas") == 0) {
uint64_t res, args, ret;
unsigned long nargs, nret;
int rc;
rc = qemu_strtoul(words[2], NULL, 0, &nargs);
g_assert(rc == 0);
rc = qemu_strtou64(words[3], NULL, 0, &args);
g_assert(rc == 0);
rc = qemu_strtoul(words[4], NULL, 0, &nret);
g_assert(rc == 0);
rc = qemu_strtou64(words[5], NULL, 0, &ret);
g_assert(rc == 0);
res = qtest_rtas_call(words[1], nargs, args, nret, ret);
qtest_send_prefix(chr);
qtest_sendf(chr, "OK %"PRIu64"\n", res);
#endif
} else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
int64_t ns;
if (words[1]) {
int ret = qemu_strtoi64(words[1], NULL, 0, &ns);
g_assert(ret == 0);
} else {
ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
QEMU_TIMER_ATTR_ALL);
}
qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns);
qtest_send_prefix(chr);
qtest_sendf(chr, "OK %"PRIi64"\n",
(int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
} else if (strcmp(words[0], "module_load") == 0) {
g_assert(words[1] && words[2]);
qtest_send_prefix(chr);
if (module_load_one(words[1], words[2], false)) {
qtest_sendf(chr, "OK\n");
} else {
qtest_sendf(chr, "FAIL\n");
}
} else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
int64_t ns;
int ret;
g_assert(words[1]);
ret = qemu_strtoi64(words[1], NULL, 0, &ns);
g_assert(ret == 0);
qtest_clock_warp(ns);
qtest_send_prefix(chr);
qtest_sendf(chr, "OK %"PRIi64"\n",
(int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
} else {
qtest_send_prefix(chr);
qtest_sendf(chr, "FAIL Unknown command '%s'\n", words[0]);
}
}