mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-23 19:28:36 +00:00
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
This commit is contained in:
parent
9ac841e922
commit
d8bfccb220
8
tools/tools/bhyve/Makefile
Normal file
8
tools/tools/bhyve/Makefile
Normal file
|
@ -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>
|
137
tools/tools/bhyve/fwctl_fetch.c
Normal file
137
tools/tools/bhyve/fwctl_fetch.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue