/*- * Copyright (c) 2023 John Baldwin * * SPDX-License-Identifier: BSD-2-Clause */ /* * Fetch the value of fwctl nodes from a guest. * * Usage: fwctl_fetch */ #include #include #include #include #include #include #include #include #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); }