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