diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c --- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include #include #include @@ -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 @@ 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: 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 --- a/usr.sbin/bhyve/amd64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/amd64/bhyverun_machdep.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -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 @@ 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: 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.h b/usr.sbin/bhyve/bhyverun.h --- a/usr.sbin/bhyve/bhyverun.h +++ b/usr.sbin/bhyve/bhyverun.h @@ -58,6 +58,18 @@ /* 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); diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -100,7 +100,6 @@ int raw_stdio = 0; -static char *progname; static const int BSP = 0; static cpuset_t cpumask; @@ -115,48 +114,6 @@ 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: 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } #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 @@ 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 @@ #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 @@ vmname = get_config_value("name"); if (vmname == NULL) - usage(1); + bhyve_usage(1); if (get_config_bool_default("config.dump", false)) { dump_config();