From nobody Sat Oct 24 11:44:49 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4jBdNK38YNz6wT7l for ; Sat, 24 Oct 2026 11:44:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jBdNK2sX2z4RHy for ; Sat, 24 Oct 2026 11:44:49 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792842289; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8w2xTNJtXwWZM0BK5Nexr6KDjM2dlWy3sSuyDh2/xbY=; b=wuDCej2Lp2ec2l7SxN5MVk7FdW/aAXQuBhO37IqZXoeDplMM8qt4j2zPHMI3LKwzbwtpZH CDOEyYUz6JFDiZ4MmoESValH4zQUf0erXXy5DqmTFL8O0zXFMiKrany+7A+NCLA9Ts2Z13 xEkgm7+1K542expsRpzGiSsS6UzWwnaGl8MdCUS9LixgEpK0U87fsPXAiQxqhKATaS+Qcv SMqFuynk9RkNLZhM7oKJtw6EDtwlSakfpyw3IYX7hy3zMDT7sLSKkv0Hh9Bh4Fu8mBWFp3 4TMVgmiyCHpHe+byx33KDyjfRsTRgOwyLAMLtu5pJ0j/qwx3Rk8O9X6xmk/L0Q== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792842289; b=iuHBKtqJV641/XY/1lyL6e7XraAkwKdpPE8XippPJg/WibVpRe/qO2MZvwA0BcySLRlS9h cAoINzBBXoPwYS4CzDfEvaJCYTSltetyA+/v30yJ6VvOt13mxFZd6wyOKLSgBgbGDbTaMs jP2jLZYg9kC8ilBR8SQh1Mq3M214JFp9ghaof2VYuoB2nCjnnmlk9tqOgaoXgtTQsZ7Vrb dTlEyDepzBoj67SpduNMIiQSKNkI3TkJng2i5Mld9mMjGLApb/1BBU30xhzty7lmcrlMyY 5FIFp268+w19KhJQm1IvMlvpYr1qXLUL4YWZYJ39lt9k0VWzouIev/X50UfJNg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792842289; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8w2xTNJtXwWZM0BK5Nexr6KDjM2dlWy3sSuyDh2/xbY=; b=oZMp1XuHhUxm/+CZPSZz3/VLhrOIWcP88LgIltab9v2AxxuTOtroFD+bf4hFPzSelsx/cj P4RkuqrpqRG24UEwHG9keIpHpjK0EDoFeDCtCh2V5mvIm9A0+5JTcayMcFlYKCPEKpXIlL vNROJUkkpLt83kV9jUYs3PpB/gZNmZwCZmMIEtRnMKjv44Shcf7/8KRyZoSXBnZ+7J6mBa rtIXhgG7flnA5LZKs5/J3jplOE9KRo0xMGoAyys9s3BGt4vQGpalOFduVblYn9PG3eRAnJ LrUbaGn+oipZ5o7YdwTUVvr+pYc89/+6Lxpc8XviusWCWz0GdGwv/jILxmKavA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jBdNK2DDKz1DXL for ; Sat, 24 Oct 2026 11:44:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 44eb8 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 24 Oct 2026 11:44:49 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Roman Bogorodskiy Subject: git: e809c7d810ce - main - bhyve: add command to list config options List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: Commit messages for the main branch of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: novel X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e809c7d810ced2307741a7c0c135a8b1bef1851b Auto-Submitted: auto-generated Date: Sat, 24 Oct 2026 11:44:49 +0000 Message-Id: <6adc9a31.44eb8.36988275@gitrepo.freebsd.org> The branch main has been updated by novel: URL: https://cgit.FreeBSD.org/src/commit/?id=e809c7d810ced2307741a7c0c135a8b1bef1851b commit e809c7d810ced2307741a7c0c135a8b1bef1851b Author: Roman Bogorodskiy AuthorDate: 2026-07-22 16:08:09 +0000 Commit: Roman Bogorodskiy CommitDate: 2026-10-24 11:01:53 +0000 bhyve: add command to list config options For a software built on top of bhyve(8) and/or managing bhyve(8), it is very convenient to know what specific features the given binary supports. Currently, bhyve(8) provides some of this information, and it could be retrieved by parsing `bhyve -h`, `bhyve -s help`, `bhyve -l help`. Sometimes it is not enough, for example, the recently added "oemstrings" feature cannot be fully probed using these commands. Over time, some workarounds were suggested. Specifically: - Mapping features to __FreeBSD_version. I see at least two issues with that: * __FreeBSD_version does not directly map to bhyve(8) features, so this is simply not accurate. * bhyve(8) might be updated separately from the system, which is not so uncommon, especially for development purposes. Then such a probing will be inaccurate. - Manual pages parsing. I see more disadvantages with that: * Manual pages are meant to be read by a human. Extracting information from it by a machine is not the most convenient thing. Especially understanding side notes like: "Note, feature 'foo' is arm64-only!". * Manual pages might be inaccurate, they might miss options. * bhyve(8) could be used in an environment where manual pages are not installed. This commit attempts to close this gap by introducing the "bhyve -o help" command which prints all the supported configuration variables. In my opinion, it is, in combination with the other commands mentioned above, sufficient to retrieve most of the capabilities of the given bhyve(8) binary. The current implementation defines a simple configuration schema for common and machdep code and prints out a list of supported configuration variables for the current architecture. The next step as I see it would be extending set_config*() functions to validate the user provided values against the schema, so users get notified early on incorrect or misspelled configuration variables. It would also be nice to allow users to only validate their configuration, think of 'nginx configtest / -t'. Reviewed by: chuck (previous revision), bnovkov MFC after: 1 month MFC to: stable/15 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D58419 --- usr.sbin/bhyve/Makefile | 1 + usr.sbin/bhyve/aarch64/bhyverun_machdep.c | 22 ++++ usr.sbin/bhyve/amd64/bhyverun_machdep.c | 95 ++++++++++++++ usr.sbin/bhyve/bhyve.8 | 6 +- usr.sbin/bhyve/block_if.c | 17 +++ usr.sbin/bhyve/block_if.h | 3 + usr.sbin/bhyve/config_schema.c | 202 ++++++++++++++++++++++++++++++ usr.sbin/bhyve/config_schema.h | 40 ++++++ usr.sbin/bhyve/pci_nvme.c | 20 +++ usr.sbin/bhyve/riscv/bhyverun_machdep.c | 18 +++ 10 files changed, 423 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index eb7cfe7b602e..0fb0e1028398 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -25,6 +25,7 @@ SRCS= \ block_if.c \ bootrom.c \ config.c \ + config_schema.c \ console.c \ crc16.c \ ctl_nvme_all.c \ diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c index f38c719a71a7..72194dd0e269 100644 --- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c @@ -46,6 +46,7 @@ #include "bhyve_machdep.h" #include "bhyverun.h" #include "config.h" +#include "config_schema.h" #include "debug.h" #include "fdt.h" #include "mem.h" @@ -55,6 +56,23 @@ #include "rtc_pl031.h" #include "uart_emul.h" +static const struct config_option config_options_machdep[] = { + { "gdb.address", CONFIG_OPTION_STRING }, + { "gdb.port", CONFIG_OPTION_INTEGER }, + { "gdb.wait", CONFIG_OPTION_BOOL }, + { "rtc.use_localtime", CONFIG_OPTION_BOOL }, + { "console", CONFIG_OPTION_STRING }, + { "fdt.bootargs", CONFIG_OPTION_STRING }, +}; + +void +config_schema_merge_options_machdep(struct config_schema *schema) +{ + + config_schema_merge_options(schema, NULL, config_options_machdep, + nitems(config_options_machdep)); +} + /* Start of mem + 1M */ #define FDT_BASE 0x100000 #define FDT_SIZE (64 * 1024) @@ -161,6 +179,10 @@ bhyve_optparse(int argc, char **argv) set_config_bool("monitor.no_reboot", true); break; case 'o': + if (strcmp(optarg, "help") == 0) { + print_config_options(); + exit(0); + } if (!bhyve_parse_config_option(optarg)) { errx(EX_USAGE, "invalid configuration option '%s'", diff --git a/usr.sbin/bhyve/amd64/bhyverun_machdep.c b/usr.sbin/bhyve/amd64/bhyverun_machdep.c index 3d498879cd58..94fda0cd212a 100644 --- a/usr.sbin/bhyve/amd64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/amd64/bhyverun_machdep.c @@ -26,10 +26,13 @@ * SUCH DAMAGE. */ +#include + #include #include #include #include +#include #include #include @@ -42,6 +45,7 @@ #endif #include "bootrom.h" #include "config.h" +#include "config_schema.h" #include "debug.h" #include "e820.h" #include "fwctl.h" @@ -57,6 +61,93 @@ #include "smbiostbl.h" #include "xmsr.h" +static const struct config_option config_options_machdep[] = { + { "bootvars", CONFIG_OPTION_STRING }, + { "acpi_tables", CONFIG_OPTION_BOOL }, + { "acpi_tables_in_memory", CONFIG_OPTION_BOOL }, + + { "gdb.address", CONFIG_OPTION_STRING }, + { "gdb.port", CONFIG_OPTION_INTEGER }, + { "gdb.wait", CONFIG_OPTION_BOOL }, + { "keyboard.layout", CONFIG_OPTION_STRING }, + { "rtc.use_localtime", CONFIG_OPTION_BOOL }, + + { "bios.vendor", CONFIG_OPTION_STRING }, + { "bios.version", CONFIG_OPTION_STRING }, + { "bios.release_date", CONFIG_OPTION_STRING }, + { "system.family_name", CONFIG_OPTION_STRING }, + { "system.manufacturer", CONFIG_OPTION_STRING }, + { "system.product_name", CONFIG_OPTION_STRING }, + { "system.serial_number", CONFIG_OPTION_STRING }, + { "system.sku", CONFIG_OPTION_STRING }, + { "system.version", CONFIG_OPTION_STRING }, + { "board.manufacturer", CONFIG_OPTION_STRING }, + { "board.product_name", CONFIG_OPTION_STRING }, + { "board.version", CONFIG_OPTION_STRING }, + { "board.serial_number", CONFIG_OPTION_STRING }, + { "board.asset_tag", CONFIG_OPTION_STRING }, + { "board.location", CONFIG_OPTION_STRING }, + { "chassis.manufacturer", CONFIG_OPTION_STRING }, + { "chassis.version", CONFIG_OPTION_STRING }, + { "chassis.serial_number", CONFIG_OPTION_STRING }, + { "chassis.asset_tag", CONFIG_OPTION_STRING }, + { "chassis.sku", CONFIG_OPTION_STRING }, + { "oemstring.N", CONFIG_OPTION_STRING }, + + { "x86.mptable", CONFIG_OPTION_BOOL }, + { "x86.x2apic", CONFIG_OPTION_BOOL }, + { "x86.strictio", CONFIG_OPTION_BOOL }, + { "x86.strictmsr", CONFIG_OPTION_BOOL }, + { "x86.verbosemsr", CONFIG_OPTION_BOOL }, + { "x86.vmexit_on_hlt", CONFIG_OPTION_BOOL }, + { "x86.vmexit_on_pause", CONFIG_OPTION_BOOL }, + + { "pci.B.S.F.wait", CONFIG_OPTION_BOOL }, + { "pci.B.S.F.rfb", CONFIG_OPTION_STRING }, + { "pci.B.S.F.vga", CONFIG_OPTION_STRING }, + { "pci.B.S.F.w", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.h", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.password", CONFIG_OPTION_STRING }, + { "pci.B.S.F.tcp", CONFIG_OPTION_STRING }, + + { "lpc.com1.path", CONFIG_OPTION_STRING }, + { "lpc.com1.tcp", CONFIG_OPTION_STRING }, + { "lpc.com2.path", CONFIG_OPTION_STRING }, + { "lpc.com2.tcp", CONFIG_OPTION_STRING }, + { "lpc.com3.path", CONFIG_OPTION_STRING }, + { "lpc.com3.tcp", CONFIG_OPTION_STRING }, + { "lpc.com4.path", CONFIG_OPTION_STRING }, + { "lpc.com4.tcp", CONFIG_OPTION_STRING }, + { "lpc.fwcfg", CONFIG_OPTION_STRING }, + { "lpc.pc-testdev", CONFIG_OPTION_BOOL }, + { "lpc.pcireg.*", CONFIG_OPTION_INTEGER }, + { "lpc.pcireg.vendor", CONFIG_OPTION_INTEGER }, + { "lpc.pcireg.device", CONFIG_OPTION_INTEGER }, + { "lpc.pcireg.revid", CONFIG_OPTION_INTEGER }, + { "lpc.pcireg.subvendor", CONFIG_OPTION_INTEGER }, + { "lpc.pcireg.subdevice", CONFIG_OPTION_INTEGER }, + + { "tpm.path", CONFIG_OPTION_STRING }, + { "tpm.type", CONFIG_OPTION_STRING }, + { "tpm.version", CONFIG_OPTION_STRING }, + { "tpm.intf", CONFIG_OPTION_STRING }, + { "tpm.ppi", CONFIG_OPTION_STRING }, + + { "pci.B.S.F.bus", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.slot", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.func", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.pptdev", CONFIG_OPTION_STRING }, + { "pci.B.S.F.rom", CONFIG_OPTION_STRING }, +}; + +void +config_schema_merge_options_machdep(struct config_schema *schema) +{ + + config_schema_merge_options(schema, NULL, config_options_machdep, + nitems(config_options_machdep)); +} + void bhyve_init_config(void) { @@ -219,6 +310,10 @@ bhyve_optparse(int argc, char **argv) set_config_bool("monitor.no_reboot", true); break; case 'o': + if (strcmp(optarg, "help") == 0) { + print_config_options(); + exit(0); + } if (!bhyve_parse_config_option(optarg)) { errx(EX_USAGE, "invalid configuration option '%s'", diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 14d91e0711d1..c5b6f538f0ae 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -26,7 +26,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 3, 2026 +.Dd October 24, 2026 .Dt BHYVE 8 .Os .Sh NAME @@ -92,6 +92,8 @@ .Nm .Fl l Cm help .Nm +.Fl o Cm help +.Nm .Fl s Cm help .Sh DESCRIPTION .Nm @@ -352,6 +354,8 @@ This option has no effect unless the configuration option is enabled or .Fl M was specified. +.It Fl o Cm help +Print a list of supported configuration variables. .It Fl o Ar var Ns Cm = Ns Ar value Set the configuration variable .Ar var diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c index 0a4f76ae197d..311809f0c0e5 100644 --- a/usr.sbin/bhyve/block_if.c +++ b/usr.sbin/bhyve/block_if.c @@ -57,6 +57,7 @@ #include "bhyverun.h" #include "config.h" +#include "config_schema.h" #include "debug.h" #include "mevent.h" #include "pci_emul.h" @@ -67,6 +68,22 @@ #define BLOCKIF_NUMTHR 8 #define BLOCKIF_MAXREQ (BLOCKIF_RING_MAX + BLOCKIF_NUMTHR) +static const struct config_option blockif_config_options[] = { + { "path", CONFIG_OPTION_STRING }, + { "nocache", CONFIG_OPTION_BOOL }, + { "nodelete", CONFIG_OPTION_BOOL }, + { "sync", CONFIG_OPTION_BOOL }, + { "direct", CONFIG_OPTION_BOOL }, + { "ro", CONFIG_OPTION_BOOL }, + { "sectorsize", CONFIG_OPTION_STRING }, + { "bootindex", CONFIG_OPTION_INTEGER }, +}; + +const struct config_option_set blockif_config_option_set = { + .options = blockif_config_options, + .count = nitems(blockif_config_options), +}; + enum blockop { BOP_READ, BOP_WRITE, diff --git a/usr.sbin/bhyve/block_if.h b/usr.sbin/bhyve/block_if.h index 9a1a65a1bfe9..afe56570035b 100644 --- a/usr.sbin/bhyve/block_if.h +++ b/usr.sbin/bhyve/block_if.h @@ -40,8 +40,11 @@ #include #include +struct config_option_set; struct vm_snapshot_meta; +extern const struct config_option_set blockif_config_option_set; + /* * BLOCKIF_IOV_MAX is the maximum number of scatter/gather entries in diff --git a/usr.sbin/bhyve/config_schema.c b/usr.sbin/bhyve/config_schema.c new file mode 100644 index 000000000000..d73803b6cb77 --- /dev/null +++ b/usr.sbin/bhyve/config_schema.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2026 The FreeBSD Foundation + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "config_schema.h" + +SET_DECLARE(config_option_set, struct config_option_set); + +struct config_schema_option { + RB_ENTRY(config_schema_option) entry; + char *name; + enum config_option_type type; +}; + +RB_HEAD(config_schema, config_schema_option); + +static int +config_schema_option_compare(struct config_schema_option *a, + struct config_schema_option *b) +{ + + return (strcmp(a->name, b->name)); +} + +RB_GENERATE_STATIC(config_schema, config_schema_option, entry, + config_schema_option_compare); + +static const struct config_option config_options[] = { + { "name", CONFIG_OPTION_STRING }, + { "cpus", CONFIG_OPTION_INTEGER }, + { "cores", CONFIG_OPTION_INTEGER }, + { "threads", CONFIG_OPTION_INTEGER }, + { "sockets", CONFIG_OPTION_INTEGER }, + { "memory.guest_in_core", CONFIG_OPTION_BOOL }, + { "memory.size", CONFIG_OPTION_STRING }, + { "memory.wired", CONFIG_OPTION_BOOL }, + { "bootrom", CONFIG_OPTION_STRING }, + { "destroy_on_poweroff", CONFIG_OPTION_BOOL }, + { "pci.enable_bars", CONFIG_OPTION_BOOL }, + { "uuid", CONFIG_OPTION_STRING }, + { "virtio.msix", CONFIG_OPTION_BOOL }, + { "config.dump", CONFIG_OPTION_BOOL }, + { "rundir", CONFIG_OPTION_STRING }, + { "monitor.enabled", CONFIG_OPTION_BOOL }, + { "monitor.no_reboot", CONFIG_OPTION_BOOL }, + + { "vcpu.N.cpuset", CONFIG_OPTION_STRING }, + { "domains.N.size", CONFIG_OPTION_STRING }, + { "domains.N.domain_policy", CONFIG_OPTION_STRING }, + { "domains.N.cpus", CONFIG_OPTION_STRING }, + + { "pci.B.S.F.device", CONFIG_OPTION_STRING }, + { "pci.B.S.F.vendor", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.devid", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.pcireg.*", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.pcireg.vendor", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.pcireg.device", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.port.N.type", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.path", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.nocache", CONFIG_OPTION_BOOL }, + { "pci.B.S.F.port.N.nodelete", CONFIG_OPTION_BOOL }, + { "pci.B.S.F.port.N.sync", CONFIG_OPTION_BOOL }, + { "pci.B.S.F.port.N.direct", CONFIG_OPTION_BOOL }, + { "pci.B.S.F.port.N.ro", CONFIG_OPTION_BOOL }, + { "pci.B.S.F.port.N.sectorsize", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.nmrr", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.port.N.ser", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.rev", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.model", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.bootindex", CONFIG_OPTION_INTEGER }, + + { "pci.B.S.F.backend", CONFIG_OPTION_STRING }, + { "pci.B.S.F.type", CONFIG_OPTION_STRING }, + { "pci.B.S.F.peerhook", CONFIG_OPTION_STRING }, + { "pci.B.S.F.socket", CONFIG_OPTION_STRING }, + { "pci.B.S.F.hook", CONFIG_OPTION_STRING }, + { "pci.B.S.F.hostfwd", CONFIG_OPTION_STRING }, + { "pci.B.S.F.mac", CONFIG_OPTION_STRING }, + { "pci.B.S.F.mtu", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.play", CONFIG_OPTION_STRING }, + { "pci.B.S.F.rec", CONFIG_OPTION_STRING }, + + { "pci.B.S.F.serial", CONFIG_OPTION_STRING }, + { "pci.B.S.F.sharename", CONFIG_OPTION_STRING }, + { "pci.B.S.F.port.N.name", CONFIG_OPTION_STRING }, + + { "pci.B.S.F.ctl_ringsz", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.evt_ringsz", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.req_ringsz", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.num_queues", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.seg_max", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.thr_per_q", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.target.N", CONFIG_OPTION_STRING }, + { "pci.B.S.F.iid", CONFIG_OPTION_INTEGER }, + { "pci.B.S.F.slot.N.device", CONFIG_OPTION_STRING }, +}; + +static const char * +config_option_type_name(enum config_option_type type) +{ + + switch (type) { + case CONFIG_OPTION_BOOL: + return ("bool"); + case CONFIG_OPTION_INTEGER: + return ("integer"); + case CONFIG_OPTION_STRING: + return ("string"); + } + errx(EX_SOFTWARE, "invalid configuration option type"); +} + +void +config_schema_merge_options(struct config_schema *schema, const char *prefix, + const struct config_option *options, size_t count) +{ + struct config_schema_option *existing, *option; + char *name; + size_t i; + + if (prefix == NULL) + prefix = ""; + for (i = 0; i < count; i++) { + if (asprintf(&name, "%s%s", prefix, options[i].name) == -1) + err(EX_OSERR, "asprintf"); + option = malloc(sizeof(*option)); + if (option == NULL) + err(EX_OSERR, "malloc"); + option->name = name; + option->type = options[i].type; + + existing = RB_INSERT(config_schema, schema, option); + if (existing == NULL) + continue; + if (existing->type != option->type) { + errx(EX_SOFTWARE, + "conflicting types for configuration option " + "'%s': %s and %s", option->name, + config_option_type_name(existing->type), + config_option_type_name(option->type)); + } + free(option->name); + free(option); + } +} + +static void +config_schema_merge_option_set(struct config_schema *schema, + const struct config_option_set *set, const char *inherited_prefix) +{ + const char *prefix; + + prefix = set->prefix != NULL ? set->prefix : inherited_prefix; + if (set->base != NULL) + config_schema_merge_option_set(schema, set->base, prefix); + config_schema_merge_options(schema, prefix, set->options, set->count); +} + +static void +config_schema_destroy(struct config_schema *schema) +{ + struct config_schema_option *option, *tmp; + + RB_FOREACH_SAFE(option, config_schema, schema, tmp) { + RB_REMOVE(config_schema, schema, option); + free(option->name); + free(option); + } +} + +void +print_config_options(void) +{ + struct config_schema_option *option; + struct config_option_set **setp; + struct config_schema schema; + + RB_INIT(&schema); + config_schema_merge_options(&schema, NULL, config_options, + nitems(config_options)); + SET_FOREACH(setp, config_option_set) { + config_schema_merge_option_set(&schema, *setp, NULL); + } + config_schema_merge_options_machdep(&schema); + + RB_FOREACH(option, config_schema, &schema) { + printf("%s\n", option->name); + } + config_schema_destroy(&schema); +} diff --git a/usr.sbin/bhyve/config_schema.h b/usr.sbin/bhyve/config_schema.h new file mode 100644 index 000000000000..2a6890ac6675 --- /dev/null +++ b/usr.sbin/bhyve/config_schema.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026 The FreeBSD Foundation + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef __CONFIG_SCHEMA_H__ +#define __CONFIG_SCHEMA_H__ + +#include +#include + +enum config_option_type { + CONFIG_OPTION_BOOL, + CONFIG_OPTION_INTEGER, + CONFIG_OPTION_STRING, +}; + +struct config_option { + const char *name; + enum config_option_type type; +}; + +struct config_option_set { + const char *prefix; + const struct config_option_set *base; + const struct config_option *options; + size_t count; +}; + +struct config_schema; + +#define CONFIG_OPTION_SET(x) DATA_SET(config_option_set, x) + +void config_schema_merge_options(struct config_schema *, const char *, + const struct config_option *, size_t); +void config_schema_merge_options_machdep(struct config_schema *); +void print_config_options(void); + +#endif /* !__CONFIG_SCHEMA_H__ */ diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c index 7e6768de8550..50ad8ea21f88 100644 --- a/usr.sbin/bhyve/pci_nvme.c +++ b/usr.sbin/bhyve/pci_nvme.c @@ -55,6 +55,7 @@ #include #include +#include #include #include #include @@ -79,9 +80,28 @@ #include "bhyverun.h" #include "block_if.h" #include "config.h" +#include "config_schema.h" #include "debug.h" #include "pci_emul.h" +static const struct config_option pci_nvme_config_options[] = { + { "maxq", CONFIG_OPTION_INTEGER }, + { "qsz", CONFIG_OPTION_INTEGER }, + { "ioslots", CONFIG_OPTION_INTEGER }, + { "sectsz", CONFIG_OPTION_INTEGER }, + { "ser", CONFIG_OPTION_STRING }, + { "eui64", CONFIG_OPTION_INTEGER }, + { "dsm", CONFIG_OPTION_STRING }, + { "ram", CONFIG_OPTION_INTEGER }, +}; + +static const struct config_option_set pci_nvme_config_option_set = { + .prefix = "pci.B.S.F.", + .base = &blockif_config_option_set, + .options = pci_nvme_config_options, + .count = nitems(pci_nvme_config_options), +}; +CONFIG_OPTION_SET(pci_nvme_config_option_set); static int nvme_debug = 0; #define DPRINTF(fmt, args...) if (nvme_debug) PRINTLN(fmt, ##args) diff --git a/usr.sbin/bhyve/riscv/bhyverun_machdep.c b/usr.sbin/bhyve/riscv/bhyverun_machdep.c index 50e68c958ab3..41adbbd51fc1 100644 --- a/usr.sbin/bhyve/riscv/bhyverun_machdep.c +++ b/usr.sbin/bhyve/riscv/bhyverun_machdep.c @@ -49,6 +49,7 @@ #include "bhyverun.h" #include "config.h" +#include "config_schema.h" #include "debug.h" #include "fdt.h" #include "ipc.h" @@ -58,6 +59,19 @@ #include "uart_emul.h" #include "riscv.h" +static const struct config_option config_options_machdep[] = { + { "console", CONFIG_OPTION_STRING }, + { "fdt.bootargs", CONFIG_OPTION_STRING }, +}; + +void +config_schema_merge_options_machdep(struct config_schema *schema) +{ + + config_schema_merge_options(schema, NULL, config_options_machdep, + nitems(config_options_machdep)); +} + #define FDT_SIZE (64 * 1024) #define FDT_DTB_ALIGN 8 @@ -152,6 +166,10 @@ bhyve_optparse(int argc, char **argv) set_config_bool("monitor.no_reboot", true); break; case 'o': + if (strcmp(optarg, "help") == 0) { + print_config_options(); + exit(0); + } if (!bhyve_parse_config_option(optarg)) { errx(EX_USAGE, "invalid configuration option '%s'",