From nobody Sat Oct 24 11:44:49 2026 X-Original-To: dev-commits-src-all@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 4jBdNQ2Z2Kz6wT11 for ; Sat, 24 Oct 2026 11:44:54 +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 4jBdNQ2Jh3z4RCk for ; Sat, 24 Oct 2026 11:44:54 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792842294; 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=ZaTo3PGkcwjOVy2xJbs6+vKWYt5MLJpVqAGayQnIAJnUWgtRkycB9F7SHCtR7CIfOtP3/8 I/PAXLZWYipxz0cO4EtljrQO+WdUH042xXoZhUsDUaE+h/nuIf1l9BxObeliUJQCqgZALO bOty3684kxYj0zQo0obI0oX+Pom/V9GXazKw8f5m/K6jHTUMLspKKI3qQNotywXGxrJalA dGdJja5i+7slPHBXHYILn2ZtlUjqBLH8k8UceVxkxCNMEwvzhy2w0jCcCH8/fgVs4/sR7t ZHsv1QGDDVy0feyW06VVjl+K07M2u2jFxPgzpa4S85PgO/A3tvudhC/a77jrog== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792842294; b=IabQsjef6MX0xzdSOWrkEC+L/kbamfCzk5hEYstj5Jo7kA36GDq6tDI3pN0OiFkN83F3X+ 5IWEcKUq7WSQi90AXfXNO6KmIbNtk/4IfTgPgZxjr3hHCH9/vNdbsn08qgA3dNu6DvNv/R vYnG5nu6SuDdt3tsztJhdtC1QZl2sj3WMCWGdUUFgcfjh09x6vPYuX+UYvZEq1L2/6XSjj QqPJvqBARvgiQe0wULscxW/ojbRqGi+x6A17lN69a907HhIylCcJFg3gXOlZ3i5H4XCg0s xdHjOGh/EsnC4GT43SFzrrfRt6q66ATyjFTIk4eICrCKXMVccT16w4eRglIT/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792842294; 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=tbCbFJ30575C0Z2941oTPKgqD390ssnGjxI5PYjxEFyii+UCAapgsq7tgk06zKlUC/fNYQ w2DTJ9rnTKq62ybxktR1KW6MJ1C6CBG6Fv/aBNLlYiz94cd19mI8xLvJh9kyl7qln09XZj i4S8TTWX2FQ+t1hqHB+XPIT5LizGdafnpKo8urRrcnK6eW6bxS0StfiDvMTjbsAX84dFYw 132dpLkUh54IV4HQOrpOR94MPNL3qrBk38Y6pDVUbwxZzHU5fEeij52Gutk+5WnpsPs2Tv f6NNpWNVNkWg8lRKNNW+fNXFvg/yeoF40vVvDheMKMnjOoH6PQlwTnkWfJU86Q== 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 4jBdNQ1znmz1Dxj for ; Sat, 24 Oct 2026 11:44:54 +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-all X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: Commit messages for all branches 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'",