diff mbox

[v4,12/19] Introduce virtio-testdev

Message ID 1397149020-3501-13-git-send-email-drjones@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Jones April 10, 2014, 4:56 p.m. UTC
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@redhat.com>
---
v4: couple tweaks (added spinlock), no functional changes
---
 lib/virtio-testdev.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/virtio-testdev.h |  18 +++++++
 2 files changed, 155 insertions(+)
 create mode 100644 lib/virtio-testdev.c
 create mode 100644 lib/virtio-testdev.h

Comments

Christoffer Dall June 6, 2014, 6:39 p.m. UTC | #1
On Thu, Apr 10, 2014 at 06:56:53PM +0200, Andrew Jones wrote:
> 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@redhat.com>

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/lib/virtio-testdev.c b/lib/virtio-testdev.c
new file mode 100644
index 0000000000000..3ece6ae58fdc5
--- /dev/null
+++ b/lib/virtio-testdev.c
@@ -0,0 +1,137 @@ 
+/*
+ * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include "libcflat.h"
+#include "asm/spinlock.h"
+#include "virtio.h"
+
+#define TESTDEV_NAME		"virtio-testdev"
+#define VIRTIO_ID_TESTDEV	0xffff
+#define TESTDEV_MAJOR_VER	1
+#define TESTDEV_MINOR_VER	1
+
+#define VIRTIO_CONFIG_SIZE	64
+
+enum {
+	VERSION = 1,
+	CLEAR,
+	EXIT,
+};
+
+#define TOKEN_OFFSET		0x0
+#define NARGS_OFFSET		0x4
+#define NRETS_OFFSET		0x8
+#define ARG_OFFSET(n)		(0xc + (n) * 4)
+#define __RET_OFFSET(nargs, n)	(ARG_OFFSET(nargs) + (n) * 4)
+
+static struct spinlock lock;
+static struct virtio_dev *vdev;
+
+static u32 testdev_readl(unsigned offset)
+{
+	assert(offset <= (VIRTIO_CONFIG_SIZE - 4));
+	return virtio_config_readl(vdev, offset);
+}
+
+static void testdev_writel(unsigned offset, u32 val)
+{
+	assert(offset <= (VIRTIO_CONFIG_SIZE - 4));
+	virtio_config_writel(vdev, offset, val);
+}
+
+/*
+ * We have to write all args; nargs, nrets, ... first to avoid executing
+ * the token's operation until all args are in place. Then issue the op,
+ * and then read the return values. Reading the return values (or just
+ * sanity checking by reading token) 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, ...)
+{
+	va_list va;
+	unsigned off;
+	u32 n;
+
+	if (!vdev)
+		return;
+
+	spin_lock(&lock);
+
+	testdev_writel(NARGS_OFFSET, nargs);
+	testdev_writel(NRETS_OFFSET, nrets);
+
+	va_start(va, nrets);
+
+	off = ARG_OFFSET(0);
+	n = nargs;
+	while (n--) {
+		testdev_writel(off, va_arg(va, unsigned));
+		off += 4;
+	}
+
+	/* this runs the op, but then resets token to zero */
+	testdev_writel(TOKEN_OFFSET, token);
+	assert(testdev_readl(TOKEN_OFFSET) == 0);
+
+	off = __RET_OFFSET(nargs, 0);
+	n = nrets;
+	while (n--) {
+		u32 *r = va_arg(va, unsigned *);
+		*r = testdev_readl(off);
+		off += 4;
+	}
+
+	spin_unlock(&lock);
+	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)
+{
+	u16 major, minor;
+	u32 version;
+
+	vdev = virtio_bind(VIRTIO_ID_TESTDEV);
+	if (vdev == NULL) {
+		printf("%s: can't find " TESTDEV_NAME ". "
+		       "Is '-device " TESTDEV_NAME "' "
+		       "on the qemu command line?\n", __func__);
+		abort();
+	}
+
+	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("%s: incompatible version of " TESTDEV_NAME ": "
+		       "major = %d, minor = %d. Update %s\n",
+		       __func__, major, minor, u);
+		abort();
+	}
+
+	if (minor > TESTDEV_MINOR_VER)
+		printf("%s: " TESTDEV_NAME " has new features. "
+		       "An update of kvm-unit-tests may be possible.\n",
+		       __func__);
+}
diff --git a/lib/virtio-testdev.h b/lib/virtio-testdev.h
new file mode 100644
index 0000000000000..bed9eaf4aca4b
--- /dev/null
+++ b/lib/virtio-testdev.h
@@ -0,0 +1,18 @@ 
+#ifndef _VIRTIO_TESTDEV_H_
+#define _VIRTIO_TESTDEV_H_
+/*
+ * virtio-testdev is a driver for the virtio-testdev qemu device.
+ * The virtio-testdev device exposes a simple control interface to
+ * qemu for kvm-unit-tests through virtio.
+ *
+ * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#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