[PATCH 6/9] Introduce virtio-testdev

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



virtio-testdev is a communication channel to qemu through virtio that
can be used by test code to send commands. The only command currently
implemented is EXIT, which allows the test code to exit with a given
status code.

Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx>
---
 lib/bswap.h          |   7 +++
 lib/libcflat.h       |  10 ++++
 lib/virtio-testdev.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/virtio-testdev.h |   9 ++++
 4 files changed, 152 insertions(+)
 create mode 100644 lib/bswap.h
 create mode 100644 lib/virtio-testdev.c
 create mode 100644 lib/virtio-testdev.h

diff --git a/lib/bswap.h b/lib/bswap.h
new file mode 100644
index 0000000000000..e63c4d37a8b9a
--- /dev/null
+++ b/lib/bswap.h
@@ -0,0 +1,7 @@
+#ifndef _BSWAP_H_
+#define _BSWAP_H_
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#endif
diff --git a/lib/libcflat.h b/lib/libcflat.h
index a1be635ab4ee9..41791194657d0 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -37,6 +37,16 @@ typedef _Bool bool;
 #define true 1
 #define false 0
 
+typedef u32 compat_ptr_t;
+static inline void *compat_ptr(compat_ptr_t ptr)
+{
+    return (void *)(unsigned long)ptr;
+}
+static inline compat_ptr_t ptr_to_compat(void *ptr)
+{
+    return (u32)(unsigned long)ptr;
+}
+
 extern void halt(int code);
 extern void exit(int code);
 
diff --git a/lib/virtio-testdev.c b/lib/virtio-testdev.c
new file mode 100644
index 0000000000000..900921302c344
--- /dev/null
+++ b/lib/virtio-testdev.c
@@ -0,0 +1,126 @@
+#include "libcflat.h"
+#include "iomaps.h"
+#include "bswap.h"
+
+#define TESTDEV_MAJOR_VER 1
+#define TESTDEV_MINOR_VER 1
+
+#define VIRTIO_MMIO_DEVICEID 0x8
+#define VIRTIO_ID_TESTDEV 0xffff
+#define DEV_CONFIG_BASE 0x100
+#define DEV_CONFIG_SIZE 0x100
+
+enum { VERSION = 1, CLEAR, EXIT, };
+enum { TOKEN, NARGS, NRETS, ARG1, ARG2, ARG3, ARG4, };
+
+#define RET1(nargs) (ARG1 + (nargs) + 0)
+#define RET2(nargs) (ARG1 + (nargs) + 1)
+#define RET3(nargs) (ARG1 + (nargs) + 2)
+#define RET4(nargs) (ARG1 + (nargs) + 3)
+
+static u32 *testdev_base;
+
+/*
+ * We have to write all args; nargs, nrets, ... first to
+ * avoid executing token's operation until all args are in
+ * place. Then issue the op, and then read the rets. Reading
+ * the rets (or just sanity checking by reading base[0]) will
+ * read a zero into qemu's copy of the token, which allows us
+ * to prepare additional ops without re-executing the last one.
+ */
+void virtio_testdev(u32 token, u32 nargs, u32 nrets, ...)
+{
+    volatile u32 *base = testdev_base;
+    volatile u32 *tdp = base + 1;
+    va_list va;
+
+    if (!testdev_base)
+	return;
+
+    *tdp++ = cpu_to_le32(nargs);
+    *tdp++ = cpu_to_le32(nrets);
+
+    va_start(va, nrets);
+
+    while (nargs--)
+	*tdp++ = cpu_to_le32(va_arg(va, unsigned));
+
+    /* this runs the op, but then resets base[0] to zero */
+    base[0] = cpu_to_le32(token);
+
+    /* sanity check */
+    if (base[0] != 0) {
+	printf("virtio-testdev base[0] should always be zero!\n");
+	halt(EIO);
+    }
+
+    while (nrets--) {
+	u32 *r = va_arg(va, unsigned *);
+	*r = le32_to_cpu(*tdp++);
+    }
+
+    va_end(va);
+}
+
+void virtio_testdev_version(u32 *version)
+{
+    virtio_testdev(VERSION, 0, 1, version);
+}
+
+void virtio_testdev_clear(void)
+{
+    virtio_testdev(CLEAR, 0, 0);
+}
+
+void virtio_testdev_exit(int code)
+{
+    virtio_testdev(EXIT, 1, 0, code);
+}
+
+void virtio_testdev_init(void)
+{
+    struct iomap *m;
+    u32 version, i;
+    u16 major, minor;
+
+    m = iomaps_find("virtio_mmio");
+    if (!m) {
+	printf("No virtio-mmio transports for virtio-testdev found!\n");
+	halt(ENODEV);
+    }
+
+    for (i = 0; i < m->nr; ++i) {
+	volatile u32 *base = (u32 *)compat_ptr(m->addrs[i]);
+	u32 devid32 = base[VIRTIO_MMIO_DEVICEID / 4];
+	u16 devid = devid32 & 0xffff;
+	devid = le16_to_cpu(devid);
+	if (devid == VIRTIO_ID_TESTDEV) {
+	    testdev_base = (u32 *)compat_ptr(m->addrs[i] + DEV_CONFIG_BASE);
+	    break;
+	}
+    }
+
+    if (!testdev_base) {
+	printf("Can't find virtio-testdev. Is '-device virtio-testdev' "
+	       "on the qemu command line?\n");
+	halt(ENODEV);
+    }
+
+    virtio_testdev_version(&version);
+    major = version >> 16;
+    minor = version & 0xffff;
+
+    if (major != TESTDEV_MAJOR_VER || minor < TESTDEV_MINOR_VER) {
+	char *u = "qemu";
+	if (major > TESTDEV_MAJOR_VER)
+	    u = "kvm-unit-tests";
+	printf("Refusing to run with virtio-testdev major = %d, minor = %d\n",
+			major, minor);
+	printf("Update %s.\n", u);
+	exit(ENODEV);
+    }
+
+    if (minor > TESTDEV_MINOR_VER)
+	printf("testdev has new features. "
+	       "An update of kvm-unit-tests may be possible.\n");
+}
diff --git a/lib/virtio-testdev.h b/lib/virtio-testdev.h
new file mode 100644
index 0000000000000..c10bbfb591d0b
--- /dev/null
+++ b/lib/virtio-testdev.h
@@ -0,0 +1,9 @@
+#ifndef _VIRTIO_TESTDEV_H_
+#define _VIRTIO_TESTDEV_H_
+#include "libcflat.h"
+
+extern void virtio_testdev_init(void);
+extern void virtio_testdev_version(u32 *version);
+extern void virtio_testdev_clear(void);
+extern void virtio_testdev_exit(int code);
+#endif
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux