git: d8bfccb22093 - main - fwctl_fetch: A small test utility for the fwctl bhyve device.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 07 Jul 2023 20:04:31 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=d8bfccb220939e121b6323700c634a5dff95b4ac
commit d8bfccb220939e121b6323700c634a5dff95b4ac
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2023-07-07 20:02:13 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2023-07-07 20:02:13 +0000
fwctl_fetch: A small test utility for the fwctl bhyve device.
This can be run inside a bhyve guest to query the value of fwctl
nodes. Note that fwctl in bhyve only supports a single hw.ncpu node.
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D40803
---
tools/tools/bhyve/Makefile | 8 +++
tools/tools/bhyve/fwctl_fetch.c | 137 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 145 insertions(+)
diff --git a/tools/tools/bhyve/Makefile b/tools/tools/bhyve/Makefile
new file mode 100644
index 000000000000..3d9ea4167bab
--- /dev/null
+++ b/tools/tools/bhyve/Makefile
@@ -0,0 +1,8 @@
+PROGS= fwctl_fetch
+MAN=
+BINDIR?= /usr/local/bin
+
+# fwctl_fetch: fetch the value of fwctl nodes from a guest
+LIBADD.fwctl_fetch+= util
+
+.include <bsd.progs.mk>
diff --git a/tools/tools/bhyve/fwctl_fetch.c b/tools/tools/bhyve/fwctl_fetch.c
new file mode 100644
index 000000000000..f3139cf4f010
--- /dev/null
+++ b/tools/tools/bhyve/fwctl_fetch.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2023 John Baldwin <jhb@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <err.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <machine/cpufunc.h>
+
+#define OP_GET 3
+#define OP_GET_LEN 4
+
+/* I/O ports */
+#define FWCTL_OUT 0x510
+#define FWCTL_IN 0x511
+
+static void
+reset_fwctl(void)
+{
+ char buf[4];
+
+ outw(FWCTL_OUT, 0);
+ for (u_int i = 0; i < 4; i++)
+ buf[i] = inb(FWCTL_IN);
+ if (memcmp(buf, "BHYV", 4) != 0)
+ errx(1, "Signature mismatch: %.4s", buf);
+}
+
+static void
+send_node_name(const char *name)
+{
+ uint32_t value;
+ size_t len;
+
+ len = strlen(name) + 1;
+ while (len > 4) {
+ memcpy(&value, name, 4);
+ outl(FWCTL_OUT, value);
+ name += 4;
+ len -= 4;
+ }
+
+ if (len > 0) {
+ value = 0;
+ memcpy(&value, name, len);
+ outl(FWCTL_OUT, value);
+ }
+}
+
+static void
+fwctl_op(uint32_t op, uint32_t id, const char *name, void *buf, size_t len)
+{
+ char *cp;
+ uint32_t value, rsplen;
+
+ /* Length */
+ outl(FWCTL_OUT, 12 + strlen(name) + 1);
+
+ /* Operation */
+ outl(FWCTL_OUT, op);
+
+ /* Transaction ID */
+ outl(FWCTL_OUT, id);
+
+ send_node_name(name);
+
+ /* Length */
+ rsplen = inl(FWCTL_IN);
+
+ /* If there is an error, the response will have no payload. */
+ if (rsplen < 4 * sizeof(value))
+ errx(1, "Invalid response length (%u): %u", id, rsplen);
+
+ /* Operation */
+ value = inl(FWCTL_IN);
+ if (value != op)
+ errx(1, "Invalid response type (%u): %u", id, value);
+
+ /* Transaction ID */
+ value = inl(FWCTL_IN);
+ if (value != id)
+ errx(1, "Invalid response ID (%u): %u", id, value);
+
+ /* Error */
+ value = inl(FWCTL_IN);
+ if (value != 0)
+ errx(1, "Error from op %u (%u): %u", op, id, value);
+
+ /* If there wasn't an error, require payload length to match */
+ if (rsplen != 4 * sizeof(value) + len)
+ errx(1, "Response payload length mismatch (%u): %zu vs %zu", id,
+ rsplen - 4 * sizeof(value), len);
+
+ cp = buf;
+ while (len > 0) {
+ value = inl(FWCTL_IN);
+ memcpy(cp, &value, 4);
+ cp += 4;
+ len -= 4;
+ }
+}
+
+int
+main(int ac, char **av)
+{
+ char *p;
+ size_t len, buflen, len2;
+
+ if (ac != 2)
+ errx(1, "Need node name");
+
+ if (open("/dev/io", O_RDWR) == -1)
+ err(1, "Failed to open /dev/io");
+
+ reset_fwctl();
+
+ fwctl_op(OP_GET_LEN, 1, av[1], &len, sizeof(len));
+ if (len == 0)
+ errx(1, "Node has length of 0");
+
+ /* Buffer includes embedded length followed by value. */
+ buflen = sizeof(size_t) + roundup2(len, 4);
+ p = malloc(buflen);
+ fwctl_op(OP_GET, 2, av[1], p, buflen);
+ memcpy(&len2, p, sizeof(len2));
+ if (len2 != len)
+ errx(1, "Length mismatch: %zu vs %zu", len, len2);
+ hexdump(p + sizeof(len2), len, NULL, 0);
+
+ return (0);
+}