git: 981f9f7495bb - main - bhyve: Push option parsing down into bhyverun_machdep.c
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 10 Apr 2024 15:19:21 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=981f9f7495bb8247e0eba48e15dcc7f2e0b1b342
commit 981f9f7495bb8247e0eba48e15dcc7f2e0b1b342
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-04-03 17:44:40 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-04-10 15:17:56 +0000
bhyve: Push option parsing down into bhyverun_machdep.c
After a couple of attempts I think this is the cleanest approach despite
the expense of some code duplication. Quite a few of the single-letter
bhyve options are x86-specific.
I think that going forward we should strongly discourage the addition of
new options and instead configure guests using the more general
configuration file syntax.
Reviewed by: corvink, jhb
MFC after: 2 weeks
Sponsored by: Innovate UK
Differential Revision: https://reviews.freebsd.org/D41753
---
usr.sbin/bhyve/aarch64/bhyverun_machdep.c | 98 ++++++++++++++
usr.sbin/bhyve/amd64/bhyverun_machdep.c | 181 +++++++++++++++++++++++++
usr.sbin/bhyve/bhyverun.c | 212 +++---------------------------
usr.sbin/bhyve/bhyverun.h | 12 ++
4 files changed, 307 insertions(+), 196 deletions(-)
diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
index 9b0010a78b47..22b8b85e6b9b 100644
--- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
+++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
@@ -34,7 +34,9 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
#include <vmmapi.h>
@@ -44,6 +46,7 @@
#include "debug.h"
#include "fdt.h"
#include "mem.h"
+#include "pci_emul.h"
#include "uart_emul.h"
/* Start of mem + 1M */
@@ -73,6 +76,101 @@ bhyve_init_config(void)
set_config_value("memory.size", "256M");
}
+void
+bhyve_usage(int code)
+{
+ const char *progname;
+
+ progname = getprogname();
+
+ fprintf(stderr,
+ "Usage: %s [-CDHhSW]\n"
+ " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
+ " %*s [-k config_file] [-m mem] [-o var=value]\n"
+ " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
+ " -C: include guest memory in core file\n"
+ " -c: number of CPUs and/or topology specification\n"
+ " -D: destroy on power-off\n"
+ " -h: help\n"
+ " -k: key=value flat config file\n"
+ " -m: memory size\n"
+ " -o: set config 'var' to 'value'\n"
+ " -p: pin 'vcpu' to 'hostcpu'\n"
+ " -S: guest memory cannot be swapped\n"
+ " -s: <slot,driver,configinfo> PCI slot config\n"
+ " -U: UUID\n"
+ " -W: force virtio to use single-vector MSI\n",
+ progname, (int)strlen(progname), "", (int)strlen(progname), "",
+ (int)strlen(progname), "");
+ exit(code);
+}
+
+void
+bhyve_optparse(int argc, char **argv)
+{
+ const char *optstr;
+ int c;
+
+ optstr = "hCDSWk:f:o:p:c:s:m:U:";
+ while ((c = getopt(argc, argv, optstr)) != -1) {
+ switch (c) {
+ case 'c':
+ if (bhyve_topology_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid cpu topology '%s'",
+ optarg);
+ }
+ break;
+ case 'C':
+ set_config_bool("memory.guest_in_core", true);
+ break;
+ case 'D':
+ set_config_bool("destroy_on_poweroff", true);
+ break;
+ case 'k':
+ bhyve_parse_simple_config_file(optarg);
+ break;
+ case 'm':
+ set_config_value("memory.size", optarg);
+ break;
+ case 'o':
+ if (!bhyve_parse_config_option(optarg)) {
+ errx(EX_USAGE,
+ "invalid configuration option '%s'",
+ optarg);
+ }
+ break;
+ case 'p':
+ if (bhyve_pincpu_parse(optarg) != 0) {
+ errx(EX_USAGE,
+ "invalid vcpu pinning configuration '%s'",
+ optarg);
+ }
+ break;
+ case 's':
+ if (strncmp(optarg, "help", strlen(optarg)) == 0) {
+ pci_print_supported_devices();
+ exit(0);
+ } else if (pci_parse_slot(optarg) != 0)
+ exit(4);
+ else
+ break;
+ case 'S':
+ set_config_bool("memory.wired", true);
+ break;
+ case 'U':
+ set_config_value("uuid", optarg);
+ break;
+ case 'W':
+ set_config_bool("virtio_msix", false);
+ break;
+ case 'h':
+ bhyve_usage(0);
+ default:
+ bhyve_usage(1);
+ }
+ }
+}
+
void
bhyve_init_vcpu(struct vcpu *vcpu __unused)
{
diff --git a/usr.sbin/bhyve/amd64/bhyverun_machdep.c b/usr.sbin/bhyve/amd64/bhyverun_machdep.c
index 4f482586f900..fc2f91e31db7 100644
--- a/usr.sbin/bhyve/amd64/bhyverun_machdep.c
+++ b/usr.sbin/bhyve/amd64/bhyverun_machdep.c
@@ -30,6 +30,7 @@
#include <err.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <sysexits.h>
#include <vmmapi.h>
@@ -44,6 +45,7 @@
#include "inout.h"
#include "kernemu_dev.h"
#include "mptbl.h"
+#include "pci_emul.h"
#include "pci_irq.h"
#include "pci_lpc.h"
#include "rtc.h"
@@ -63,6 +65,185 @@ bhyve_init_config(void)
set_config_value("lpc.fwcfg", "bhyve");
}
+void
+bhyve_usage(int code)
+{
+ const char *progname;
+
+ progname = getprogname();
+
+ fprintf(stderr,
+ "Usage: %s [-AaCDeHhPSuWwxY]\n"
+ " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
+ " %*s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n"
+ " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
+ " -A: create ACPI tables\n"
+ " -a: local apic is in xAPIC mode (deprecated)\n"
+ " -C: include guest memory in core file\n"
+ " -c: number of CPUs and/or topology specification\n"
+ " -D: destroy on power-off\n"
+ " -e: exit on unhandled I/O access\n"
+ " -G: start a debug server\n"
+ " -H: vmexit from the guest on HLT\n"
+ " -h: help\n"
+ " -k: key=value flat config file\n"
+ " -K: PS2 keyboard layout\n"
+ " -l: LPC device configuration\n"
+ " -m: memory size\n"
+ " -o: set config 'var' to 'value'\n"
+ " -P: vmexit from the guest on pause\n"
+ " -p: pin 'vcpu' to 'hostcpu'\n"
+#ifdef BHYVE_SNAPSHOT
+ " -r: path to checkpoint file\n"
+#endif
+ " -S: guest memory cannot be swapped\n"
+ " -s: <slot,driver,configinfo> PCI slot config\n"
+ " -U: UUID\n"
+ " -u: RTC keeps UTC time\n"
+ " -W: force virtio to use single-vector MSI\n"
+ " -w: ignore unimplemented MSRs\n"
+ " -x: local APIC is in x2APIC mode\n"
+ " -Y: disable MPtable generation\n",
+ progname, (int)strlen(progname), "", (int)strlen(progname), "",
+ (int)strlen(progname), "");
+ exit(code);
+}
+
+void
+bhyve_optparse(int argc, char **argv)
+{
+ const char *optstr;
+ int c;
+
+#ifdef BHYVE_SNAPSHOT
+ optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:";
+#else
+ optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:";
+#endif
+ while ((c = getopt(argc, argv, optstr)) != -1) {
+ switch (c) {
+ case 'a':
+ set_config_bool("x86.x2apic", false);
+ break;
+ case 'A':
+ /*
+ * NOP. For backward compatibility. Most systems don't
+ * work properly without sane ACPI tables. Therefore,
+ * we're always generating them.
+ */
+ break;
+ case 'D':
+ set_config_bool("destroy_on_poweroff", true);
+ break;
+ case 'p':
+ if (bhyve_pincpu_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid vcpu pinning "
+ "configuration '%s'", optarg);
+ }
+ break;
+ case 'c':
+ if (bhyve_topology_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid cpu topology "
+ "'%s'", optarg);
+ }
+ break;
+ case 'C':
+ set_config_bool("memory.guest_in_core", true);
+ break;
+ case 'f':
+ if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) {
+ errx(EX_USAGE, "invalid fwcfg item '%s'",
+ optarg);
+ }
+ break;
+ case 'G':
+ bhyve_parse_gdb_options(optarg);
+ break;
+ case 'k':
+ bhyve_parse_simple_config_file(optarg);
+ break;
+ case 'K':
+ set_config_value("keyboard.layout", optarg);
+ break;
+ case 'l':
+ if (strncmp(optarg, "help", strlen(optarg)) == 0) {
+ lpc_print_supported_devices();
+ exit(0);
+ } else if (lpc_device_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid lpc device "
+ "configuration '%s'", optarg);
+ }
+ break;
+#ifdef BHYVE_SNAPSHOT
+ case 'r':
+ restore_file = optarg;
+ break;
+#endif
+ case 's':
+ if (strncmp(optarg, "help", strlen(optarg)) == 0) {
+ pci_print_supported_devices();
+ exit(0);
+ } else if (pci_parse_slot(optarg) != 0)
+ exit(4);
+ else
+ break;
+ case 'S':
+ set_config_bool("memory.wired", true);
+ break;
+ case 'm':
+ set_config_value("memory.size", optarg);
+ break;
+ case 'o':
+ if (!bhyve_parse_config_option(optarg)) {
+ errx(EX_USAGE,
+ "invalid configuration option '%s'",
+ optarg);
+ }
+ break;
+ case 'H':
+ set_config_bool("x86.vmexit_on_hlt", true);
+ break;
+ case 'I':
+ /*
+ * The "-I" option was used to add an ioapic to the
+ * virtual machine.
+ *
+ * An ioapic is now provided unconditionally for each
+ * virtual machine and this option is now deprecated.
+ */
+ break;
+ case 'P':
+ set_config_bool("x86.vmexit_on_pause", true);
+ break;
+ case 'e':
+ set_config_bool("x86.strictio", true);
+ break;
+ case 'u':
+ set_config_bool("rtc.use_localtime", false);
+ break;
+ case 'U':
+ set_config_value("uuid", optarg);
+ break;
+ case 'w':
+ set_config_bool("x86.strictmsr", false);
+ break;
+ case 'W':
+ set_config_bool("virtio_msix", false);
+ break;
+ case 'x':
+ set_config_bool("x86.x2apic", true);
+ break;
+ case 'Y':
+ set_config_bool("x86.mptable", false);
+ break;
+ case 'h':
+ bhyve_usage(0);
+ default:
+ bhyve_usage(1);
+ }
+ }
+}
+
void
bhyve_init_vcpu(struct vcpu *vcpu)
{
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index b9f00385d9e8..1c3b810efb02 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -100,7 +100,6 @@ uint16_t cpu_cores, cpu_sockets, cpu_threads;
int raw_stdio = 0;
-static char *progname;
static const int BSP = 0;
static cpuset_t cpumask;
@@ -115,48 +114,6 @@ static struct vcpu_info {
static cpuset_t **vcpumap;
-static void
-usage(int code)
-{
-
- fprintf(stderr,
- "Usage: %s [-AaCDeHhPSuWwxY]\n"
- " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
- " %*s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n"
- " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
- " -A: create ACPI tables\n"
- " -a: local apic is in xAPIC mode (deprecated)\n"
- " -C: include guest memory in core file\n"
- " -c: number of CPUs and/or topology specification\n"
- " -D: destroy on power-off\n"
- " -e: exit on unhandled I/O access\n"
- " -G: start a debug server\n"
- " -H: vmexit from the guest on HLT\n"
- " -h: help\n"
- " -k: key=value flat config file\n"
- " -K: PS2 keyboard layout\n"
- " -l: LPC device configuration\n"
- " -m: memory size\n"
- " -o: set config 'var' to 'value'\n"
- " -P: vmexit from the guest on pause\n"
- " -p: pin 'vcpu' to 'hostcpu'\n"
-#ifdef BHYVE_SNAPSHOT
- " -r: path to checkpoint file\n"
-#endif
- " -S: guest memory cannot be swapped\n"
- " -s: <slot,driver,configinfo> PCI slot config\n"
- " -U: UUID\n"
- " -u: RTC keeps UTC time\n"
- " -W: force virtio to use single-vector MSI\n"
- " -w: ignore unimplemented MSRs\n"
- " -x: local APIC is in x2APIC mode\n"
- " -Y: disable MPtable generation\n",
- progname, (int)strlen(progname), "", (int)strlen(progname), "",
- (int)strlen(progname), "");
-
- exit(code);
-}
-
/*
* XXX This parser is known to have the following issues:
* 1. It accepts null key=value tokens ",," as setting "cpus" to an
@@ -165,8 +122,8 @@ usage(int code)
* The acceptance of a null specification ('-c ""') is by design to match the
* manual page syntax specification, this results in a topology of 1 vCPU.
*/
-static int
-topology_parse(const char *opt)
+int
+bhyve_topology_parse(const char *opt)
{
char *cp, *str, *tofree;
@@ -275,8 +232,8 @@ calc_topology(void)
guest_ncpus = ncpus;
}
-static int
-pincpu_parse(const char *opt)
+int
+bhyve_pincpu_parse(const char *opt)
{
const char *value;
char *newval;
@@ -619,8 +576,8 @@ do_open(const char *vmname)
return (ctx);
}
-static bool
-parse_config_option(const char *option)
+bool
+bhyve_parse_config_option(const char *option)
{
const char *value;
char *path;
@@ -635,8 +592,8 @@ parse_config_option(const char *option)
return (true);
}
-static void
-parse_simple_config_file(const char *path)
+void
+bhyve_parse_simple_config_file(const char *path)
{
FILE *fp;
char *line, *cp;
@@ -655,7 +612,7 @@ parse_simple_config_file(const char *path)
cp = strchr(line, '\n');
if (cp != NULL)
*cp = '\0';
- if (!parse_config_option(line))
+ if (!bhyve_parse_config_option(line))
errx(4, "%s line %u: invalid config option '%s'", path,
lineno, line);
}
@@ -664,8 +621,8 @@ parse_simple_config_file(const char *path)
}
#ifdef BHYVE_GDB
-static void
-parse_gdb_options(const char *opt)
+void
+bhyve_parse_gdb_options(const char *opt)
{
const char *sport;
char *colon;
@@ -692,12 +649,12 @@ parse_gdb_options(const char *opt)
int
main(int argc, char *argv[])
{
- int c, error;
+ int error;
int max_vcpus, memflags;
struct vcpu *bsp;
struct vmctx *ctx;
size_t memsize;
- const char *optstr, *value, *vmname;
+ const char *value, *vmname;
#ifdef BHYVE_SNAPSHOT
char *restore_file;
struct restore_state rstate;
@@ -706,149 +663,12 @@ main(int argc, char *argv[])
#endif
bhyve_init_config();
-
- progname = basename(argv[0]);
-
-#ifdef BHYVE_SNAPSHOT
- optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:";
-#else
- optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:";
-#endif
- while ((c = getopt(argc, argv, optstr)) != -1) {
- switch (c) {
-#ifdef __amd64__
- case 'a':
- set_config_bool("x86.x2apic", false);
- break;
-#endif
- case 'A':
- /*
- * NOP. For backward compatibility. Most systems don't
- * work properly without sane ACPI tables. Therefore,
- * we're always generating them.
- */
- break;
- case 'D':
- set_config_bool("destroy_on_poweroff", true);
- break;
- case 'p':
- if (pincpu_parse(optarg) != 0) {
- errx(EX_USAGE, "invalid vcpu pinning "
- "configuration '%s'", optarg);
- }
- break;
- case 'c':
- if (topology_parse(optarg) != 0) {
- errx(EX_USAGE, "invalid cpu topology "
- "'%s'", optarg);
- }
- break;
- case 'C':
- set_config_bool("memory.guest_in_core", true);
- break;
- case 'f':
- if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) {
- errx(EX_USAGE, "invalid fwcfg item '%s'", optarg);
- }
- break;
-#ifdef BHYVE_GDB
- case 'G':
- parse_gdb_options(optarg);
- break;
-#endif
- case 'k':
- parse_simple_config_file(optarg);
- break;
- case 'K':
- set_config_value("keyboard.layout", optarg);
- break;
-#ifdef __amd64__
- case 'l':
- if (strncmp(optarg, "help", strlen(optarg)) == 0) {
- lpc_print_supported_devices();
- exit(0);
- } else if (lpc_device_parse(optarg) != 0) {
- errx(EX_USAGE, "invalid lpc device "
- "configuration '%s'", optarg);
- }
- break;
-#endif
-#ifdef BHYVE_SNAPSHOT
- case 'r':
- restore_file = optarg;
- break;
-#endif
- case 's':
- if (strncmp(optarg, "help", strlen(optarg)) == 0) {
- pci_print_supported_devices();
- exit(0);
- } else if (pci_parse_slot(optarg) != 0)
- exit(4);
- else
- break;
- case 'S':
- set_config_bool("memory.wired", true);
- break;
- case 'm':
- set_config_value("memory.size", optarg);
- break;
- case 'o':
- if (!parse_config_option(optarg))
- errx(EX_USAGE, "invalid configuration option '%s'", optarg);
- break;
-#ifdef __amd64__
- case 'H':
- set_config_bool("x86.vmexit_on_hlt", true);
- break;
- case 'I':
- /*
- * The "-I" option was used to add an ioapic to the
- * virtual machine.
- *
- * An ioapic is now provided unconditionally for each
- * virtual machine and this option is now deprecated.
- */
- break;
- case 'P':
- set_config_bool("x86.vmexit_on_pause", true);
- break;
- case 'e':
- set_config_bool("x86.strictio", true);
- break;
- case 'u':
- set_config_bool("rtc.use_localtime", false);
- break;
-#endif
- case 'U':
- set_config_value("uuid", optarg);
- break;
-#ifdef __amd64__
- case 'w':
- set_config_bool("x86.strictmsr", false);
- break;
-#endif
- case 'W':
- set_config_bool("virtio_msix", false);
- break;
-#ifdef __amd64__
- case 'x':
- set_config_bool("x86.x2apic", true);
- break;
- case 'Y':
- set_config_bool("x86.mptable", false);
- break;
-#endif
- case 'h':
- usage(0);
- default:
- usage(1);
- }
- }
+ bhyve_optparse(argc, argv);
argc -= optind;
argv += optind;
if (argc > 1)
- usage(1);
+ bhyve_usage(1);
#ifdef BHYVE_SNAPSHOT
if (restore_file != NULL) {
@@ -869,7 +689,7 @@ main(int argc, char *argv[])
vmname = get_config_value("name");
if (vmname == NULL)
- usage(1);
+ bhyve_usage(1);
if (get_config_bool_default("config.dump", false)) {
dump_config();
diff --git a/usr.sbin/bhyve/bhyverun.h b/usr.sbin/bhyve/bhyverun.h
index 5fe97ca07f0b..e6ff90e5daa0 100644
--- a/usr.sbin/bhyve/bhyverun.h
+++ b/usr.sbin/bhyve/bhyverun.h
@@ -58,6 +58,18 @@ typedef int (*vmexit_handler_t)(struct vmctx *, struct vcpu *, struct vm_run *);
/* Interfaces implemented by machine-dependent code. */
void bhyve_init_config(void);
+void bhyve_optparse(int argc, char **argv);
+void bhyve_usage(int code);
+
+/* Interfaces used by command-line option-parsing code. */
+bool bhyve_parse_config_option(const char *option);
+void bhyve_parse_simple_config_file(const char *path);
+#ifdef BHYVE_GDB
+void bhyve_parse_gdb_options(const char *opt);
+#endif
+int bhyve_pincpu_parse(const char *opt);
+int bhyve_topology_parse(const char *opt);
+
void bhyve_init_vcpu(struct vcpu *vcpu);
void bhyve_start_vcpu(struct vcpu *vcpu, bool bsp);
int bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp);