]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/bhyve/fwctl_fetch.c
zfs: merge openzfs/zfs@0ee9b0239
[FreeBSD/FreeBSD.git] / tools / tools / bhyve / fwctl_fetch.c
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 }