xref: /freebsd/tools/tools/bhyve/fwctl_fetch.c (revision 61e21613)
1 /*-
2  * Copyright (c) 2023 John Baldwin <jhb@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 /*
8  * Fetch the value of fwctl nodes from a guest.
9  *
10  * Usage: fwctl_fetch <node>
11  */
12 
13 #include <sys/param.h>
14 #include <err.h>
15 #include <fcntl.h>
16 #include <libutil.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <machine/cpufunc.h>
21 
22 #define	OP_GET		3
23 #define	OP_GET_LEN	4
24 
25 /* I/O ports */
26 #define	FWCTL_OUT	0x510
27 #define	FWCTL_IN	0x511
28 
29 static void
30 reset_fwctl(void)
31 {
32 	char buf[4];
33 
34 	outw(FWCTL_OUT, 0);
35 	for (u_int i = 0; i < 4; i++)
36 		buf[i] = inb(FWCTL_IN);
37 	if (memcmp(buf, "BHYV", 4) != 0)
38 		errx(1, "Signature mismatch: %.4s", buf);
39 }
40 
41 static void
42 send_node_name(const char *name)
43 {
44 	uint32_t value;
45 	size_t len;
46 
47 	len = strlen(name) + 1;
48 	while (len > 4) {
49 		memcpy(&value, name, 4);
50 		outl(FWCTL_OUT, value);
51 		name += 4;
52 		len -= 4;
53 	}
54 
55 	if (len > 0) {
56 		value = 0;
57 		memcpy(&value, name, len);
58 		outl(FWCTL_OUT, value);
59 	}
60 }
61 
62 static void
63 fwctl_op(uint32_t op, uint32_t id, const char *name, void *buf, size_t len)
64 {
65 	char *cp;
66 	uint32_t value, rsplen;
67 
68 	/* Length */
69 	outl(FWCTL_OUT, 12 + strlen(name) + 1);
70 
71 	/* Operation */
72 	outl(FWCTL_OUT, op);
73 
74 	/* Transaction ID */
75 	outl(FWCTL_OUT, id);
76 
77 	send_node_name(name);
78 
79 	/* Length */
80 	rsplen = inl(FWCTL_IN);
81 
82 	/* If there is an error, the response will have no payload. */
83 	if (rsplen < 4 * sizeof(value))
84 		errx(1, "Invalid response length (%u): %u", id, rsplen);
85 
86 	/* Operation */
87 	value = inl(FWCTL_IN);
88 	if (value != op)
89 		errx(1, "Invalid response type (%u): %u", id, value);
90 
91 	/* Transaction ID */
92 	value = inl(FWCTL_IN);
93 	if (value != id)
94 		errx(1, "Invalid response ID (%u): %u", id, value);
95 
96 	/* Error */
97 	value = inl(FWCTL_IN);
98 	if (value != 0)
99 		errx(1, "Error from op %u (%u): %u", op, id, value);
100 
101 	/* If there wasn't an error, require payload length to match */
102 	if (rsplen != 4 * sizeof(value) + len)
103 		errx(1, "Response payload length mismatch (%u): %zu vs %zu", id,
104 		    rsplen - 4 * sizeof(value), len);
105 
106 	cp = buf;
107 	while (len > 0) {
108 		value = inl(FWCTL_IN);
109 		memcpy(cp, &value, 4);
110 		cp += 4;
111 		len -= 4;
112 	}
113 }
114 
115 int
116 main(int ac, char **av)
117 {
118 	char *p;
119 	size_t len, buflen, len2;
120 
121 	if (ac != 2)
122 		errx(1, "Need node name");
123 
124 	if (open("/dev/io", O_RDWR) == -1)
125 		err(1, "Failed to open /dev/io");
126 
127 	reset_fwctl();
128 
129 	fwctl_op(OP_GET_LEN, 1, av[1], &len, sizeof(len));
130 	if (len == 0)
131 		errx(1, "Node has length of 0");
132 
133 	/* Buffer includes embedded length followed by value. */
134 	buflen = sizeof(size_t) + roundup2(len, 4);
135 	p = malloc(buflen);
136 	fwctl_op(OP_GET, 2, av[1], p, buflen);
137 	memcpy(&len2, p, sizeof(len2));
138 	if (len2 != len)
139 		errx(1, "Length mismatch: %zu vs %zu", len, len2);
140 	hexdump(p + sizeof(len2), len, NULL, 0);
141 
142 	return (0);
143 }
144