diff options
Diffstat (limited to 'usr/src/cmd')
57 files changed, 2501 insertions, 2002 deletions
diff --git a/usr/src/cmd/bhyve/Makefile b/usr/src/cmd/bhyve/Makefile index 1c1b99c52b..662a155ec5 100644 --- a/usr/src/cmd/bhyve/Makefile +++ b/usr/src/cmd/bhyve/Makefile @@ -13,6 +13,7 @@ # Copyright 2014 Pluribus Networks Inc. # Copyright 2020 Joyent, Inc. # Copyright 2020 Oxide Computer Company +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. # PROG = bhyve @@ -35,8 +36,7 @@ SRCS = acpi.c \ block_if.c \ bootrom.c \ console.c \ - consport.c \ - dbgport.c \ + config.c \ fwctl.c \ gdb.c \ inout.c \ @@ -125,13 +125,17 @@ CPPFLAGS = -I$(COMPAT)/bhyve -I$(CONTRIB)/bhyve \ -DWITHOUT_CAPSICUM pci_nvme.o := CERRWARN += -_gcc=-Wno-pointer-sign +pci_nvme.o := CERRWARN += -_gcc10=-Wno-address-of-packed-member pci_nvme.o := SMOFF += kmalloc_wrong_size +pci_passthru.o := CERRWARN += -_gcc10=-Wno-address-of-packed-member + +pci_xhci.o := CERRWARN += -_gcc10=-Wno-address-of-packed-member + SMOFF += all_func_returns,leaks,no_if_block # Force c99 for everything CSTD= $(CSTD_GNU99) -C99MODE= -xc99=%all $(PROG) := LDLIBS += \ -lsocket \ @@ -139,6 +143,7 @@ $(PROG) := LDLIBS += \ -ldlpi \ -ldladm \ -lmd \ + -lnvpair \ -lcrypto \ -luuid \ -lvmmapi \ diff --git a/usr/src/cmd/bhyve/README.sync b/usr/src/cmd/bhyve/README.sync index 2384413853..bed6671c73 100644 --- a/usr/src/cmd/bhyve/README.sync +++ b/usr/src/cmd/bhyve/README.sync @@ -4,18 +4,18 @@ public Git repository at https://git.freebsd.org/src.git The bhyve kernel module and its associated userland consumers have been updated to the latest upstream FreeBSD sources as of: -commit 2bb4be0f86501ec0565dba3d37ce0f7d7fc9c464 -Author: grehan <grehan@FreeBSD.org> -Date: Fri Dec 18 00:38:48 2020 +0000 - - Fix issues with various VNC clients. - - PR: 250795 - Submitted by: Marko Kiiskila <marko@apache.org> - Reviewed by: jhb (bhyve) - MFC after: 3 weeks - Relnotes: yes - Differential Revision: https://reviews.freebsd.org/D27605 +commit 9f40a3be3d5dbddf782c3d1eeaadcd022a4dad01 +Author: John Baldwin <jhb@FreeBSD.org> +Date: Wed Mar 24 09:29:15 2021 -0700 + + bhyve hostbridge: Rename "device" property to "devid". + + "device" is already used as the generic PCI-level name of the device + model to use (e.g. "hostbridge"). The result was that parsing + "hostbridge" as an integer failed and the host bridge used a device ID + of 0. The EFI ROM asserts that the device ID of the hostbridge is not + 0, so booting with the current EFI ROM was failing during the ROM + boot. Divergence Notes: diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c index 53a92f6dd7..3e2a72ced8 100644 --- a/usr/src/cmd/bhyve/bhyverun.c +++ b/usr/src/cmd/bhyve/bhyverun.c @@ -90,8 +90,8 @@ __FBSDID("$FreeBSD$"); #include "atkbdc.h" #include "console.h" #include "bootrom.h" +#include "config.h" #include "inout.h" -#include "dbgport.h" #include "debug.h" #include "fwctl.h" #include "gdb.h" @@ -186,26 +186,11 @@ static const char * const vmx_exit_reason_desc[] = { typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu); extern int vmexit_task_switch(struct vmctx *, struct vm_exit *, int *vcpu); -char *vmname; - int guest_ncpus; uint16_t cores, maxcpus, sockets, threads; -char *guest_uuid_str; - int raw_stdio = 0; -static int gdb_port = 0; -static int guest_vmexit_on_hlt, guest_vmexit_on_pause; -static int virtio_msix = 1; -static int x2apic_mode = 0; /* default is xAPIC */ -static int destroy_on_poweroff = 0; - -static int strictio; -static int strictmsr = 1; - -static int acpi; - static char *progname; static const int BSP = 0; @@ -246,16 +231,16 @@ usage(int code) fprintf(stderr, #ifdef __FreeBSD__ - "Usage: %s [-abehuwxACDHPSWY]\n" + "Usage: %s [-aehuwxACDHPSWY]\n" #else - "Usage: %s [-abdehuwxACDHPSWY]\n" + "Usage: %s [-adehuwxACDHPSWY]\n" #endif " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n" - " %*s [-g <gdb port>] [-l <lpc>]\n" + " %*s [-k <file>] [-l <lpc>] [-m mem] [-o <var>=<value>]\n" #ifdef __FreeBSD__ - " %*s [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] <vm>\n" + " %*s [-p vcpu:hostcpu] [-s <pci>] [-U uuid] [<vm>]\n" #else - " %*s [-m mem] [-s <pci>] [-U uuid] <vm>\n" + " %*s [-s <pci>] [-U uuid] [<vm>]\n" #endif " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create ACPI tables\n" @@ -266,11 +251,12 @@ usage(int code) #endif " -D: destroy on power-off\n" " -e: exit on unhandled I/O access\n" - " -g: gdb port\n" " -h: help\n" " -H: vmexit from the guest on hlt\n" + " -k: key=value flat config file\n" " -l: LPC device configuration\n" " -m: memory size\n" + " -o: set config 'var' to 'value'\n" #ifdef __FreeBSD__ " -p: pin 'vcpu' to 'hostcpu'\n" #endif @@ -291,11 +277,8 @@ usage(int code) /* * XXX This parser is known to have the following issues: - * 1. It accepts null key=value tokens ",,". - * 2. It accepts whitespace after = and before value. - * 3. Values out of range of INT are silently wrapped. - * 4. It doesn't check non-final values. - * 5. The apparently bogus limits of UINT16_MAX are for future expansion. + * 1. It accepts null key=value tokens ",," as setting "cpus" to an + * empty string. * * 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. @@ -303,80 +286,116 @@ usage(int code) static int topology_parse(const char *opt) { - uint64_t ncpus; - int c, chk, n, s, t, tmp; char *cp, *str; - bool ns, scts; - c = 1, n = 1, s = 1, t = 1; - ns = false, scts = false; + if (*opt == '\0') { + set_config_value("sockets", "1"); + set_config_value("cores", "1"); + set_config_value("threads", "1"); + set_config_value("cpus", "1"); + return (0); + } + str = strdup(opt); if (str == NULL) - goto out; + errx(4, "Failed to allocate memory"); while ((cp = strsep(&str, ",")) != NULL) { - if (sscanf(cp, "%i%n", &tmp, &chk) == 1) { - n = tmp; - ns = true; - } else if (sscanf(cp, "cpus=%i%n", &tmp, &chk) == 1) { - n = tmp; - ns = true; - } else if (sscanf(cp, "sockets=%i%n", &tmp, &chk) == 1) { - s = tmp; - scts = true; - } else if (sscanf(cp, "cores=%i%n", &tmp, &chk) == 1) { - c = tmp; - scts = true; - } else if (sscanf(cp, "threads=%i%n", &tmp, &chk) == 1) { - t = tmp; - scts = true; + if (strncmp(cp, "cpus=", strlen("cpus=")) == 0) + set_config_value("cpus", cp + strlen("cpus=")); + else if (strncmp(cp, "sockets=", strlen("sockets=")) == 0) + set_config_value("sockets", cp + strlen("sockets=")); + else if (strncmp(cp, "cores=", strlen("cores=")) == 0) + set_config_value("cores", cp + strlen("cores=")); + else if (strncmp(cp, "threads=", strlen("threads=")) == 0) + set_config_value("threads", cp + strlen("threads=")); #ifdef notyet /* Do not expose this until vmm.ko implements it */ - } else if (sscanf(cp, "maxcpus=%i%n", &tmp, &chk) == 1) { - m = tmp; + else if (strncmp(cp, "maxcpus=", strlen("maxcpus=")) == 0) + set_config_value("maxcpus", cp + strlen("maxcpus=")); #endif - /* Skip the empty argument case from -c "" */ - } else if (cp[0] == '\0') - continue; - else - goto out; - /* Any trailing garbage causes an error */ - if (cp[chk] != '\0') + else if (strchr(cp, '=') != NULL) goto out; + else + set_config_value("cpus", cp); } free(str); - str = NULL; - - /* - * Range check 1 <= n <= UINT16_MAX all values - */ - if (n < 1 || s < 1 || c < 1 || t < 1 || - n > UINT16_MAX || s > UINT16_MAX || c > UINT16_MAX || - t > UINT16_MAX) - return (-1); - - /* If only the cpus was specified, use that as sockets */ - if (!scts) - s = n; - /* - * Compute sockets * cores * threads avoiding overflow - * The range check above insures these are 16 bit values - * If n was specified check it against computed ncpus - */ - ncpus = (uint64_t)s * c * t; - if (ncpus > UINT16_MAX || (ns && n != ncpus)) - return (-1); - - guest_ncpus = ncpus; - sockets = s; - cores = c; - threads = t; - return(0); + return (0); out: free(str); return (-1); } +static int +parse_int_value(const char *key, const char *value, int minval, int maxval) +{ + char *cp; + long lval; + + errno = 0; + lval = strtol(value, &cp, 0); + if (errno != 0 || *cp != '\0' || cp == value || lval < minval || + lval > maxval) + errx(4, "Invalid value for %s: '%s'", key, value); + return (lval); +} + +/* + * Set the sockets, cores, threads, and guest_cpus variables based on + * the configured topology. + * + * The limits of UINT16_MAX are due to the types passed to + * vm_set_topology(). vmm.ko may enforce tighter limits. + */ +static void +calc_topolopgy(void) +{ + const char *value; + bool explicit_cpus; + uint64_t ncpus; + + value = get_config_value("cpus"); + if (value != NULL) { + guest_ncpus = parse_int_value("cpus", value, 1, UINT16_MAX); + explicit_cpus = true; + } else { + guest_ncpus = 1; + explicit_cpus = false; + } + value = get_config_value("cores"); + if (value != NULL) + cores = parse_int_value("cores", value, 1, UINT16_MAX); + else + cores = 1; + value = get_config_value("threads"); + if (value != NULL) + threads = parse_int_value("threads", value, 1, UINT16_MAX); + else + threads = 1; + value = get_config_value("sockets"); + if (value != NULL) + sockets = parse_int_value("sockets", value, 1, UINT16_MAX); + else + sockets = guest_ncpus; + + /* + * Compute sockets * cores * threads avoiding overflow. The + * range check above insures these are 16 bit values. + */ + ncpus = (uint64_t)sockets * cores * threads; + if (ncpus > UINT16_MAX) + errx(4, "Computed number of vCPUs too high: %ju", + (uintmax_t)ncpus); + + if (explicit_cpus) { + if (guest_ncpus != ncpus) + errx(4, "Topology (%d sockets, %d cores, %d threads) " + "does not match %d vCPUs", sockets, cores, threads, + guest_ncpus); + } else + guest_ncpus = ncpus; +} + #ifndef WITHOUT_CAPSICUM /* * 11-stable capsicum helpers @@ -437,17 +456,85 @@ pincpu_parse(const char *opt) return (-1); } - if (vcpumap[vcpu] == NULL) { - if ((vcpumap[vcpu] = malloc(sizeof(cpuset_t))) == NULL) { - perror("malloc"); - return (-1); - } - CPU_ZERO(vcpumap[vcpu]); + snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu); + value = get_config_value(key); + + if (asprintf(&newval, "%s%s%d", value != NULL ? value : "", + value != NULL ? "," : "", pcpu) == -1) { + perror("failed to build new cpuset string"); + return (-1); } - CPU_SET(pcpu, vcpumap[vcpu]); + + set_config_value(key, newval); + free(newval); return (0); } +static void +parse_cpuset(int vcpu, const char *list, cpuset_t *set) +{ + char *cp, *token; + int pcpu, start; + + CPU_ZERO(set); + start = -1; + token = __DECONST(char *, list); + for (;;) { + pcpu = strtoul(token, &cp, 0); + if (cp == token) + errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list); + if (pcpu < 0 || pcpu >= CPU_SETSIZE) + errx(4, "hostcpu '%d' outside valid range from 0 to %d", + pcpu, CPU_SETSIZE - 1); + switch (*cp) { + case ',': + case '\0': + if (start >= 0) { + if (start > pcpu) + errx(4, "Invalid hostcpu range %d-%d", + start, pcpu); + while (start < pcpu) { + CPU_SET(start, vcpumap[vcpu]); + start++; + } + start = -1; + } + CPU_SET(pcpu, vcpumap[vcpu]); + break; + case '-': + if (start >= 0) + errx(4, "invalid cpuset for vcpu %d: '%s'", + vcpu, list); + start = pcpu; + break; + default: + errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list); + } + if (*cp == '\0') + break; + token = cp + 1; + } +} + +static void +build_vcpumaps(void) +{ + char key[16]; + const char *value; + int vcpu; + + for (vcpu = 0; vcpu < guest_ncpus; vcpu++) { + snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu); + value = get_config_value(key); + if (value == NULL) + continue; + vcpumap[vcpu] = malloc(sizeof(cpuset_t)); + if (vcpumap[vcpu] == NULL) + err(4, "Failed to allocate cpuset for vcpu %d", vcpu); + parse_cpuset(vcpu, value, vcpumap[vcpu]); + } +} + void vm_inject_fault(void *arg, int vcpu, int vector, int errcode_valid, int errcode) @@ -472,24 +559,10 @@ paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len) } int -fbsdrun_vmexit_on_pause(void) -{ - - return (guest_vmexit_on_pause); -} - -int -fbsdrun_vmexit_on_hlt(void) -{ - - return (guest_vmexit_on_hlt); -} - -int fbsdrun_virtio_msix(void) { - return (virtio_msix); + return (get_config_bool_default("virtio_msix", true)); } static void * @@ -505,8 +578,7 @@ fbsdrun_start_thread(void *param) snprintf(tname, sizeof(tname), "vcpu %d", vcpu); pthread_set_name_np(mtp->mt_thr, tname); - if (gdb_port != 0) - gdb_cpu_add(vcpu); + gdb_cpu_add(vcpu); vm_loop(mtp->mt_ctx, vcpu, mtp->mt_startrip); @@ -667,7 +739,7 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) return (error); } - error = emulate_inout(ctx, vcpu, &inout, strictio != 0); + error = emulate_inout(ctx, vcpu, &inout); if (error) { fprintf(stderr, "Unhandled %s%c 0x%04x at 0x%lx\n", in ? "in" : "out", @@ -700,7 +772,7 @@ vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) if (error != 0) { fprintf(stderr, "rdmsr to register %#x on vcpu %d\n", vme->u.msr.code, *pvcpu); - if (strictmsr) { + if (get_config_bool("x86.strictmsr")) { vm_inject_gp(ctx, *pvcpu); return (VMEXIT_CONTINUE); } @@ -726,7 +798,7 @@ vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) if (error != 0) { fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n", vme->u.msr.code, vme->u.msr.wval, *pvcpu); - if (strictmsr) { + if (get_config_bool("x86.strictmsr")) { vm_inject_gp(ctx, *pvcpu); return (VMEXIT_CONTINUE); } @@ -880,11 +952,8 @@ vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) stats.vmexit_mtrap++; - if (gdb_port == 0) { - fprintf(stderr, "vm_loop: unexpected VMEXIT_MTRAP\n"); - exit(4); - } gdb_cpu_mtrap(*pvcpu); + return (VMEXIT_CONTINUE); } @@ -986,7 +1055,7 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) case VM_SUSPEND_RESET: exit(0); case VM_SUSPEND_POWEROFF: - if (destroy_on_poweroff) + if (get_config_bool_default("destroy_on_poweroff", false)) vm_destroy(ctx); exit(1); case VM_SUSPEND_HALT: @@ -1004,10 +1073,6 @@ static int vmexit_debug(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { - if (gdb_port == 0) { - fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n"); - exit(4); - } gdb_cpu_suspend(*pvcpu); return (VMEXIT_CONTINUE); } @@ -1016,10 +1081,6 @@ static int vmexit_breakpoint(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { - if (gdb_port == 0) { - fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n"); - exit(4); - } gdb_cpu_breakpoint(*pvcpu, vmexit); return (VMEXIT_CONTINUE); } @@ -1132,7 +1193,7 @@ fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) { int err, tmp; - if (fbsdrun_vmexit_on_hlt()) { + if (get_config_bool_default("x86.vmexit_on_hlt", false)) { err = vm_get_capability(ctx, cpu, VM_CAP_HALT_EXIT, &tmp); if (err < 0) { fprintf(stderr, "VM exit on HLT not supported\n"); @@ -1143,7 +1204,7 @@ fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) handler[VM_EXITCODE_HLT] = vmexit_hlt; } - if (fbsdrun_vmexit_on_pause()) { + if (get_config_bool_default("x86.vmexit_on_pause", false)) { /* * pause exit support required for this mode */ @@ -1158,7 +1219,7 @@ fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) handler[VM_EXITCODE_PAUSE] = vmexit_pause; } - if (x2apic_mode) + if (get_config_bool_default("x86.x2apic", false)) err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED); else err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED); @@ -1248,63 +1309,103 @@ do_open(const char *vmname) return (ctx); } +static bool +parse_config_option(const char *option) +{ + const char *value; + char *path; + + value = strchr(option, '='); + if (value == NULL || value[1] == '\0') + return (false); + path = strndup(option, value - option); + if (path == NULL) + err(4, "Failed to allocate memory"); + set_config_value(path, value + 1); + return (true); +} + +static void +parse_simple_config_file(const char *path) +{ + FILE *fp; + char *line, *cp; + size_t linecap; + unsigned int lineno; + + fp = fopen(path, "r"); + if (fp == NULL) + err(4, "Failed to open configuration file %s", path); + line = NULL; + linecap = 0; + lineno = 1; + for (lineno = 1; getline(&line, &linecap, fp) > 0; lineno++) { + if (*line == '#' || *line == '\n') + continue; + cp = strchr(line, '\n'); + if (cp != NULL) + *cp = '\0'; + if (!parse_config_option(line)) + errx(4, "%s line %u: invalid config option '%s'", path, + lineno, line); + } + free(line); + fclose(fp); +} + +static void +set_defaults(void) +{ + + set_config_bool("acpi_tables", false); + set_config_value("memory.size", "256M"); + set_config_bool("x86.strictmsr", true); +} + int main(int argc, char *argv[]) { - int c, error, dbg_port, err, bvmcons; - int max_vcpus, mptgen, memflags; - int rtc_localtime; - bool gdb_stop; -#ifndef __FreeBSD__ - bool suspend = false; -#endif + int c, error, err; + int max_vcpus, memflags; struct vmctx *ctx; uint64_t rip; size_t memsize; + const char *value, *vmname; char *optstr; - bvmcons = 0; + init_config(); + set_defaults(); progname = basename(argv[0]); - dbg_port = 0; - gdb_stop = false; - guest_ncpus = 1; - sockets = cores = threads = 1; - maxcpus = 0; - memsize = 256 * MB; - mptgen = 1; - rtc_localtime = 1; - memflags = 0; #ifdef __FreeBSD__ - optstr = "abehuwxACDHIPSWYp:g:G:c:s:m:l:B:U:"; + optstr = "aehuwxACDHIPSWYk:o:p:G:c:s:m:l:U:"; #else - optstr = "abdehuwxACDHIPSWYg:G:c:s:m:l:B:U:"; + /* +d, +B, -p */ + optstr = "adehuwxACDHIPSWYk:o:G:c:s:m:l:B:U:"; #endif while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'a': - x2apic_mode = 0; + set_config_bool("x86.x2apic", false); break; case 'A': - acpi = 1; - break; - case 'b': - bvmcons = 1; + set_config_bool("acpi_tables", true); break; case 'D': - destroy_on_poweroff = 1; + set_config_bool("destroy_on_poweroff", true); break; +#ifndef __FreeBSD__ case 'B': if (smbios_parse(optarg) != 0) { errx(EX_USAGE, "invalid SMBIOS " "configuration '%s'", optarg); } break; -#ifndef __FreeBSD__ case 'd': - suspend = true; + set_config_bool("suspend_at_boot", true); break; -#else +#endif +#ifdef __FreeBSD__ case 'p': if (pincpu_parse(optarg) != 0) { errx(EX_USAGE, "invalid vcpu pinning " @@ -1319,17 +1420,17 @@ main(int argc, char *argv[]) } break; case 'C': - memflags |= VM_MEM_F_INCORE; - break; - case 'g': - dbg_port = atoi(optarg); + set_config_bool("memory.guest_in_core", true); break; case 'G': if (optarg[0] == 'w') { - gdb_stop = true; + set_config_bool("gdb.wait", true); optarg++; } - gdb_port = atoi(optarg); + set_config_value("gdb.port", optarg); + break; + case 'k': + parse_simple_config_file(optarg); break; case 'l': if (strncmp(optarg, "help", strlen(optarg)) == 0) { @@ -1349,15 +1450,17 @@ main(int argc, char *argv[]) else break; case 'S': - memflags |= VM_MEM_F_WIRED; + set_config_bool("memory.wired", true); break; case 'm': - error = vm_parse_memsize(optarg, &memsize); - if (error) - errx(EX_USAGE, "invalid memsize '%s'", optarg); + set_config_value("memory.size", optarg); + break; + case 'o': + if (!parse_config_option(optarg)) + errx(EX_USAGE, "invalid configuration option '%s'", optarg); break; case 'H': - guest_vmexit_on_hlt = 1; + set_config_bool("x86.vmexit_on_hlt", true); break; case 'I': /* @@ -1369,28 +1472,28 @@ main(int argc, char *argv[]) */ break; case 'P': - guest_vmexit_on_pause = 1; + set_config_bool("x86.vmexit_on_pause", true); break; case 'e': - strictio = 1; + set_config_bool("x86.strictio", true); break; case 'u': - rtc_localtime = 0; + set_config_bool("rtc.use_localtime", false); break; case 'U': - guest_uuid_str = optarg; + set_config_value("uuid", optarg); break; case 'w': - strictmsr = 0; + set_config_bool("x86.strictmsr", false); break; case 'W': - virtio_msix = 0; + set_config_bool("virtio_msix", false); break; case 'x': - x2apic_mode = 1; + set_config_bool("x86.x2apic", true); break; case 'Y': - mptgen = 0; + set_config_bool("x86.mptable", false); break; case 'h': usage(0); @@ -1401,14 +1504,35 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (argc != 1) + if (argc > 1) + usage(1); + + if (argc == 1) + set_config_value("name", argv[0]); + + vmname = get_config_value("name"); + if (vmname == NULL) usage(1); - vmname = argv[0]; + if (get_config_bool_default("config.dump", false)) { + dump_config(); + exit(1); + } + + calc_topolopgy(); +#ifdef __FreeBSD__ + build_vcpumaps(); +#endif + + value = get_config_value("memory.size"); + error = vm_parse_memsize(value, &memsize); + if (error) + errx(EX_USAGE, "invalid memsize '%s'", value); + ctx = do_open(vmname); - max_vcpus = num_vcpus_allowed(ctx); - if (guest_ncpus > max_vcpus) { + max_vcpus = num_vcpus_allowed(ctx); + if (guest_ncpus > max_vcpus) { fprintf(stderr, "%d vCPUs requested but only %d available\n", guest_ncpus, max_vcpus); exit(4); @@ -1416,6 +1540,11 @@ main(int argc, char *argv[]) fbsdrun_set_capabilities(ctx, BSP); + memflags = 0; + if (get_config_bool_default("memory.wired", false)) + memflags |= VM_MEM_F_WIRED; + if (get_config_bool_default("memory.guest_in_core", false)) + memflags |= VM_MEM_F_INCORE; vm_set_memflags(ctx, memflags); #ifdef __FreeBSD__ err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL); @@ -1432,7 +1561,7 @@ main(int argc, char *argv[]) } while (error == ENOMEM); #endif if (err) { - fprintf(stderr, "Unable to setup memory (%d)\n", errno); + fprintf(stderr, "Unable to set up memory (%d)\n", errno); exit(4); } @@ -1452,7 +1581,7 @@ main(int argc, char *argv[]) pci_irq_init(ctx); ioapic_init(ctx); - rtc_init(ctx, rtc_localtime); + rtc_init(ctx); sci_init(ctx); #ifndef __FreeBSD__ pmtmr_init(ctx); @@ -1470,30 +1599,28 @@ main(int argc, char *argv[]) * Initialize after PCI, to allow a bootrom file to reserve the high * region. */ - if (acpi) + if (get_config_bool("acpi_tables")) vmgenc_init(ctx); - if (dbg_port != 0) - init_dbgport(dbg_port); - + value = get_config_value("gdb.port"); #ifdef __FreeBSD__ - if (gdb_port != 0) - init_gdb(ctx, gdb_port, gdb_stop); + if (value != NULL) + init_gdb(ctx, atoi(value), get_config_bool_default("gdb.wait", + false)); #else - if (gdb_port < 0) { - /* - * Set up the internal gdb state needed for basic debugging, but - * skip the step of listening on a port for the GDB server. - */ - init_mdb(ctx, gdb_stop); - } else if (gdb_port != 0) { - init_gdb(ctx, gdb_port, gdb_stop); + if (value != NULL) { + int port = atoi(value); + + if (port < 0) { + init_mdb(ctx, + get_config_bool_default("gdb.wait", false)); + } else { + init_gdb(ctx, port, + get_config_bool_default("gdb.wait", false)); + } } #endif - if (bvmcons) - init_bvmcons(); - vga_init(1); if (lpc_bootrom()) { @@ -1516,7 +1643,7 @@ main(int argc, char *argv[]) /* * build the guest tables, MP etc. */ - if (mptgen) { + if (get_config_bool_default("x86.mptable", true)) { error = mptable_build(ctx, guest_ncpus); if (error) { perror("error to build the guest tables"); @@ -1524,10 +1651,13 @@ main(int argc, char *argv[]) } } +#ifndef __FreeBSD__ + smbios_apply(); +#endif error = smbios_build(ctx); assert(error == 0); - if (acpi) { + if (get_config_bool("acpi_tables")) { error = acpi_build(ctx, guest_ncpus); assert(error == 0); } @@ -1559,7 +1689,8 @@ main(int argc, char *argv[]) /* Set BSP to run (unlike the APs which wait for INIT) */ error = vm_set_run_state(ctx, BSP, VRS_RUN, 0); assert(error == 0); - fbsdrun_addcpu(ctx, BSP, rip, suspend); + fbsdrun_addcpu(ctx, BSP, rip, + get_config_bool_default("suspend_at_boot", false)); /* Add subsequent CPUs, which will wait until INIT/SIPI-ed */ for (uint_t i = 1; i < guest_ncpus; i++) { diff --git a/usr/src/cmd/bhyve/bhyverun.h b/usr/src/cmd/bhyve/bhyverun.h index f2582512ea..24ff115345 100644 --- a/usr/src/cmd/bhyve/bhyverun.h +++ b/usr/src/cmd/bhyve/bhyverun.h @@ -49,8 +49,6 @@ struct vmctx; extern int guest_ncpus; extern uint16_t cores, sockets, threads; -extern char *guest_uuid_str; -extern char *vmname; void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len); @@ -60,9 +58,6 @@ void fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip); #else void fbsdrun_addcpu(struct vmctx *ctx, int newcpu, uint64_t rip, bool suspend); #endif -int fbsdrun_muxed(void); -int fbsdrun_vmexit_on_hlt(void); -int fbsdrun_vmexit_on_pause(void); -int fbsdrun_disable_x2apic(void); int fbsdrun_virtio_msix(void); + #endif diff --git a/usr/src/cmd/bhyve/block_if.c b/usr/src/cmd/bhyve/block_if.c index 23a04c0f5b..f15ff1ae7b 100644 --- a/usr/src/cmd/bhyve/block_if.c +++ b/usr/src/cmd/bhyve/block_if.c @@ -69,10 +69,12 @@ __FBSDID("$FreeBSD$"); #include <machine/atomic.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #ifdef __FreeBSD__ #include "mevent.h" #endif +#include "pci_emul.h" #include "block_if.h" #define BLOCKIF_SIG 0xb109b109 @@ -488,16 +490,34 @@ blockif_init(void) #endif } +int +blockif_legacy_config(nvlist_t *nvl, const char *opts) +{ + char *cp, *path; + + if (opts == NULL) + return (0); + + cp = strchr(opts, ','); + if (cp == NULL) { + set_config_value_node(nvl, "path", opts); + return (0); + } + path = strndup(opts, cp - opts); + set_config_value_node(nvl, "path", path); + free(path); + return (pci_parse_legacy_config(nvl, cp + 1)); +} + struct blockif_ctxt * -blockif_open(const char *optstr, const char *ident) +blockif_open(nvlist_t *nvl, const char *ident) { char tname[MAXCOMLEN + 1]; #ifdef __FreeBSD__ char name[MAXPATHLEN]; - char *nopt, *xopts, *cp; -#else - char *nopt, *xopts, *cp = NULL; #endif + const char *path, *pssval, *ssval; + char *cp; struct blockif_ctxt *bc; struct stat sbuf; #ifdef __FreeBSD__ @@ -507,7 +527,7 @@ blockif_open(const char *optstr, const char *ident) #endif off_t size, psectsz, psectoff; int extra, fd, i, sectsz; - int nocache, sync, ro, candelete, geom, ssopt, pssopt; + int ro, candelete, geom, ssopt, pssopt; int nodelete; #ifndef WITHOUT_CAPSICUM @@ -518,59 +538,65 @@ blockif_open(const char *optstr, const char *ident) pthread_once(&blockif_once, blockif_init); fd = -1; + extra = 0; ssopt = 0; - nocache = 0; - sync = 0; +#ifndef __FreeBSD__ + pssopt = 0; +#endif ro = 0; nodelete = 0; - /* - * The first element in the optstring is always a pathname. - * Optional elements follow - */ - nopt = xopts = strdup(optstr); - while (xopts != NULL) { - cp = strsep(&xopts, ","); - if (cp == nopt) /* file or device pathname */ - continue; - else if (!strcmp(cp, "nocache")) - nocache = 1; - else if (!strcmp(cp, "nodelete")) - nodelete = 1; - else if (!strcmp(cp, "sync") || !strcmp(cp, "direct")) - sync = 1; - else if (!strcmp(cp, "ro")) - ro = 1; - else if (sscanf(cp, "sectorsize=%d/%d", &ssopt, &pssopt) == 2) - ; - else if (sscanf(cp, "sectorsize=%d", &ssopt) == 1) + if (get_config_bool_node_default(nvl, "nocache", false)) + extra |= O_DIRECT; + if (get_config_bool_node_default(nvl, "nodelete", false)) + nodelete = 1; + if (get_config_bool_node_default(nvl, "sync", false) || + get_config_bool_node_default(nvl, "direct", false)) + extra |= O_SYNC; + if (get_config_bool_node_default(nvl, "ro", false)) + ro = 1; + ssval = get_config_value_node(nvl, "sectorsize"); + if (ssval != NULL) { + ssopt = strtol(ssval, &cp, 10); + if (cp == ssval) { + EPRINTLN("Invalid sector size \"%s\"", ssval); + goto err; + } + if (*cp == '\0') { pssopt = ssopt; - else { - EPRINTLN("Invalid device option \"%s\"", cp); + } else if (*cp == '/') { + pssval = cp + 1; + pssopt = strtol(pssval, &cp, 10); + if (cp == pssval || *cp != '\0') { + EPRINTLN("Invalid sector size \"%s\"", ssval); + goto err; + } + } else { + EPRINTLN("Invalid sector size \"%s\"", ssval); goto err; } } - extra = 0; - if (nocache) - extra |= O_DIRECT; - if (sync) - extra |= O_SYNC; + path = get_config_value_node(nvl, "path"); + if (path == NULL) { + EPRINTLN("Missing \"path\" for block device."); + goto err; + } - fd = open(nopt, (ro ? O_RDONLY : O_RDWR) | extra); + fd = open(path, (ro ? O_RDONLY : O_RDWR) | extra); if (fd < 0 && !ro) { /* Attempt a r/w fail with a r/o open */ - fd = open(nopt, O_RDONLY | extra); + fd = open(path, O_RDONLY | extra); ro = 1; } if (fd < 0) { - warn("Could not open backing file: %s", nopt); + warn("Could not open backing file: %s", path); goto err; } if (fstat(fd, &sbuf) < 0) { - warn("Could not stat backing file %s", nopt); + warn("Could not stat backing file %s", path); goto err; } @@ -759,7 +785,6 @@ blockif_open(const char *optstr, const char *ident) err: if (fd >= 0) close(fd); - free(nopt); return (NULL); } diff --git a/usr/src/cmd/bhyve/block_if.h b/usr/src/cmd/bhyve/block_if.h index bff2b42768..d0a7f8812f 100644 --- a/usr/src/cmd/bhyve/block_if.h +++ b/usr/src/cmd/bhyve/block_if.h @@ -38,6 +38,7 @@ #ifndef _BLOCK_IF_H_ #define _BLOCK_IF_H_ +#include <sys/nv.h> #include <sys/uio.h> #include <sys/unistd.h> @@ -59,7 +60,8 @@ struct blockif_req { }; struct blockif_ctxt; -struct blockif_ctxt *blockif_open(const char *optstr, const char *ident); +int blockif_legacy_config(nvlist_t *nvl, const char *opts); +struct blockif_ctxt *blockif_open(nvlist_t *nvl, const char *ident); off_t blockif_size(struct blockif_ctxt *bc); void blockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h, uint8_t *s); diff --git a/usr/src/cmd/bhyve/config.c b/usr/src/cmd/bhyve/config.c new file mode 100644 index 0000000000..db28cc5516 --- /dev/null +++ b/usr/src/cmd/bhyve/config.c @@ -0,0 +1,439 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 John H. Baldwin <jhb@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" + +static nvlist_t *config_root; + +void +init_config(void) +{ + config_root = nvlist_create(0); + if (config_root == NULL) + err(4, "Failed to create configuration root nvlist"); +} + +static nvlist_t * +_lookup_config_node(nvlist_t *parent, const char *path, bool create) +{ + char *copy, *name, *tofree; + nvlist_t *nvl, *new_nvl; + + copy = strdup(path); + if (copy == NULL) + errx(4, "Failed to allocate memory"); + tofree = copy; + nvl = parent; + while ((name = strsep(©, ".")) != NULL) { + if (*name == '\0') { + warnx("Invalid configuration node: %s", path); + nvl = NULL; + break; + } + if (nvlist_exists_nvlist(nvl, name)) + nvl = (nvlist_t *)nvlist_get_nvlist(nvl, name); + else if (nvlist_exists(nvl, name)) { + for (copy = tofree; copy < name; copy++) + if (*copy == '\0') + *copy = '.'; + warnx( + "Configuration node %s is a child of existing variable %s", + path, tofree); + nvl = NULL; + break; + } else if (create) { + new_nvl = nvlist_create(0); + if (new_nvl == NULL) + errx(4, "Failed to allocate memory"); +#ifdef __FreeBSD__ + nvlist_move_nvlist(nvl, name, new_nvl); +#else + if (nvlist_add_nvlist(nvl, name, new_nvl) != 0) + errx(4, "Failed to allocate memory"); + (void) nvlist_free(new_nvl); + if (nvlist_lookup_nvlist(nvl, name, &new_nvl) != 0) + errx(4, "Failed to retrieve new nvlist"); +#endif + nvl = new_nvl; + } else { + nvl = NULL; + break; + } + } + free(tofree); + return (nvl); +} + +nvlist_t * +create_config_node(const char *path) +{ + + return (_lookup_config_node(config_root, path, true)); +} + +nvlist_t * +find_config_node(const char *path) +{ + + return (_lookup_config_node(config_root, path, false)); +} + +nvlist_t * +create_relative_config_node(nvlist_t *parent, const char *path) +{ + + return (_lookup_config_node(parent, path, true)); +} + +nvlist_t * +find_relative_config_node(nvlist_t *parent, const char *path) +{ + + return (_lookup_config_node(parent, path, false)); +} + +void +set_config_value_node(nvlist_t *parent, const char *name, const char *value) +{ + + if (strchr(name, '.') != NULL) + errx(4, "Invalid config node name %s", name); + if (parent == NULL) + parent = config_root; + if (nvlist_exists_string(parent, name)) + nvlist_free_string(parent, name); + else if (nvlist_exists(parent, name)) + errx(4, + "Attemping to add value %s to existing node %s of list %p", + value, name, parent); + nvlist_add_string(parent, name, value); +} + +void +set_config_value(const char *path, const char *value) +{ + const char *name; + char *node_name; + nvlist_t *nvl; + + /* Look for last separator. */ + name = strrchr(path, '.'); + if (name == NULL) { + nvl = config_root; + name = path; + } else { + node_name = strndup(path, name - path); + if (node_name == NULL) + errx(4, "Failed to allocate memory"); + nvl = create_config_node(node_name); + if (nvl == NULL) + errx(4, "Failed to create configuration node %s", + node_name); + free(node_name); + + /* Skip over '.'. */ + name++; + } + + if (nvlist_exists_nvlist(nvl, name)) + errx(4, "Attempting to add value %s to existing node %s", + value, path); + set_config_value_node(nvl, name, value); +} + +static const char * +get_raw_config_value(const char *path) +{ + const char *name; + char *node_name; + nvlist_t *nvl; + + /* Look for last separator. */ + name = strrchr(path, '.'); + if (name == NULL) { + nvl = config_root; + name = path; + } else { + node_name = strndup(path, name - path); + if (node_name == NULL) + errx(4, "Failed to allocate memory"); + nvl = find_config_node(node_name); + free(node_name); + if (nvl == NULL) + return (NULL); + + /* Skip over '.'. */ + name++; + } + + if (nvlist_exists_string(nvl, name)) + return (nvlist_get_string(nvl, name)); + if (nvlist_exists_nvlist(nvl, name)) + warnx("Attempting to fetch value of node %s", path); + return (NULL); +} + +static char * +_expand_config_value(const char *value, int depth) +{ + FILE *valfp; + const char *cp, *vp; + char *nestedval, *path, *valbuf; + size_t valsize; + + valfp = open_memstream(&valbuf, &valsize); + if (valfp == NULL) + errx(4, "Failed to allocate memory"); + + vp = value; + while (*vp != '\0') { + switch (*vp) { + case '%': + if (depth > 15) { + warnx( + "Too many recursive references in configuration value"); + fputc('%', valfp); + vp++; + break; + } + if (vp[1] != '(' || vp[2] == '\0') + cp = NULL; + else + cp = strchr(vp + 2, ')'); + if (cp == NULL) { + warnx( + "Invalid reference in configuration value \"%s\"", + value); + fputc('%', valfp); + vp++; + break; + } + vp += 2; + + if (cp == vp) { + warnx( + "Empty reference in configuration value \"%s\"", + value); + vp++; + break; + } + + /* Allocate a C string holding the path. */ + path = strndup(vp, cp - vp); + if (path == NULL) + errx(4, "Failed to allocate memory"); + + /* Advance 'vp' past the reference. */ + vp = cp + 1; + + /* Fetch the referenced value. */ + cp = get_raw_config_value(path); + if (cp == NULL) + warnx( + "Failed to fetch referenced configuration variable %s", + path); + else { + nestedval = _expand_config_value(cp, depth + 1); + fputs(nestedval, valfp); + free(nestedval); + } + free(path); + break; + case '\\': + vp++; + if (*vp == '\0') { + warnx( + "Trailing \\ in configuration value \"%s\"", + value); + break; + } + /* FALLTHROUGH */ + default: + fputc(*vp, valfp); + vp++; + break; + } + } + fclose(valfp); + return (valbuf); +} + +const char * +expand_config_value(const char *value) +{ + static char *valbuf; + + if (strchr(value, '%') == NULL) + return (value); + + free(valbuf); + valbuf = _expand_config_value(value, 0); + return (valbuf); +} + +const char * +get_config_value(const char *path) +{ + const char *value; + + value = get_raw_config_value(path); + if (value == NULL) + return (NULL); + return (expand_config_value(value)); +} + +const char * +get_config_value_node(const nvlist_t *parent, const char *name) +{ + + if (strchr(name, '.') != NULL) + errx(4, "Invalid config node name %s", name); + if (parent == NULL) + parent = config_root; + + if (nvlist_exists_nvlist(parent, name)) + warnx("Attempt to fetch value of node %s of list %p", name, + parent); + if (!nvlist_exists_string(parent, name)) + return (NULL); + + return (expand_config_value(nvlist_get_string(parent, name))); +} + +bool +_bool_value(const char *name, const char *value) +{ + + if (strcasecmp(value, "true") == 0 || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0 || + strcmp(value, "1") == 0) + return (true); + if (strcasecmp(value, "false") == 0 || + strcasecmp(value, "off") == 0 || + strcasecmp(value, "no") == 0 || + strcmp(value, "0") == 0) + return (false); + err(4, "Invalid value %s for boolean variable %s", value, name); +} + +bool +get_config_bool(const char *path) +{ + const char *value; + + value = get_config_value(path); + if (value == NULL) + err(4, "Failed to fetch boolean variable %s", path); + return (_bool_value(path, value)); +} + +bool +get_config_bool_default(const char *path, bool def) +{ + const char *value; + + value = get_config_value(path); + if (value == NULL) + return (def); + return (_bool_value(path, value)); +} + +bool +get_config_bool_node(const nvlist_t *parent, const char *name) +{ + const char *value; + + value = get_config_value_node(parent, name); + if (value == NULL) + err(4, "Failed to fetch boolean variable %s", name); + return (_bool_value(name, value)); +} + +bool +get_config_bool_node_default(const nvlist_t *parent, const char *name, + bool def) +{ + const char *value; + + value = get_config_value_node(parent, name); + if (value == NULL) + return (def); + return (_bool_value(name, value)); +} + +void +set_config_bool(const char *path, bool value) +{ + + set_config_value(path, value ? "true" : "false"); +} + +void +set_config_bool_node(nvlist_t *parent, const char *name, bool value) +{ + + set_config_value_node(parent, name, value ? "true" : "false"); +} + +static void +dump_tree(const char *prefix, const nvlist_t *nvl) +{ + const char *name; + void *cookie; + int type; + + cookie = NULL; + while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) { + if (type == NV_TYPE_NVLIST) { + char *new_prefix; + + asprintf(&new_prefix, "%s%s.", prefix, name); + dump_tree(new_prefix, nvlist_get_nvlist(nvl, name)); + free(new_prefix); + } else { + assert(type == NV_TYPE_STRING); + printf("%s%s=%s\n", prefix, name, + nvlist_get_string(nvl, name)); + } + } +} + +void +dump_config(void) +{ + dump_tree("", config_root); +} diff --git a/usr/src/cmd/bhyve/config.h b/usr/src/cmd/bhyve/config.h new file mode 100644 index 0000000000..9f82afb267 --- /dev/null +++ b/usr/src/cmd/bhyve/config.h @@ -0,0 +1,119 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 John H. Baldwin <jhb@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#include <sys/nv.h> + +/*- + * Manages a configuration database backed by an nv(9) list. + * + * The database only stores string values. Callers should parse + * values into other types if needed. String values can reference + * other configuration variables using a '%(name)' syntax. In this + * case, the name must be the the full path of the configuration + * variable. The % character can be escaped with a preceding \ to + * avoid expansion. Any \ characters must be escaped. + * + * Configuration variables are stored in a tree. The full path of a + * variable is specified as a dot-separated name similar to sysctl(8) + * OIDs. + */ + +/* + * Fetches the value of a configuration variable. If the "raw" value + * contains references to other configuration variables, this function + * expands those references and returns a pointer to the parsed + * string. The string's storage is only stable until the next call to + * this function. + * + * If no node is found, returns NULL. + * + * If 'parent' is NULL, 'name' is assumed to be a top-level variable. + */ +const char *get_config_value_node(const nvlist_t *parent, const char *name); + +/* + * Similar to get_config_value_node but expects a full path to the + * leaf node. + */ +const char *get_config_value(const char *path); + +/* Initializes the tree to an empty state. */ +void init_config(void); + +/* + * Creates an existing configuration node via a dot-separated OID + * path. Will fail if the path names an existing leaf configuration + * variable. If the node already exists, this returns a pointer to + * the existing node. + */ +nvlist_t *create_config_node(const char *path); + +/* + * Looks for an existing configuration node via a dot-separated OID + * path. Will fail if the path names an existing leaf configuration + * variable. + */ +nvlist_t *find_config_node(const char *path); + +/* + * Similar to the above, but treats the path relative to an existing + * 'parent' node rather than as an absolute path. + */ +nvlist_t *create_relative_config_node(nvlist_t *parent, const char *path); +nvlist_t *find_relative_config_node(nvlist_t *parent, const char *path); + +/* + * Adds or replaces the value of the specified variable. + * + * If 'parent' is NULL, 'name' is assumed to be a top-level variable. + */ +void set_config_value_node(nvlist_t *parent, const char *name, + const char *value); + +/* + * Similar to set_config_value_node but expects a full path to the + * leaf node. + */ +void set_config_value(const char *path, const char *value); + +/* Convenience wrappers for boolean variables. */ +bool get_config_bool(const char *path); +bool get_config_bool_node(const nvlist_t *parent, const char *name); +bool get_config_bool_default(const char *path, bool def); +bool get_config_bool_node_default(const nvlist_t *parent, const char *name, + bool def); +void set_config_bool(const char *path, bool value); +void set_config_bool_node(nvlist_t *parent, const char *name, bool value); + +void dump_config(void); + +#endif /* !__CONFIG_H__ */ diff --git a/usr/src/cmd/bhyve/consport.c b/usr/src/cmd/bhyve/consport.c deleted file mode 100644 index 42ba910f76..0000000000 --- a/usr/src/cmd/bhyve/consport.c +++ /dev/null @@ -1,182 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2011 NetApp, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#ifndef WITHOUT_CAPSICUM -#include <sys/capsicum.h> -#endif -#include <sys/select.h> - -#ifndef WITHOUT_CAPSICUM -#include <capsicum_helpers.h> -#endif -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <termios.h> -#include <unistd.h> -#include <stdbool.h> -#include <sysexits.h> - -#include "inout.h" -#include "pci_lpc.h" -#include "debug.h" - -#define BVM_CONSOLE_PORT 0x220 -#define BVM_CONS_SIG ('b' << 8 | 'v') - -#ifdef __FreeBSD__ -static struct termios tio_orig, tio_new; - -static void -ttyclose(void) -{ - tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig); -} -#endif - -static void -ttyopen(void) -{ -#ifdef __FreeBSD__ - tcgetattr(STDIN_FILENO, &tio_orig); - - cfmakeraw(&tio_new); - tcsetattr(STDIN_FILENO, TCSANOW, &tio_new); - raw_stdio = 1; - - atexit(ttyclose); -#endif -} - -static bool -tty_char_available(void) -{ - fd_set rfds; - struct timeval tv; - - FD_ZERO(&rfds); - FD_SET(STDIN_FILENO, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0) { - return (true); - } else { - return (false); - } -} - -static int -ttyread(void) -{ - char rb; - - if (tty_char_available()) { - read(STDIN_FILENO, &rb, 1); - return (rb & 0xff); - } else { - return (-1); - } -} - -static void -ttywrite(unsigned char wb) -{ - (void) write(STDOUT_FILENO, &wb, 1); -} - -static int -console_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, - uint32_t *eax, void *arg) -{ - static int opened; -#ifndef WITHOUT_CAPSICUM - cap_rights_t rights; - cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; -#endif - - if (bytes == 2 && in) { - *eax = BVM_CONS_SIG; - return (0); - } - - /* - * Guests might probe this port to look for old ISA devices - * using single-byte reads. Return 0xff for those. - */ - if (bytes == 1 && in) { - *eax = 0xff; - return (0); - } - - if (bytes != 4) - return (-1); - - if (!opened) { -#ifndef WITHOUT_CAPSICUM - cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, - CAP_WRITE); - if (caph_rights_limit(STDIN_FILENO, &rights) == -1) - errx(EX_OSERR, "Unable to apply rights for sandbox"); - if (caph_ioctls_limit(STDIN_FILENO, cmds, nitems(cmds)) == -1) - errx(EX_OSERR, "Unable to apply rights for sandbox"); -#endif - ttyopen(); - opened = 1; - } - - if (in) - *eax = ttyread(); - else - ttywrite(*eax); - - return (0); -} - -SYSRES_IO(BVM_CONSOLE_PORT, 4); - -static struct inout_port consport = { - "bvmcons", - BVM_CONSOLE_PORT, - 1, - IOPORT_F_INOUT, - console_handler -}; - -void -init_bvmcons(void) -{ - - register_inout(&consport); -} diff --git a/usr/src/cmd/bhyve/dbgport.c b/usr/src/cmd/bhyve/dbgport.c deleted file mode 100644 index 88a616b50d..0000000000 --- a/usr/src/cmd/bhyve/dbgport.c +++ /dev/null @@ -1,180 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2011 NetApp, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#ifndef WITHOUT_CAPSICUM -#include <sys/capsicum.h> -#endif -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <sys/uio.h> - -#ifndef WITHOUT_CAPSICUM -#include <capsicum_helpers.h> -#endif -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <sysexits.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - -#include "inout.h" -#include "dbgport.h" -#include "pci_lpc.h" - -#define BVM_DBG_PORT 0x224 -#define BVM_DBG_SIG ('B' << 8 | 'V') - -static int listen_fd, conn_fd; - -static struct sockaddr_in sin; - -static int -dbg_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, - uint32_t *eax, void *arg) -{ - int nwritten, nread, printonce; - int on = 1; - char ch; - - if (bytes == 2 && in) { - *eax = BVM_DBG_SIG; - return (0); - } - - if (bytes != 4) - return (-1); - -again: - printonce = 0; - while (conn_fd < 0) { - if (!printonce) { - printf("Waiting for connection from gdb\r\n"); - printonce = 1; - } - conn_fd = accept4(listen_fd, NULL, NULL, SOCK_NONBLOCK); - if (conn_fd >= 0) { - /* Avoid EPIPE after the client drops off. */ - (void)setsockopt(conn_fd, SOL_SOCKET, SO_NOSIGPIPE, - &on, sizeof(on)); - /* Improve latency for one byte at a time tranfers. */ - (void)setsockopt(conn_fd, IPPROTO_TCP, TCP_NODELAY, - &on, sizeof(on)); - } else if (errno != EINTR) { - perror("accept"); - } - } - - if (in) { - nread = read(conn_fd, &ch, 1); - if (nread == -1 && errno == EAGAIN) - *eax = -1; - else if (nread == 1) - *eax = ch; - else { - close(conn_fd); - conn_fd = -1; - goto again; - } - } else { - ch = *eax; - nwritten = write(conn_fd, &ch, 1); - if (nwritten != 1) { - close(conn_fd); - conn_fd = -1; - goto again; - } - } - return (0); -} - -static struct inout_port dbgport = { - "bvmdbg", - BVM_DBG_PORT, - 1, - IOPORT_F_INOUT, - dbg_handler -}; - -SYSRES_IO(BVM_DBG_PORT, 4); - -void -init_dbgport(int sport) -{ - int reuse; -#ifndef WITHOUT_CAPSICUM - cap_rights_t rights; -#endif - - conn_fd = -1; - - if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("cannot create socket"); - exit(4); - } - -#ifdef __FreeBSD__ - sin.sin_len = sizeof(sin); -#endif - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(sport); - - reuse = 1; - if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, - sizeof(reuse)) < 0) { - perror("cannot set socket options"); - exit(4); - } - - if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - perror("cannot bind socket"); - exit(4); - } - - if (listen(listen_fd, 1) < 0) { - perror("cannot listen socket"); - exit(4); - } - -#ifndef WITHOUT_CAPSICUM - cap_rights_init(&rights, CAP_ACCEPT, CAP_READ, CAP_WRITE); - if (caph_rights_limit(listen_fd, &rights) == -1) - errx(EX_OSERR, "Unable to apply rights for sandbox"); -#endif - - register_inout(&dbgport); -} diff --git a/usr/src/cmd/bhyve/dbgport.h b/usr/src/cmd/bhyve/dbgport.h deleted file mode 100644 index 407ff3ffbf..0000000000 --- a/usr/src/cmd/bhyve/dbgport.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2011 NetApp, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DBGPORT_H_ -#define _DBGPORT_H_ - -void init_dbgport(int port); - -#endif diff --git a/usr/src/cmd/bhyve/gdb.c b/usr/src/cmd/bhyve/gdb.c index 720a55c58b..60b3b8ab6d 100644 --- a/usr/src/cmd/bhyve/gdb.c +++ b/usr/src/cmd/bhyve/gdb.c @@ -135,6 +135,7 @@ static int cur_fd = -1; static TAILQ_HEAD(, breakpoint) breakpoints; static struct vcpu_state *vcpu_state; static int cur_vcpu, stopped_vcpu; +static bool gdb_active = false; const int gdb_regset[] = { VM_REG_GUEST_RAX, @@ -753,6 +754,8 @@ static void _gdb_cpu_suspend(int vcpu, bool report_stop) { + if (!gdb_active) + return; debug("$vCPU %d suspending\n", vcpu); CPU_SET(vcpu, &vcpus_waiting); if (report_stop && CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0) @@ -771,6 +774,8 @@ void gdb_cpu_add(int vcpu) { + if (!gdb_active) + return; debug("$vCPU %d starting\n", vcpu); pthread_mutex_lock(&gdb_lock); assert(vcpu < guest_ncpus); @@ -852,6 +857,8 @@ gdb_cpu_mtrap(int vcpu) { struct vcpu_state *vs; + if (!gdb_active) + return; debug("$vCPU %d MTRAP\n", vcpu); pthread_mutex_lock(&gdb_lock); vs = &vcpu_state[vcpu]; @@ -892,6 +899,10 @@ gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit) uint64_t gpa; int error; + if (!gdb_active) { + fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n"); + exit(4); + } pthread_mutex_lock(&gdb_lock); error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa); assert(error == 1); @@ -1931,4 +1942,5 @@ init_gdb(struct vmctx *_ctx, int sport, bool wait) limit_gdb_socket(s); #endif mevent_add(s, EVF_READ, new_connection, NULL); + gdb_active = true; } diff --git a/usr/src/cmd/bhyve/hda_codec.c b/usr/src/cmd/bhyve/hda_codec.c index 41e8121ae2..7a6ba345d8 100644 --- a/usr/src/cmd/bhyve/hda_codec.c +++ b/usr/src/cmd/bhyve/hda_codec.c @@ -205,7 +205,7 @@ struct hda_codec_softc { * HDA Codec module function declarations */ static int hda_codec_init(struct hda_codec_inst *hci, const char *play, - const char *rec, const char *opts); + const char *rec); static int hda_codec_reset(struct hda_codec_inst *hci); static int hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data); static int hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, @@ -391,7 +391,7 @@ verb_func_t hda_codec_verb_handlers[HDA_CODEC_NODES_COUNT] = { static int hda_codec_init(struct hda_codec_inst *hci, const char *play, - const char *rec, const char *opts) + const char *rec) { struct hda_codec_softc *sc = NULL; struct hda_codec_stream *st = NULL; @@ -400,8 +400,6 @@ hda_codec_init(struct hda_codec_inst *hci, const char *play, if (!(play || rec)) return (-1); - DPRINTF("cad: 0x%x opts: %s", hci->cad, opts); - sc = calloc(1, sizeof(*sc)); if (!sc) return (-1); diff --git a/usr/src/cmd/bhyve/inout.c b/usr/src/cmd/bhyve/inout.c index 27068023d3..0548807730 100644 --- a/usr/src/cmd/bhyve/inout.c +++ b/usr/src/cmd/bhyve/inout.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include <assert.h> #include "bhyverun.h" +#include "config.h" #include "inout.h" SET_DECLARE(inout_port_set, struct inout_port); @@ -116,7 +117,7 @@ register_default_iohandler(int start, int size) } int -emulate_inout(struct vmctx *ctx, int vcpu, struct vm_inout *inout, bool strict) +emulate_inout(struct vmctx *ctx, int vcpu, struct vm_inout *inout) { struct inout_handler handler; inout_func_t hfunc; @@ -134,7 +135,8 @@ emulate_inout(struct vmctx *ctx, int vcpu, struct vm_inout *inout, bool strict) hfunc = handler.handler; harg = handler.arg; - if (strict && hfunc == default_inout) + if (hfunc == default_inout && + get_config_bool_default("x86.strictio", false)) return (-1); if (in) { diff --git a/usr/src/cmd/bhyve/inout.h b/usr/src/cmd/bhyve/inout.h index b026e18e92..a3b64b9001 100644 --- a/usr/src/cmd/bhyve/inout.h +++ b/usr/src/cmd/bhyve/inout.h @@ -47,7 +47,9 @@ struct vmctx; struct vm_exit; +#ifndef __FreeBSD__ struct vm_inout; +#endif /* * inout emulation handlers return 0 on success and -1 on failure. @@ -85,10 +87,12 @@ struct inout_port { DATA_SET(inout_port_set, __CONCAT(__inout_port, __LINE__)) void init_inout(void); -int emulate_inout(struct vmctx *, int vcpu, struct vm_inout *inout, - bool strict); +#ifdef __FreeBSD__ +int emulate_inout(struct vmctx *, int vcpu, struct vm_exit *vmexit); +#else +int emulate_inout(struct vmctx *, int vcpu, struct vm_inout *inout); +#endif int register_inout(struct inout_port *iop); int unregister_inout(struct inout_port *iop); -void init_bvmcons(void); #endif /* _INOUT_H_ */ diff --git a/usr/src/cmd/bhyve/mevent.c b/usr/src/cmd/bhyve/mevent.c index f3ffc6bcaf..3eb55e3d3a 100644 --- a/usr/src/cmd/bhyve/mevent.c +++ b/usr/src/cmd/bhyve/mevent.c @@ -82,8 +82,6 @@ __FBSDID("$FreeBSD$"); #define EV_DELETE 0x04 #endif -extern char *vmname; - static pthread_t mevent_tid; static int mevent_timid = 43; static int mevent_pipefd[2]; diff --git a/usr/src/cmd/bhyve/mevent_test.c b/usr/src/cmd/bhyve/mevent_test.c index 4da3adb5ae..dad8b7773e 100644 --- a/usr/src/cmd/bhyve/mevent_test.c +++ b/usr/src/cmd/bhyve/mevent_test.c @@ -64,8 +64,6 @@ static pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER; static struct mevent *tevp; -char *vmname = "test vm"; - #define MEVENT_ECHO diff --git a/usr/src/cmd/bhyve/net_backends.c b/usr/src/cmd/bhyve/net_backends.c index 884ffb8241..30c26aea45 100644 --- a/usr/src/cmd/bhyve/net_backends.c +++ b/usr/src/cmd/bhyve/net_backends.c @@ -75,10 +75,12 @@ __FBSDID("$FreeBSD$"); #include <netgraph.h> #endif +#include "config.h" #include "debug.h" #include "iov.h" #include "mevent.h" #include "net_backends.h" +#include "pci_emul.h" #include <sys/linker_set.h> @@ -96,7 +98,7 @@ struct net_backend { * and should not be called by the frontend. */ int (*init)(struct net_backend *be, const char *devname, - const char *opts, net_be_rxeof_t cb, void *param); + nvlist_t *nvl, net_be_rxeof_t cb, void *param); void (*cleanup)(struct net_backend *be); /* @@ -204,7 +206,7 @@ tap_cleanup(struct net_backend *be) static int tap_init(struct net_backend *be, const char *devname, - const char *opts, net_be_rxeof_t cb, void *param) + nvlist_t *nvl, net_be_rxeof_t cb, void *param) { struct tap_priv *priv = (struct tap_priv *)be->opaque; char tbuf[80]; @@ -398,18 +400,14 @@ DATA_SET(net_backend_set, vmnet_backend); static int ng_init(struct net_backend *be, const char *devname, - const char *opts, net_be_rxeof_t cb, void *param) + nvlist_t *nvl, net_be_rxeof_t cb, void *param) { struct tap_priv *p = (struct tap_priv *)be->opaque; struct ngm_connect ngc; - char *ngopts, *tofree; - char nodename[NG_NODESIZ]; + const char *value, *nodename; int sbsz; int ctrl_sock; int flags; - int path_provided; - int peerhook_provided; - int socket_provided; unsigned long maxsbsz; size_t msbsz; #ifndef WITHOUT_CAPSICUM @@ -425,56 +423,27 @@ ng_init(struct net_backend *be, const char *devname, memset(&ngc, 0, sizeof(ngc)); - strncpy(ngc.ourhook, "vmlink", NG_HOOKSIZ - 1); - - tofree = ngopts = strdup(opts); - - if (ngopts == NULL) { - WPRINTF(("strdup error")); - return (-1); - } - - socket_provided = 0; - path_provided = 0; - peerhook_provided = 0; - - while (ngopts != NULL) { - char *value = ngopts; - char *key; - - key = strsep(&value, "="); - if (value == NULL) - break; - ngopts = value; - (void) strsep(&ngopts, ","); - - if (strcmp(key, "socket") == 0) { - strncpy(nodename, value, NG_NODESIZ - 1); - socket_provided = 1; - } else if (strcmp(key, "path") == 0) { - strncpy(ngc.path, value, NG_PATHSIZ - 1); - path_provided = 1; - } else if (strcmp(key, "hook") == 0) { - strncpy(ngc.ourhook, value, NG_HOOKSIZ - 1); - } else if (strcmp(key, "peerhook") == 0) { - strncpy(ngc.peerhook, value, NG_HOOKSIZ - 1); - peerhook_provided = 1; - } - } - - free(tofree); - - if (!path_provided) { + value = get_config_value_node(nvl, "path"); + if (value == NULL) { WPRINTF(("path must be provided")); return (-1); } + strncpy(ngc.path, value, NG_PATHSIZ - 1); - if (!peerhook_provided) { + value = get_config_value_node(nvl, "hook"); + if (value == NULL) + value = "vmlink"; + strncpy(ngc.ourhook, value, NG_HOOKSIZ - 1); + + value = get_config_value_node(nvl, "peerhook"); + if (value == NULL) { WPRINTF(("peer hook must be provided")); return (-1); } + strncpy(ngc.peerhook, value, NG_HOOKSIZ - 1); - if (NgMkSockNode(socket_provided ? nodename : NULL, + nodename = get_config_value_node(nvl, "socket"); + if (NgMkSockNode(nodename, &ctrl_sock, &be->fd) < 0) { WPRINTF(("can't get Netgraph sockets")); return (-1); @@ -664,7 +633,7 @@ netmap_set_cap(struct net_backend *be, uint64_t features, static int netmap_init(struct net_backend *be, const char *devname, - const char *opts, net_be_rxeof_t cb, void *param) + nvlist_t *nvl, net_be_rxeof_t cb, void *param) { struct netmap_priv *priv = (struct netmap_priv *)be->opaque; @@ -924,10 +893,29 @@ static struct net_backend vale_backend = { DATA_SET(net_backend_set, netmap_backend); DATA_SET(net_backend_set, vale_backend); +int +netbe_legacy_config(nvlist_t *nvl, const char *opts) +{ + char *backend, *cp; + + if (opts == NULL) + return (0); + + cp = strchr(opts, ','); + if (cp == NULL) { + set_config_value_node(nvl, "backend", opts); + return (0); + } + backend = strndup(opts, cp - opts); + set_config_value_node(nvl, "backend", backend); + free(backend); + return (pci_parse_legacy_config(nvl, cp + 1)); +} + /* * Initialize a backend and attach to the frontend. * This is called during frontend initialization. - * @pbe is a pointer to the backend to be initialized + * @ret is a pointer to the backend to be initialized * @devname is the backend-name as supplied on the command line, * e.g. -s 2:0,frontend-name,backend-name[,other-args] * @cb is the receive callback supplied by the frontend, @@ -937,21 +925,19 @@ DATA_SET(net_backend_set, vale_backend); * the argument for the callback. */ int -netbe_init(struct net_backend **ret, const char *opts, net_be_rxeof_t cb, +netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb, void *param) { struct net_backend **pbe, *nbe, *tbe = NULL; + const char *value; char *devname; - char *options; int err; - devname = options = strdup(opts); - - if (devname == NULL) { + value = get_config_value_node(nvl, "backend"); + if (value == NULL) { return (-1); } - - devname = strsep(&options, ","); + devname = strdup(value); /* * Find the network backend that matches the user-provided @@ -985,7 +971,7 @@ netbe_init(struct net_backend **ret, const char *opts, net_be_rxeof_t cb, nbe->fe_vnet_hdr_len = 0; /* Initialize the backend. */ - err = nbe->init(nbe, devname, options, cb, param); + err = nbe->init(nbe, devname, nvl, cb, param); if (err) { free(devname); free(nbe); diff --git a/usr/src/cmd/bhyve/net_backends.h b/usr/src/cmd/bhyve/net_backends.h index b55437fc7b..bc7834546b 100644 --- a/usr/src/cmd/bhyve/net_backends.h +++ b/usr/src/cmd/bhyve/net_backends.h @@ -37,8 +37,9 @@ typedef struct net_backend net_backend_t; /* Interface between network frontends and the network backends. */ typedef void (*net_be_rxeof_t)(int, enum ev_type, void *param); -int netbe_init(net_backend_t **be, const char *opts, net_be_rxeof_t cb, +int netbe_init(net_backend_t **be, nvlist_t *nvl, net_be_rxeof_t cb, void *param); +int netbe_legacy_config(nvlist_t *nvl, const char *opts); void netbe_cleanup(net_backend_t *be); uint64_t netbe_get_cap(net_backend_t *be); int netbe_set_cap(net_backend_t *be, uint64_t cap, diff --git a/usr/src/cmd/bhyve/net_utils.c b/usr/src/cmd/bhyve/net_utils.c index d602cac3eb..8088fa89a5 100644 --- a/usr/src/cmd/bhyve/net_utils.c +++ b/usr/src/cmd/bhyve/net_utils.c @@ -40,11 +40,12 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "net_utils.h" int -net_parsemac(char *mac_str, uint8_t *mac_addr) +net_parsemac(const char *mac_str, uint8_t *mac_addr) { struct ether_addr *ea; char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 }; @@ -107,7 +108,7 @@ net_genmac(struct pci_devinst *pi, uint8_t *macaddr) char nstr[80]; snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot, - pi->pi_func, vmname); + pi->pi_func, get_config_value("name")); MD5Init(&mdctx); MD5Update(&mdctx, nstr, (unsigned int)strlen(nstr)); diff --git a/usr/src/cmd/bhyve/net_utils.h b/usr/src/cmd/bhyve/net_utils.h index 1ca20ddb74..3dd4457258 100644 --- a/usr/src/cmd/bhyve/net_utils.h +++ b/usr/src/cmd/bhyve/net_utils.h @@ -34,7 +34,7 @@ #include "pci_emul.h" void net_genmac(struct pci_devinst *pi, uint8_t *macaddr); -int net_parsemac(char *mac_str, uint8_t *mac_addr); +int net_parsemac(const char *mac_str, uint8_t *mac_addr); int net_parsemtu(const char *mtu_str, unsigned long *mtu); #endif /* _NET_UTILS_H_ */ diff --git a/usr/src/cmd/bhyve/pci_ahci.c b/usr/src/cmd/bhyve/pci_ahci.c index 0d4951a61e..2416edd166 100644 --- a/usr/src/cmd/bhyve/pci_ahci.c +++ b/usr/src/cmd/bhyve/pci_ahci.c @@ -56,6 +56,8 @@ __FBSDID("$FreeBSD$"); #include <md5.h> #include "bhyverun.h" +#include "config.h" +#include "debug.h" #include "pci_emul.h" #include "ahci.h" #include "block_if.h" @@ -2308,20 +2310,115 @@ pci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, return (value); } +/* + * Each AHCI controller has a "port" node which contains nodes for + * each port named after the decimal number of the port (no leading + * zeroes). Port nodes contain a "type" ("hd" or "cd"), as well as + * options for blockif. For example: + * + * pci.0.1.0 + * .device="ahci" + * .port + * .0 + * .type="hd" + * .path="/path/to/image" + */ static int -pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) +pci_ahci_legacy_config_port(nvlist_t *nvl, int port, const char *type, + const char *opts) +{ + char node_name[sizeof("XX")]; + nvlist_t *port_nvl; + + snprintf(node_name, sizeof(node_name), "%d", port); + port_nvl = create_relative_config_node(nvl, node_name); + set_config_value_node(port_nvl, "type", type); + return (blockif_legacy_config(port_nvl, opts)); +} + +static int +pci_ahci_legacy_config(nvlist_t *nvl, const char *opts) +{ + nvlist_t *ports_nvl; + const char *type; + char *next, *next2, *str, *tofree; + int p, ret; + + if (opts == NULL) + return (0); + + ports_nvl = create_relative_config_node(nvl, "port"); + ret = 1; + tofree = str = strdup(opts); + for (p = 0; p < MAX_PORTS && str != NULL; p++, str = next) { + /* Identify and cut off type of present port. */ + if (strncmp(str, "hd:", 3) == 0) { + type = "hd"; + str += 3; + } else if (strncmp(str, "cd:", 3) == 0) { + type = "cd"; + str += 3; + } else + type = NULL; + + /* Find and cut off the next port options. */ + next = strstr(str, ",hd:"); + next2 = strstr(str, ",cd:"); + if (next == NULL || (next2 != NULL && next2 < next)) + next = next2; + if (next != NULL) { + next[0] = 0; + next++; + } + + if (str[0] == 0) + continue; + + if (type == NULL) { + EPRINTLN("Missing or invalid type for port %d: \"%s\"", + p, str); + goto out; + } + + if (pci_ahci_legacy_config_port(ports_nvl, p, type, str) != 0) + goto out; + } + ret = 0; +out: + free(tofree); + return (ret); +} + +static int +pci_ahci_cd_legacy_config(nvlist_t *nvl, const char *opts) +{ + nvlist_t *ports_nvl; + + ports_nvl = create_relative_config_node(nvl, "port"); + return (pci_ahci_legacy_config_port(ports_nvl, 0, "cd", opts)); +} + +static int +pci_ahci_hd_legacy_config(nvlist_t *nvl, const char *opts) +{ + nvlist_t *ports_nvl; + + ports_nvl = create_relative_config_node(nvl, "port"); + return (pci_ahci_legacy_config_port(ports_nvl, 0, "hd", opts)); +} + +static int +pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { char bident[sizeof("XX:XX:XX")]; + char node_name[sizeof("XX")]; struct blockif_ctxt *bctxt; struct pci_ahci_softc *sc; - int ret, slots, p; + int atapi, ret, slots, p; MD5_CTX mdctx; u_char digest[16]; - char *next, *next2; - char *bopt, *uopt, *xopts, *config; - FILE* fp; - size_t block_len; - int comma, optpos; + const char *path, *type, *value; + nvlist_t *ports_nvl, *port_nvl; ret = 0; @@ -2337,98 +2434,24 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) sc->pi = 0; slots = 32; - for (p = 0; p < MAX_PORTS && opts != NULL; p++, opts = next) { + ports_nvl = find_relative_config_node(nvl, "port"); + for (p = 0; p < MAX_PORTS; p++) { struct ata_params *ata_ident = &sc->port[p].ata_ident; - memset(ata_ident, 0, sizeof(struct ata_params)); + char ident[AHCI_PORT_IDENT]; - /* Identify and cut off type of present port. */ - if (strncmp(opts, "hd:", 3) == 0) { - atapi = 0; - opts += 3; - } else if (strncmp(opts, "cd:", 3) == 0) { - atapi = 1; - opts += 3; - } - - /* Find and cut off the next port options. */ - next = strstr(opts, ",hd:"); - next2 = strstr(opts, ",cd:"); - if (next == NULL || (next2 != NULL && next2 < next)) - next = next2; - if (next != NULL) { - next[0] = 0; - next++; - } - - if (opts[0] == 0) + snprintf(node_name, sizeof(node_name), "%d", p); + port_nvl = find_relative_config_node(ports_nvl, node_name); + if (port_nvl == NULL) continue; - uopt = strdup(opts); - bopt = NULL; - fp = open_memstream(&bopt, &block_len); - comma = 0; - optpos = 0; - - for (xopts = strtok(uopt, ","); - xopts != NULL; - xopts = strtok(NULL, ",")) { - - /* First option assume as block filename. */ - if (optpos == 0) { - /* - * Create an identifier for the backing file. - * Use parts of the md5 sum of the filename - */ - char ident[AHCI_PORT_IDENT]; - MD5Init(&mdctx); - MD5Update(&mdctx, opts, strlen(opts)); - MD5Final(digest, &mdctx); - snprintf(ident, AHCI_PORT_IDENT, - "BHYVE-%02X%02X-%02X%02X-%02X%02X", - digest[0], digest[1], digest[2], digest[3], digest[4], - digest[5]); - ata_string((uint8_t*)&ata_ident->serial, ident, 20); - ata_string((uint8_t*)&ata_ident->revision, "001", 8); - if (atapi) { - ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40); - } - else { - ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40); - } - } - - if ((config = strchr(xopts, '=')) != NULL) { - *config++ = '\0'; - if (!strcmp("nmrr", xopts)) { - ata_ident->media_rotation_rate = atoi(config); - } - else if (!strcmp("ser", xopts)) { - ata_string((uint8_t*)(&ata_ident->serial), config, 20); - } - else if (!strcmp("rev", xopts)) { - ata_string((uint8_t*)(&ata_ident->revision), config, 8); - } - else if (!strcmp("model", xopts)) { - ata_string((uint8_t*)(&ata_ident->model), config, 40); - } - else { - /* Pass all other options to blockif_open. */ - *--config = '='; - fprintf(fp, "%s%s", comma ? "," : "", xopts); - comma = 1; - } - } - else { - /* Pass all other options to blockif_open. */ - fprintf(fp, "%s%s", comma ? "," : "", xopts); - comma = 1; - } - optpos++; - } - free(uopt); - fclose(fp); + type = get_config_value_node(port_nvl, "type"); + if (type == NULL) + continue; - DPRINTF("%s\n", bopt); + if (strcmp(type, "hd") == 0) + atapi = 0; + else + atapi = 1; /* * Attempt to open the backing image. Use the PCI slot/func @@ -2436,9 +2459,8 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) */ snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot, pi->pi_func, p); - bctxt = blockif_open(bopt, bident); - free(bopt); + bctxt = blockif_open(port_nvl, bident); if (bctxt == NULL) { sc->ports = p; ret = 1; @@ -2449,6 +2471,40 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) sc->port[p].port = p; sc->port[p].atapi = atapi; + /* + * Create an identifier for the backing file. + * Use parts of the md5 sum of the filename + */ + path = get_config_value_node(port_nvl, "path"); + MD5Init(&mdctx); + MD5Update(&mdctx, path, strlen(path)); + MD5Final(digest, &mdctx); + snprintf(ident, AHCI_PORT_IDENT, + "BHYVE-%02X%02X-%02X%02X-%02X%02X", + digest[0], digest[1], digest[2], digest[3], digest[4], + digest[5]); + + memset(ata_ident, 0, sizeof(struct ata_params)); + ata_string((uint8_t*)&ata_ident->serial, ident, 20); + ata_string((uint8_t*)&ata_ident->revision, "001", 8); + if (atapi) + ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40); + else + ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40); + value = get_config_value_node(port_nvl, "nmrr"); + if (value != NULL) + ata_ident->media_rotation_rate = atoi(value); + value = get_config_value_node(port_nvl, "ser"); + if (value != NULL) + ata_string((uint8_t*)(&ata_ident->serial), value, 20); + value = get_config_value_node(port_nvl, "rev"); + if (value != NULL) + ata_string((uint8_t*)(&ata_ident->revision), value, 8); + value = get_config_value_node(port_nvl, "model"); + if (value != NULL) + ata_string((uint8_t*)(&ata_ident->model), value, 40); + ata_identify_init(&sc->port[p], atapi); + #ifndef __FreeBSD__ /* * Attempt to enable the write cache for this device, as the @@ -2460,8 +2516,6 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) (void) blockif_set_wce(bctxt, 1); #endif - ata_identify_init(&sc->port[p], atapi); - /* * Allocate blockif request structures and add them * to the free list @@ -2513,43 +2567,28 @@ open_fail: return (ret); } -static int -pci_ahci_hd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) -{ - - return (pci_ahci_init(ctx, pi, opts, 0)); -} - -static int -pci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) -{ - - return (pci_ahci_init(ctx, pi, opts, 1)); -} - /* * Use separate emulation names to distinguish drive and atapi devices */ struct pci_devemu pci_de_ahci = { .pe_emu = "ahci", - .pe_init = pci_ahci_hd_init, + .pe_init = pci_ahci_init, + .pe_legacy_config = pci_ahci_legacy_config, .pe_barwrite = pci_ahci_write, - .pe_barread = pci_ahci_read + .pe_barread = pci_ahci_read, }; PCI_EMUL_SET(pci_de_ahci); struct pci_devemu pci_de_ahci_hd = { .pe_emu = "ahci-hd", - .pe_init = pci_ahci_hd_init, - .pe_barwrite = pci_ahci_write, - .pe_barread = pci_ahci_read + .pe_legacy_config = pci_ahci_hd_legacy_config, + .pe_alias = "ahci", }; PCI_EMUL_SET(pci_de_ahci_hd); struct pci_devemu pci_de_ahci_cd = { .pe_emu = "ahci-cd", - .pe_init = pci_ahci_atapi_init, - .pe_barwrite = pci_ahci_write, - .pe_barread = pci_ahci_read + .pe_legacy_config = pci_ahci_cd_legacy_config, + .pe_alias = "ahci", }; PCI_EMUL_SET(pci_de_ahci_cd); diff --git a/usr/src/cmd/bhyve/pci_e82545.c b/usr/src/cmd/bhyve/pci_e82545.c index cb7e074540..598deff980 100644 --- a/usr/src/cmd/bhyve/pci_e82545.c +++ b/usr/src/cmd/bhyve/pci_e82545.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include "mii.h" #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #include "mevent.h" @@ -360,7 +361,7 @@ static void e82545_reset(struct e82545_softc *sc, int dev); static void e82545_rx_enable(struct e82545_softc *sc); static void e82545_rx_disable(struct e82545_softc *sc); #ifdef __FreeBSD__ -static void e82545_tap_callback(int fd, enum ev_type type, void *param); +static void e82545_rx_callback(int fd, enum ev_type type, void *param); #endif static void e82545_tx_start(struct e82545_softc *sc); static void e82545_tx_enable(struct e82545_softc *sc); @@ -841,7 +842,7 @@ static uint8_t dummybuf[2048]; /* XXX one packet at a time until this is debugged */ static void -e82545_tap_callback(int fd, enum ev_type type, void *param) +e82545_rx_callback(int fd, enum ev_type type, void *param) { struct e82545_softc *sc = param; struct e1000_rx_desc *rxd; @@ -2236,24 +2237,24 @@ e82545_reset(struct e82545_softc *sc, int drvr) } static void -e82545_open_tap(struct e82545_softc *sc, char *opts) +e82545_open_tap(struct e82545_softc *sc, const char *path) { char tbuf[80]; #ifndef WITHOUT_CAPSICUM cap_rights_t rights; #endif - if (opts == NULL) { + if (path == NULL) { sc->esc_tapfd = -1; return; } strcpy(tbuf, "/dev/"); - strlcat(tbuf, opts, sizeof(tbuf)); + strlcat(tbuf, path, sizeof(tbuf)); sc->esc_tapfd = open(tbuf, O_RDWR); if (sc->esc_tapfd == -1) { - DPRINTF("unable to open tap device %s\n", opts); + DPRINTF("unable to open tap device %s\n", path); exit(4); } @@ -2277,7 +2278,7 @@ e82545_open_tap(struct e82545_softc *sc, char *opts) #ifdef __FreeBSD__ sc->esc_mevp = mevent_add(sc->esc_tapfd, EVF_READ, - e82545_tap_callback, + e82545_rx_callback, sc); if (sc->esc_mevp == NULL) { DPRINTF("Could not register mevent %d\n", EVF_READ); @@ -2288,15 +2289,12 @@ e82545_open_tap(struct e82545_softc *sc, char *opts) } static int -e82545_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +e82545_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { char nstr[80]; struct e82545_softc *sc; - char *optscopy; - char *vtopts; - int mac_provided; - - DPRINTF("Loading with options: %s", opts); + const char *mac; + int err; /* Setup our softc */ sc = calloc(1, sizeof(*sc)); @@ -2334,60 +2332,59 @@ e82545_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_emul_alloc_bar(pi, E82545_BAR_IO, PCIBAR_IO, E82545_BAR_IO_LEN); - /* - * Attempt to open the tap device and read the MAC address - * if specified. Copied from virtio-net, slightly modified. - */ - mac_provided = 0; - sc->esc_tapfd = -1; - if (opts != NULL) { - int err = 0; + mac = get_config_value_node(nvl, "mac"); + if (mac != NULL) { + err = net_parsemac(mac, sc->esc_mac.octet); + if (err) { + free(sc); + return (err); + } + } else + net_genmac(pi, sc->esc_mac.octet); - optscopy = vtopts = strdup(opts); - (void) strsep(&vtopts, ","); + const char *tap = get_config_value_node(nvl, "tap"); + if (tap != NULL && (strncmp(tap, "tap", 3) == 0 || + strncmp(tap, "vmnet", 5) == 0)) + e82545_open_tap(sc, tap); - /* - * Parse the list of options in the form - * key1=value1,...,keyN=valueN. - */ - while (vtopts != NULL) { - char *value = vtopts; - char *key; + /* H/w initiated reset */ + e82545_reset(sc, 0); - key = strsep(&value, "="); - if (value == NULL) - break; - vtopts = value; - (void) strsep(&vtopts, ","); - - if (strcmp(key, "mac") == 0) { - err = net_parsemac(value, sc->esc_mac.octet); - if (err) - break; - mac_provided = 1; - } - } + return (0); +} - if (strncmp(optscopy, "tap", 3) == 0 || - strncmp(optscopy, "vmnet", 5) == 0) - e82545_open_tap(sc, optscopy); +#ifndef __FreeBSD__ +static int +e82545_legacy_config(nvlist_t *nvl, const char *opt) +{ + char *config, *name, *tofree, *value; - free(optscopy); - } + if (opt == NULL) + return (0); - if (!mac_provided) { - net_genmac(pi, sc->esc_mac.octet); + config = tofree = strdup(opt); + while ((name = strsep(&config, ",")) != NULL) { + value = strchr(name, '='); + if (value != NULL) { + *value++ = '\0'; + set_config_value_node(nvl, name, value); + } else { + set_config_value_node(nvl, "tap", name); + } } - - /* H/w initiated reset */ - e82545_reset(sc, 0); - + free(tofree); return (0); } +#endif struct pci_devemu pci_de_e82545 = { .pe_emu = "e1000", .pe_init = e82545_init, +#ifdef __FreeBSD__ + .pe_legacy_config = netbe_legacy_config, +#else + .pe_legacy_config = e82545_legacy_config, +#endif .pe_barwrite = e82545_write, .pe_barread = e82545_read }; diff --git a/usr/src/cmd/bhyve/pci_emul.c b/usr/src/cmd/bhyve/pci_emul.c index 90602f715b..ce218b8185 100644 --- a/usr/src/cmd/bhyve/pci_emul.c +++ b/usr/src/cmd/bhyve/pci_emul.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include "acpi.h" #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "inout.h" #include "ioapic.h" @@ -80,8 +81,8 @@ __FBSDID("$FreeBSD$"); #define MAXFUNCS (PCI_FUNCMAX + 1) struct funcinfo { - char *fi_name; - char *fi_param; + nvlist_t *fi_config; + struct pci_devemu *fi_pde; struct pci_devinst *fi_devi; }; @@ -123,7 +124,7 @@ SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE); #define PCI_EMUL_MEMBASE64 0xD000000000UL #define PCI_EMUL_MEMLIMIT64 0xFD00000000UL -static struct pci_devemu *pci_emul_finddev(char *name); +static struct pci_devemu *pci_emul_finddev(const char *name); static void pci_lintr_route(struct pci_devinst *pi); static void pci_lintr_update(struct pci_devinst *pi); static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, @@ -179,13 +180,56 @@ pci_parse_slot_usage(char *aopt) EPRINTLN("Invalid PCI slot info field \"%s\"", aopt); } +/* + * Helper function to parse a list of comma-separated options where + * each option is formatted as "name[=value]". If no value is + * provided, the option is treated as a boolean and is given a value + * of true. + */ +int +pci_parse_legacy_config(nvlist_t *nvl, const char *opt) +{ + char *config, *name, *tofree, *value; + + if (opt == NULL) + return (0); + + config = tofree = strdup(opt); + while ((name = strsep(&config, ",")) != NULL) { + value = strchr(name, '='); + if (value != NULL) { + *value = '\0'; + value++; + set_config_value_node(nvl, name, value); + } else + set_config_bool_node(nvl, name, true); + } + free(tofree); + return (0); +} + +/* + * PCI device configuration is stored in MIBs that encode the device's + * location: + * + * pci.<bus>.<slot>.<func> + * + * Where "bus", "slot", and "func" are all decimal values without + * leading zeroes. Each valid device must have a "device" node which + * identifies the driver model of the device. + * + * Device backends can provide a parser for the "config" string. If + * a custom parser is not provided, pci_parse_legacy_config() is used + * to parse the string. + */ int pci_parse_slot(char *opt) { - struct businfo *bi; - struct slotinfo *si; + char node_name[sizeof("pci.XXX.XX.X")]; + struct pci_devemu *pde; char *emul, *config, *str, *cp; int error, bnum, snum, fnum; + nvlist_t *nvl; error = -1; str = strdup(opt); @@ -222,32 +266,33 @@ pci_parse_slot(char *opt) goto done; } - if (pci_businfo[bnum] == NULL) - pci_businfo[bnum] = calloc(1, sizeof(struct businfo)); - - bi = pci_businfo[bnum]; - si = &bi->slotinfo[snum]; - - if (si->si_funcs[fnum].fi_name != NULL) { - EPRINTLN("pci slot %d:%d already occupied!", - snum, fnum); + pde = pci_emul_finddev(emul); + if (pde == NULL) { + EPRINTLN("pci slot %d:%d:%d: unknown device \"%s\"", bnum, snum, + fnum, emul); goto done; } - if (pci_emul_finddev(emul) == NULL) { - EPRINTLN("pci slot %d:%d: unknown device \"%s\"", - snum, fnum, emul); + snprintf(node_name, sizeof(node_name), "pci.%d.%d.%d", bnum, snum, + fnum); + nvl = find_config_node(node_name); + if (nvl != NULL) { + EPRINTLN("pci slot %d:%d:%d already occupied!", bnum, snum, + fnum); goto done; } + nvl = create_config_node(node_name); + if (pde->pe_alias != NULL) + set_config_value_node(nvl, "device", pde->pe_alias); + else + set_config_value_node(nvl, "device", pde->pe_emu); - error = 0; - si->si_funcs[fnum].fi_name = emul; - si->si_funcs[fnum].fi_param = config; - + if (pde->pe_legacy_config != NULL) + error = pde->pe_legacy_config(nvl, config); + else + error = pci_parse_legacy_config(nvl, config); done: - if (error) - free(str); - + free(str); return (error); } @@ -470,10 +515,12 @@ pci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size, static void modify_bar_registration(struct pci_devinst *pi, int idx, int registration) { + struct pci_devemu *pe; int error; struct inout_port iop; struct mem_range mr; + pe = pi->pi_d; switch (pi->pi_bar[idx].type) { case PCIBAR_IO: bzero(&iop, sizeof(struct inout_port)); @@ -487,6 +534,9 @@ modify_bar_registration(struct pci_devinst *pi, int idx, int registration) error = register_inout(&iop); } else error = unregister_inout(&iop); + if (pe->pe_baraddr != NULL) + (*pe->pe_baraddr)(pi->pi_vmctx, pi, idx, registration, + pi->pi_bar[idx].addr); break; case PCIBAR_MEM32: case PCIBAR_MEM64: @@ -502,6 +552,9 @@ modify_bar_registration(struct pci_devinst *pi, int idx, int registration) error = register_mem(&mr); } else error = unregister_mem(&mr); + if (pe->pe_baraddr != NULL) + (*pe->pe_baraddr)(pi->pi_vmctx, pi, idx, registration, + pi->pi_bar[idx].addr); break; default: error = EINVAL; @@ -729,7 +782,7 @@ pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen) } static struct pci_devemu * -pci_emul_finddev(char *name) +pci_emul_finddev(const char *name) { struct pci_devemu **pdpp, *pdp; @@ -770,7 +823,7 @@ pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot, pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN); - err = (*pde->pe_init)(ctx, pdi, fi->fi_param); + err = (*pde->pe_init)(ctx, pdi, fi->fi_config); if (err == 0) fi->fi_devi = pdi; else @@ -1099,11 +1152,14 @@ pci_ecfg_base(void) int init_pci(struct vmctx *ctx) { + char node_name[sizeof("pci.XXX.XX.X")]; struct mem_range mr; struct pci_devemu *pde; struct businfo *bi; struct slotinfo *si; struct funcinfo *fi; + nvlist_t *nvl; + const char *emul; size_t lowmem; int bus, slot, func; int error; @@ -1113,8 +1169,13 @@ init_pci(struct vmctx *ctx) pci_emul_membase64 = PCI_EMUL_MEMBASE64; for (bus = 0; bus < MAXBUSES; bus++) { - if ((bi = pci_businfo[bus]) == NULL) + snprintf(node_name, sizeof(node_name), "pci.%d", bus); + nvl = find_config_node(node_name); + if (nvl == NULL) continue; + pci_businfo[bus] = calloc(1, sizeof(struct businfo)); + bi = pci_businfo[bus]; + /* * Keep track of the i/o and memory resources allocated to * this bus. @@ -1127,10 +1188,34 @@ init_pci(struct vmctx *ctx) si = &bi->slotinfo[slot]; for (func = 0; func < MAXFUNCS; func++) { fi = &si->si_funcs[func]; - if (fi->fi_name == NULL) + snprintf(node_name, sizeof(node_name), + "pci.%d.%d.%d", bus, slot, func); + nvl = find_config_node(node_name); + if (nvl == NULL) continue; - pde = pci_emul_finddev(fi->fi_name); - assert(pde != NULL); + + fi->fi_config = nvl; + emul = get_config_value_node(nvl, "device"); + if (emul == NULL) { + EPRINTLN("pci slot %d:%d:%d: missing " + "\"device\" value", bus, slot, func); + return (EINVAL); + } + pde = pci_emul_finddev(emul); + if (pde == NULL) { + EPRINTLN("pci slot %d:%d:%d: unknown " + "device \"%s\"", bus, slot, func, + emul); + return (EINVAL); + } + if (pde->pe_alias != NULL) { + EPRINTLN("pci slot %d:%d:%d: legacy " + "device \"%s\", use \"%s\" instead", + bus, slot, func, emul, + pde->pe_alias); + return (EINVAL); + } + fi->fi_pde = pde; error = pci_emul_init(ctx, pde, bus, slot, func, fi); if (error) @@ -1992,7 +2077,7 @@ struct pci_emul_dsoftc { #define PCI_EMUL_MSIX_MSGS 16 static int -pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { int error; struct pci_emul_dsoftc *sc; @@ -2150,7 +2235,7 @@ struct pci_devemu pci_dummy = { .pe_emu = "dummy", .pe_init = pci_emul_dinit, .pe_barwrite = pci_emul_diow, - .pe_barread = pci_emul_dior + .pe_barread = pci_emul_dior, }; PCI_EMUL_SET(pci_dummy); diff --git a/usr/src/cmd/bhyve/pci_emul.h b/usr/src/cmd/bhyve/pci_emul.h index 63e3c89a95..cc3a8c048c 100644 --- a/usr/src/cmd/bhyve/pci_emul.h +++ b/usr/src/cmd/bhyve/pci_emul.h @@ -37,6 +37,7 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/kernel.h> +#include <sys/nv.h> #include <sys/_pthreadtypes.h> #include <dev/pci/pcireg.h> @@ -54,7 +55,9 @@ struct pci_devemu { /* instance creation */ int (*pe_init)(struct vmctx *, struct pci_devinst *, - char *opts); + nvlist_t *); + int (*pe_legacy_config)(nvlist_t *, const char *); + const char *pe_alias; /* ACPI DSDT enumeration */ void (*pe_write_dsdt)(struct pci_devinst *); @@ -75,10 +78,13 @@ struct pci_devemu { struct pci_devinst *pi, int baridx, uint64_t offset, int size); + void (*pe_baraddr)(struct vmctx *ctx, struct pci_devinst *pi, + int baridx, int enabled, uint64_t address); #ifndef __FreeBSD__ void (*pe_lintrupdate)(struct pci_devinst *pi); #endif /* __FreeBSD__ */ }; + #define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x); enum pcibar_type { @@ -237,6 +243,7 @@ int pci_msix_enabled(struct pci_devinst *pi); int pci_msix_table_bar(struct pci_devinst *pi); int pci_msix_pba_bar(struct pci_devinst *pi); int pci_msi_maxmsgnum(struct pci_devinst *pi); +int pci_parse_legacy_config(nvlist_t *nvl, const char *opt); int pci_parse_slot(char *opt); void pci_print_supported_devices(); void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr); diff --git a/usr/src/cmd/bhyve/pci_fbuf.c b/usr/src/cmd/bhyve/pci_fbuf.c index d945545b9d..44f65f61c7 100644 --- a/usr/src/cmd/bhyve/pci_fbuf.c +++ b/usr/src/cmd/bhyve/pci_fbuf.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include "bhyvegc.h" #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "console.h" #include "inout.h" @@ -100,7 +101,7 @@ struct pci_fbuf_softc { char *rfb_password; int rfb_port; #ifndef __FreeBSD__ - char *rfb_unix; + const char *rfb_unix; #endif int rfb_wait; int vga_enabled; @@ -119,15 +120,6 @@ static struct pci_fbuf_softc *fbuf_sc; #define PCI_FBUF_MSI_MSGS 4 static void -pci_fbuf_usage(char *opt) -{ - - EPRINTLN("Invalid fbuf emulation option \"%s\"", opt); - EPRINTLN("fbuf: {wait,}{vga=on|io|off,}rfb=<ip>:port" - "{,w=width}{,h=height}"); -} - -static void pci_fbuf_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size, uint64_t value) { @@ -227,107 +219,137 @@ pci_fbuf_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, return (value); } -static int -pci_fbuf_parse_opts(struct pci_fbuf_softc *sc, char *opts) +static void +pci_fbuf_baraddr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, + int enabled, uint64_t address) { - char *uopts, *uoptsbak, *xopts, *config; - char *tmpstr; - int ret; - - ret = 0; - uoptsbak = uopts = strdup(opts); - while ((xopts = strsep(&uopts, ",")) != NULL) { - if (strcmp(xopts, "wait") == 0) { - sc->rfb_wait = 1; - continue; - } + struct pci_fbuf_softc *sc; + int prot; - if ((config = strchr(xopts, '=')) == NULL) { - pci_fbuf_usage(xopts); - ret = -1; - goto done; - } + if (baridx != 1) + return; - *config++ = '\0'; - - DPRINTF(DEBUG_VERBOSE, ("pci_fbuf option %s = %s", - xopts, config)); - - if (!strcmp(xopts, "tcp") || !strcmp(xopts, "rfb")) { - /* - * IPv4 -- host-ip:port - * IPv6 -- [host-ip%zone]:port - * XXX for now port is mandatory. - */ - tmpstr = strsep(&config, "]"); - if (config) { - if (tmpstr[0] == '[') - tmpstr++; - sc->rfb_host = strdup(tmpstr); - if (config[0] == ':') - config++; - else { - pci_fbuf_usage(xopts); - ret = -1; - goto done; + sc = pi->pi_arg; + if (!enabled && sc->fbaddr != 0) { + if (vm_munmap_memseg(ctx, sc->fbaddr, FB_SIZE) != 0) + EPRINTLN("pci_fbuf: munmap_memseg failed"); + sc->fbaddr = 0; + } else if (sc->fb_base != NULL && sc->fbaddr == 0) { + prot = PROT_READ | PROT_WRITE; + if (vm_mmap_memseg(ctx, address, VM_FRAMEBUFFER, 0, FB_SIZE, prot) != 0) + EPRINTLN("pci_fbuf: mmap_memseg failed"); + sc->fbaddr = address; + } +} + + +static int +pci_fbuf_parse_config(struct pci_fbuf_softc *sc, nvlist_t *nvl) +{ + const char *value; + char *cp; + + sc->rfb_wait = get_config_bool_node_default(nvl, "wait", false); + + /* Prefer "rfb" to "tcp". */ + value = get_config_value_node(nvl, "rfb"); + if (value == NULL) + value = get_config_value_node(nvl, "tcp"); + if (value != NULL) { + /* + * IPv4 -- host-ip:port + * IPv6 -- [host-ip%zone]:port + * XXX for now port is mandatory for IPv4. + */ + if (value[0] == '[') { + cp = strchr(value + 1, ']'); + if (cp == NULL || cp == value + 1) { + EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"", + value); + return (-1); + } + sc->rfb_host = strndup(value + 1, cp - (value + 1)); + cp++; + if (*cp == ':') { + cp++; + if (*cp == '\0') { + EPRINTLN( + "fbuf: Missing port number: \"%s\"", + value); + return (-1); } - sc->rfb_port = atoi(config); + sc->rfb_port = atoi(cp); + } else if (*cp != '\0') { + EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"", + value); + return (-1); + } + } else { + cp = strchr(value, ':'); + if (cp == NULL) { + sc->rfb_port = atoi(value); } else { - config = tmpstr; - tmpstr = strsep(&config, ":"); - if (!config) - sc->rfb_port = atoi(tmpstr); - else { - sc->rfb_port = atoi(config); - sc->rfb_host = strdup(tmpstr); + sc->rfb_host = strndup(value, cp - value); + cp++; + if (*cp == '\0') { + EPRINTLN( + "fbuf: Missing port number: \"%s\"", + value); + return (-1); } + sc->rfb_port = atoi(cp); } + } + } + #ifndef __FreeBSD__ - } else if (!strcmp(xopts, "unix")) { - sc->rfb_unix = strdup(config); + sc->rfb_unix = get_config_value_node(nvl, "unix"); #endif - } else if (!strcmp(xopts, "vga")) { - if (!strcmp(config, "off")) { - sc->vga_enabled = 0; - } else if (!strcmp(config, "io")) { - sc->vga_enabled = 1; - sc->vga_full = 0; - } else if (!strcmp(config, "on")) { - sc->vga_enabled = 1; - sc->vga_full = 1; - } else { - pci_fbuf_usage(xopts); - ret = -1; - goto done; - } - } else if (!strcmp(xopts, "w")) { - sc->memregs.width = atoi(config); - if (sc->memregs.width > COLS_MAX) { - pci_fbuf_usage(xopts); - ret = -1; - goto done; - } else if (sc->memregs.width == 0) - sc->memregs.width = 1920; - } else if (!strcmp(xopts, "h")) { - sc->memregs.height = atoi(config); - if (sc->memregs.height > ROWS_MAX) { - pci_fbuf_usage(xopts); - ret = -1; - goto done; - } else if (sc->memregs.height == 0) - sc->memregs.height = 1080; - } else if (!strcmp(xopts, "password")) { - sc->rfb_password = strdup(config); + + value = get_config_value_node(nvl, "vga"); + if (value != NULL) { + if (strcmp(value, "off") == 0) { + sc->vga_enabled = 0; + } else if (strcmp(value, "io") == 0) { + sc->vga_enabled = 1; + sc->vga_full = 0; + } else if (strcmp(value, "on") == 0) { + sc->vga_enabled = 1; + sc->vga_full = 1; } else { - pci_fbuf_usage(xopts); - ret = -1; - goto done; + EPRINTLN("fbuf: Invalid vga setting: \"%s\"", value); + return (-1); } } -done: - free(uoptsbak); - return (ret); + value = get_config_value_node(nvl, "w"); + if (value != NULL) { + sc->memregs.width = atoi(value); + if (sc->memregs.width > COLS_MAX) { + EPRINTLN("fbuf: width %d too large", sc->memregs.width); + return (-1); + } + if (sc->memregs.width == 0) + sc->memregs.width = 1920; + } + + value = get_config_value_node(nvl, "h"); + if (value != NULL) { + sc->memregs.height = atoi(value); + if (sc->memregs.height > ROWS_MAX) { + EPRINTLN("fbuf: height %d too large", + sc->memregs.height); + return (-1); + } + if (sc->memregs.height == 0) + sc->memregs.height = 1080; + } + + value = get_config_value_node(nvl, "password"); + if (value != NULL) + sc->rfb_password = strdup(value); + + return (0); } @@ -358,7 +380,7 @@ pci_fbuf_render(struct bhyvegc *gc, void *arg) } static int -pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { int error, prot; struct pci_fbuf_softc *sc; @@ -398,7 +420,7 @@ pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) sc->fsc_pi = pi; - error = pci_fbuf_parse_opts(sc, opts); + error = pci_fbuf_parse_config(sc, nvl); if (error != 0) goto done; @@ -462,6 +484,7 @@ struct pci_devemu pci_fbuf = { .pe_emu = "fbuf", .pe_init = pci_fbuf_init, .pe_barwrite = pci_fbuf_write, - .pe_barread = pci_fbuf_read + .pe_barread = pci_fbuf_read, + .pe_baraddr = pci_fbuf_baraddr, }; PCI_EMUL_SET(pci_fbuf); diff --git a/usr/src/cmd/bhyve/pci_hda.c b/usr/src/cmd/bhyve/pci_hda.c index 86e46a550a..7491944fed 100644 --- a/usr/src/cmd/bhyve/pci_hda.c +++ b/usr/src/cmd/bhyve/pci_hda.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include "pci_hda.h" #include "bhyverun.h" +#include "config.h" #include "pci_emul.h" #include "hdac_reg.h" @@ -147,13 +148,11 @@ static inline uint32_t hda_get_reg_by_offset(struct hda_softc *sc, static inline void hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t mask, uint32_t value); -static uint8_t hda_parse_config(const char *opts, const char *key, char *val); -static struct hda_softc *hda_init(const char *opts); +static struct hda_softc *hda_init(nvlist_t *nvl); static void hda_update_intr(struct hda_softc *sc); static void hda_response_interrupt(struct hda_softc *sc); static int hda_codec_constructor(struct hda_softc *sc, - struct hda_codec_class *codec, const char *play, const char *rec, - const char *opts); + struct hda_codec_class *codec, const char *play, const char *rec); static struct hda_codec_class *hda_find_codec_class(const char *name); static int hda_send_command(struct hda_softc *sc, uint32_t verb); @@ -210,7 +209,7 @@ static uint64_t hda_get_clock_ns(void); /* * PCI HDA function declarations */ -static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts); +static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl); static void pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size, uint64_t value); static uint64_t pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, @@ -318,67 +317,20 @@ hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, hda_set_reg_by_offset(sc, offset, reg_value); } -static uint8_t -hda_parse_config(const char *opts, const char *key, char *val) -{ - char buf[64]; - char *s = buf; - char *tmp = NULL; - size_t len; - int i; - - if (!opts) - return (0); - - len = strlen(opts); - if (len >= sizeof(buf)) { - DPRINTF("Opts too big"); - return (0); - } - - DPRINTF("opts: %s", opts); - - strcpy(buf, opts); - - for (i = 0; i < len; i++) - if (buf[i] == ',') { - buf[i] = 0; - tmp = buf + i + 1; - break; - } - - if (!memcmp(s, key, strlen(key))) { - strncpy(val, s + strlen(key), 64); - return (1); - } - - if (!tmp) - return (0); - - s = tmp; - if (!memcmp(s, key, strlen(key))) { - strncpy(val, s + strlen(key), 64); - return (1); - } - - return (0); -} - static struct hda_softc * -hda_init(const char *opts) +hda_init(nvlist_t *nvl) { struct hda_softc *sc = NULL; struct hda_codec_class *codec = NULL; - char play[64]; - char rec[64]; - int err, p, r; + const char *value; + char *play; + char *rec; + int err; #if DEBUG_HDA == 1 dbg = fopen("/tmp/bhyve_hda.log", "w+"); #endif - DPRINTF("opts: %s", opts); - sc = calloc(1, sizeof(*sc)); if (!sc) return (NULL); @@ -386,19 +338,28 @@ hda_init(const char *opts) hda_reset_regs(sc); /* - * TODO search all the codecs declared in opts + * TODO search all configured codecs * For now we play with one single codec */ codec = hda_find_codec_class("hda_codec"); if (codec) { - p = hda_parse_config(opts, "play=", play); - r = hda_parse_config(opts, "rec=", rec); + value = get_config_value_node(nvl, "play"); + if (value == NULL) + play = NULL; + else + play = strdup(value); + value = get_config_value_node(nvl, "rec"); + if (value == NULL) + rec = NULL; + else + rec = strdup(value); DPRINTF("play: %s rec: %s", play, rec); - if (p | r) { - err = hda_codec_constructor(sc, codec, p ? \ - play : NULL, r ? rec : NULL, NULL); + if (play != NULL || rec != NULL) { + err = hda_codec_constructor(sc, codec, play, rec); assert(!err); } + free(play); + free(rec); } return (sc); @@ -470,7 +431,7 @@ hda_response_interrupt(struct hda_softc *sc) static int hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, - const char *play, const char *rec, const char *opts) + const char *play, const char *rec) { struct hda_codec_inst *hci = NULL; @@ -493,7 +454,7 @@ hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, return (-1); } - return (codec->init(hci, play, rec, opts)); + return (codec->init(hci, play, rec)); } static struct hda_codec_class * @@ -1263,7 +1224,7 @@ static uint64_t hda_get_clock_ns(void) * PCI HDA function definitions */ static int -pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct hda_softc *sc = NULL; @@ -1285,7 +1246,7 @@ pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) /* allocate an IRQ pin for our slot */ pci_lintr_request(pi); - sc = hda_init(opts); + sc = hda_init(nvl); if (!sc) return (-1); diff --git a/usr/src/cmd/bhyve/pci_hda.h b/usr/src/cmd/bhyve/pci_hda.h index 7b6bba92e4..65a85f6d60 100644 --- a/usr/src/cmd/bhyve/pci_hda.h +++ b/usr/src/cmd/bhyve/pci_hda.h @@ -72,7 +72,7 @@ struct hda_codec_inst { struct hda_codec_class { char *name; int (*init)(struct hda_codec_inst *hci, const char *play, - const char *rec, const char *opts); + const char *rec); int (*reset)(struct hda_codec_inst *hci); int (*command)(struct hda_codec_inst *hci, uint32_t cmd_data); int (*notify)(struct hda_codec_inst *hci, uint8_t run, uint8_t stream, diff --git a/usr/src/cmd/bhyve/pci_hostbridge.c b/usr/src/cmd/bhyve/pci_hostbridge.c index b926c7817e..e59affb92e 100644 --- a/usr/src/cmd/bhyve/pci_hostbridge.c +++ b/usr/src/cmd/bhyve/pci_hostbridge.c @@ -38,68 +38,12 @@ #endif __FBSDID("$FreeBSD$"); -#include "pci_emul.h" - -#ifdef __FreeBSD__ -static int -pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) -{ - - /* config space */ - pci_set_cfgdata16(pi, PCIR_VENDOR, 0x1275); /* NetApp */ - pci_set_cfgdata16(pi, PCIR_DEVICE, 0x1275); /* NetApp */ - pci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL); - pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); - pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST); - - pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT); - - return (0); -} - -static int -pci_amd_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) -{ - (void) pci_hostbridge_init(ctx, pi, opts); - pci_set_cfgdata16(pi, PCIR_VENDOR, 0x1022); /* AMD */ - pci_set_cfgdata16(pi, PCIR_DEVICE, 0x7432); /* made up */ - - return (0); -} -#else -static void -pci_hostbridge_setup(struct pci_devinst *pi, uint16_t vendor, uint16_t device) -{ - /* config space */ - pci_set_cfgdata16(pi, PCIR_VENDOR, vendor); - pci_set_cfgdata16(pi, PCIR_DEVICE, device); - pci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL); - pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); - pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST); - - pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT); -} - - -static int -pci_hostbridge_parse_pci_val(const char *in, uint16_t *val) -{ - long num; - char *endp = NULL; +#include <stdlib.h> - errno = 0; - num = strtol(in, &endp, 0); - if (errno != 0 || endp == NULL || *endp != '\0') { - fprintf(stderr, "pci_hostbridge: invalid num '%s'", in); - return (-1); - } else if (num < 1 || num > UINT16_MAX) { - fprintf(stderr, "pci_hostbridge: 0x%04lx out of range", num); - return (-1); - } - *val = num; - return (0); -} +#include "config.h" +#include "pci_emul.h" +#ifndef __FreeBSD__ static struct pci_hostbridge_model { const char *phm_model; uint16_t phm_vendor; @@ -112,58 +56,30 @@ static struct pci_hostbridge_model { }; #define NUM_HB_MODELS (sizeof (pci_hb_models) / sizeof (pci_hb_models[0])) +#endif static int -pci_hostbridge_parse_args(char *opts, uint16_t *vendorp, uint16_t *devicep) +pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { - const char *model = NULL; - char *next; - uint16_t vendor = 0, device = 0; - int err = 0; - - for (; opts != NULL && *opts != '\0'; opts = next) { - char *val, *cp; - - if ((cp = strchr(opts, ',')) != NULL) { - *cp = '\0'; - next = cp + 1; - } else { - next = NULL; - } + const char *value; + u_int vendor, device; - if ((cp = strchr(opts, '=')) == NULL) { - fprintf(stderr, - "pci_hostbridge: expected value for param" - " (%s=VAL)", opts); - err = -1; - continue; - } +#ifdef __FreeBSD__ + vendor = 0x1275; /* NetApp */ + device = 0x1275; /* NetApp */ +#else + vendor = device = 0; +#endif - /* <param>=<value> handling */ - val = cp + 1; - *cp = '\0'; - if (strcmp(opts, "model") == 0) { - model = val; - } else if (strcmp(opts, "vendor") == 0) { - if (pci_hostbridge_parse_pci_val(val, &vendor) != 0) { - err = -1; - continue; - } - } else if (strcmp(opts, "device") == 0) { - if (pci_hostbridge_parse_pci_val(val, &device) != 0) { - err = -1; - continue; - } - } else { - fprintf(stderr, - "pci_hostbridge: unrecognized option '%s'", opts); - err = -1; - continue; - } - } - if (err != 0) { - return (err); - } + value = get_config_value_node(nvl, "vendor"); + if (value != NULL) + vendor = strtol(value, NULL, 0); + value = get_config_value_node(nvl, "devid"); + if (value != NULL) + device = strtol(value, NULL, 0); + +#ifndef __FreeBSD__ + const char *model = get_config_value_node(nvl, "model"); if (model != NULL && (vendor != 0 || device != 0)) { fprintf(stderr, "pci_hostbridge: cannot specify model " @@ -175,57 +91,53 @@ pci_hostbridge_parse_args(char *opts, uint16_t *vendorp, uint16_t *devicep) "device for custom hostbridge"); return (-1); } - if (model != NULL) { - uint_t i; + if (model == NULL && vendor == 0 && device == 0) + model = "netapp"; - for (i = 0; i < NUM_HB_MODELS; i++) { + if (model != NULL) { + for (uint_t i = 0; i < NUM_HB_MODELS; i++) { if (strcmp(model, pci_hb_models[i].phm_model) != 0) continue; /* found a model match */ - *vendorp = pci_hb_models[i].phm_vendor; - *devicep = pci_hb_models[i].phm_device; - return (0); + vendor = pci_hb_models[i].phm_vendor; + device = pci_hb_models[i].phm_device; + break; + } + if (vendor == 0) { + fprintf(stderr, "pci_hostbridge: invalid model '%s'", + model); + return (-1); } - fprintf(stderr, "pci_hostbridge: invalid model '%s'", model); - return (-1); } +#endif /* !__FreeBSD__ */ - /* custom hostbridge ID was specified */ - *vendorp = vendor; - *devicep = device; - return (0); -} - -static int -pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) -{ - uint16_t vendor, device; + /* config space */ + pci_set_cfgdata16(pi, PCIR_VENDOR, vendor); + pci_set_cfgdata16(pi, PCIR_DEVICE, device); + pci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL); + pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); + pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST); - if (opts == NULL) { - /* Fall back to NetApp default if no options are specified */ - vendor = 0x1275; - device = 0x1275; - } else if (pci_hostbridge_parse_args(opts, &vendor, &device) != 0) { - return (-1); - } + pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT); - pci_hostbridge_setup(pi, vendor, device); return (0); } static int -pci_amd_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_amd_hostbridge_legacy_config(nvlist_t *nvl, const char *opts) { - pci_hostbridge_setup(pi, 0x1022, 0x7432); + + set_config_value_node(nvl, "vendor", "0x1022"); /* AMD */ + set_config_value_node(nvl, "devid", "0x7432"); /* made up */ + return (0); } -#endif /* __FreeBSD__ */ - struct pci_devemu pci_de_amd_hostbridge = { .pe_emu = "amd_hostbridge", - .pe_init = pci_amd_hostbridge_init, + .pe_legacy_config = pci_amd_hostbridge_legacy_config, + .pe_alias = "hostbridge", }; PCI_EMUL_SET(pci_de_amd_hostbridge); diff --git a/usr/src/cmd/bhyve/pci_lpc.c b/usr/src/cmd/bhyve/pci_lpc.c index 9c8f25e89d..2387f382c5 100644 --- a/usr/src/cmd/bhyve/pci_lpc.c +++ b/usr/src/cmd/bhyve/pci_lpc.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include "acpi.h" #include "debug.h" #include "bootrom.h" +#include "config.h" #include "inout.h" #include "pci_emul.h" #include "pci_irq.h" @@ -71,20 +72,21 @@ SYSRES_IO(NMISC_PORT, 1); static struct pci_devinst *lpc_bridge; -static const char *romfile; - -#define LPC_UART_NUM 2 +#define LPC_UART_NUM 4 static struct lpc_uart_softc { struct uart_softc *uart_softc; - const char *opts; int iobase; int irq; int enabled; } lpc_uart_softc[LPC_UART_NUM]; -static const char *lpc_uart_names[LPC_UART_NUM] = { "COM1", "COM2" }; +static const char *lpc_uart_names[LPC_UART_NUM] = { + "com1", "com2", "com3", "com4" +}; -static bool pctestdev_present; +static const char *lpc_uart_acpi_names[LPC_UART_NUM] = { + "COM1", "COM2", "COM3", "COM4" +}; /* * LPC device configuration is in the following form: @@ -95,41 +97,38 @@ int lpc_device_parse(const char *opts) { int unit, error; - char *str, *cpy, *lpcdev; + char *str, *cpy, *lpcdev, *node_name; error = -1; str = cpy = strdup(opts); lpcdev = strsep(&str, ","); if (lpcdev != NULL) { if (strcasecmp(lpcdev, "bootrom") == 0) { - romfile = str; + set_config_value("lpc.bootrom", str); error = 0; goto done; } for (unit = 0; unit < LPC_UART_NUM; unit++) { if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) { - lpc_uart_softc[unit].opts = str; + asprintf(&node_name, "lpc.%s.path", + lpc_uart_names[unit]); + set_config_value(node_name, str); + free(node_name); error = 0; goto done; } } if (strcasecmp(lpcdev, pctestdev_getname()) == 0) { - if (pctestdev_present) { - EPRINTLN("More than one %s device conf is " - "specified; only one is allowed.", - pctestdev_getname()); - } else if (pctestdev_parse(str) == 0) { - pctestdev_present = true; - error = 0; - free(cpy); - goto done; - } + asprintf(&node_name, "lpc.%s", pctestdev_getname()); + set_config_bool(node_name, true); + free(node_name); + error = 0; + goto done; } } done: - if (error) - free(cpy); + free(cpy); return (error); } @@ -149,7 +148,7 @@ const char * lpc_bootrom(void) { - return (romfile); + return (get_config_value("lpc.bootrom")); } static void @@ -223,9 +222,11 @@ lpc_init(struct vmctx *ctx) { struct lpc_uart_softc *sc; struct inout_port iop; - const char *name; + const char *backend, *name, *romfile; + char *node_name; int unit, error; + romfile = get_config_value("lpc.bootrom"); if (romfile != NULL) { error = bootrom_loadrom(ctx, romfile); if (error) @@ -247,9 +248,12 @@ lpc_init(struct vmctx *ctx) sc->uart_softc = uart_init(lpc_uart_intr_assert, lpc_uart_intr_deassert, sc); - if (uart_set_backend(sc->uart_softc, sc->opts) != 0) { + asprintf(&node_name, "lpc.%s.path", name); + backend = get_config_value(node_name); + free(node_name); + if (uart_set_backend(sc->uart_softc, backend) != 0) { EPRINTLN("Unable to initialize backend '%s' " - "for LPC device %s", sc->opts, name); + "for LPC device %s", backend, name); return (-1); } @@ -267,11 +271,13 @@ lpc_init(struct vmctx *ctx) } /* pc-testdev */ - if (pctestdev_present) { + asprintf(&node_name, "lpc.%s", pctestdev_getname()); + if (get_config_bool_default(node_name, false)) { error = pctestdev_init(ctx); if (error) return (error); } + free(node_name); return (0); } @@ -380,7 +386,7 @@ pci_lpc_uart_dsdt(void) if (!sc->enabled) continue; dsdt_line(""); - dsdt_line("Device (%s)", lpc_uart_names[unit]); + dsdt_line("Device (%s)", lpc_uart_acpi_names[unit]); dsdt_line("{"); dsdt_line(" Name (_HID, EisaId (\"PNP0501\"))"); dsdt_line(" Name (_UID, %d)", unit + 1); @@ -434,7 +440,7 @@ pci_lpc_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, #define LPC_VENDOR 0x8086 static int -pci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { /* diff --git a/usr/src/cmd/bhyve/pci_nvme.c b/usr/src/cmd/bhyve/pci_nvme.c index a0a8a9571d..c8fd44aa52 100644 --- a/usr/src/cmd/bhyve/pci_nvme.c +++ b/usr/src/cmd/bhyve/pci_nvme.c @@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$"); #include "bhyverun.h" #include "block_if.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" @@ -581,8 +582,9 @@ pci_nvme_init_nsdata(struct pci_nvme_softc *sc, char *data = NULL; uint64_t eui64 = nvstore->eui64; - asprintf(&data, "%s%u%u%u", vmname, sc->nsc_pi->pi_bus, - sc->nsc_pi->pi_slot, sc->nsc_pi->pi_func); + asprintf(&data, "%s%u%u%u", get_config_value("name"), + sc->nsc_pi->pi_bus, sc->nsc_pi->pi_slot, + sc->nsc_pi->pi_func); if (data != NULL) { eui64 = OUI_FREEBSD_NVME_LOW | crc16(0, data, strlen(data)); @@ -1080,9 +1082,13 @@ static int nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command, struct nvme_completion* compl) { - uint32_t logsize = 0; + uint32_t logsize; uint8_t logpage = command->cdw10 & 0xFF; +#ifndef __FreeBSD__ + logsize = 0; +#endif + DPRINTF("%s log page %u len %u", __func__, logpage, logsize); pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS); @@ -1140,7 +1146,11 @@ nvme_opc_identify(struct pci_nvme_softc* sc, struct nvme_command* command, struct nvme_completion* compl) { void *dest; - uint16_t status = 0; + uint16_t status; + +#ifndef __FreeBSD__ + status = 0; +#endif DPRINTF("%s identify 0x%x nsid 0x%x", __func__, command->cdw10 & 0xFF, command->nsid); @@ -1866,7 +1876,11 @@ pci_nvme_io_done(struct blockif_req *br, int err) { struct pci_nvme_ioreq *req = br->br_param; struct nvme_submission_queue *sq = req->nvme_sq; - uint16_t code, status = 0; + uint16_t code, status; + +#ifndef __FreeBSD__ + status = 0; +#endif DPRINTF("%s error %d %s", __func__, err, strerror(err)); @@ -1929,7 +1943,11 @@ nvme_write_read_ram(struct pci_nvme_softc *sc, { uint8_t *buf = nvstore->ctx; enum nvme_copy_dir dir; - uint16_t status = 0; + uint16_t status; + +#ifndef __FreeBSD__ + status = 0; +#endif if (is_write) dir = NVME_COPY_TO_PRP; @@ -2029,11 +2047,15 @@ nvme_opc_write_read(struct pci_nvme_softc *sc, struct pci_nvme_ioreq *req, uint16_t *status) { - uint64_t lba, nblocks, bytes = 0; + uint64_t lba, nblocks, bytes; size_t offset; bool is_write = cmd->opc == NVME_OPC_WRITE; bool pending = false; +#ifndef __FreeBSD__ + bytes = 0; +#endif + lba = ((uint64_t)cmd->cdw11 << 32) | cmd->cdw10; nblocks = (cmd->cdw12 & 0xFFFF) + 1; if (pci_nvme_out_of_range(nvstore, lba, nblocks)) { @@ -2081,10 +2103,10 @@ pci_nvme_dealloc_sm(struct blockif_req *br, int err) struct pci_nvme_ioreq *req = br->br_param; struct pci_nvme_softc *sc = req->sc; bool done = true; -#ifdef __FreeBSD__ uint16_t status; -#else - uint16_t status = 0; + +#ifndef __FreeBSD__ + status = 0; #endif if (err) { @@ -2121,11 +2143,15 @@ nvme_opc_dataset_mgmt(struct pci_nvme_softc *sc, struct pci_nvme_ioreq *req, uint16_t *status) { - struct nvme_dsm_range *range = NULL; + struct nvme_dsm_range *range; uint32_t nr, r, non_zero, dr; int err; bool pending = false; +#ifndef __FreeBSD__ + range = NULL; +#endif + if ((sc->ctrldata.oncs & NVME_ONCS_DSM) == 0) { pci_nvme_status_genc(status, NVME_SC_INVALID_OPCODE); goto out; @@ -2237,9 +2263,13 @@ static void pci_nvme_handle_io_cmd(struct pci_nvme_softc* sc, uint16_t idx) { struct nvme_submission_queue *sq; - uint16_t status = 0; + uint16_t status; uint16_t sqhead; +#ifndef __FreeBSD__ + status = 0; +#endif + /* handle all submissions up to sq->tail index */ sq = &sc->submit_queues[idx]; @@ -2624,14 +2654,12 @@ pci_nvme_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, return (0); } - static int -pci_nvme_parse_opts(struct pci_nvme_softc *sc, char *opts) +pci_nvme_parse_config(struct pci_nvme_softc *sc, nvlist_t *nvl) { char bident[sizeof("XX:X:X")]; - char *uopt, *xopts, *config; + const char *value; uint32_t sectsz; - int optidx; sc->max_queues = NVME_QUEUES; sc->max_qentries = NVME_MAX_QENTRIES; @@ -2640,81 +2668,81 @@ pci_nvme_parse_opts(struct pci_nvme_softc *sc, char *opts) sc->num_cqueues = sc->max_queues; sc->dataset_management = NVME_DATASET_MANAGEMENT_AUTO; sectsz = 0; - - uopt = strdup(opts); - optidx = 0; snprintf(sc->ctrldata.sn, sizeof(sc->ctrldata.sn), "NVME-%d-%d", sc->nsc_pi->pi_slot, sc->nsc_pi->pi_func); - for (xopts = strtok(uopt, ","); - xopts != NULL; - xopts = strtok(NULL, ",")) { - - if ((config = strchr(xopts, '=')) != NULL) - *config++ = '\0'; - - if (!strcmp("maxq", xopts)) { - sc->max_queues = atoi(config); - } else if (!strcmp("qsz", xopts)) { - sc->max_qentries = atoi(config); - } else if (!strcmp("ioslots", xopts)) { - sc->ioslots = atoi(config); - } else if (!strcmp("sectsz", xopts)) { - sectsz = atoi(config); - } else if (!strcmp("ser", xopts)) { - /* - * This field indicates the Product Serial Number in - * 7-bit ASCII, unused bytes should be space characters. - * Ref: NVMe v1.3c. - */ - cpywithpad((char *)sc->ctrldata.sn, - sizeof(sc->ctrldata.sn), config, ' '); - } else if (!strcmp("ram", xopts)) { - uint64_t sz = strtoull(&xopts[4], NULL, 10); - - sc->nvstore.type = NVME_STOR_RAM; - sc->nvstore.size = sz * 1024 * 1024; - sc->nvstore.ctx = calloc(1, sc->nvstore.size); - sc->nvstore.sectsz = 4096; - sc->nvstore.sectsz_bits = 12; - if (sc->nvstore.ctx == NULL) { - perror("Unable to allocate RAM"); - free(uopt); - return (-1); - } - } else if (!strcmp("eui64", xopts)) { - sc->nvstore.eui64 = htobe64(strtoull(config, NULL, 0)); - } else if (!strcmp("dsm", xopts)) { - if (!strcmp("auto", config)) - sc->dataset_management = NVME_DATASET_MANAGEMENT_AUTO; - else if (!strcmp("enable", config)) - sc->dataset_management = NVME_DATASET_MANAGEMENT_ENABLE; - else if (!strcmp("disable", config)) - sc->dataset_management = NVME_DATASET_MANAGEMENT_DISABLE; - } else if (optidx == 0) { - snprintf(bident, sizeof(bident), "%d:%d", - sc->nsc_pi->pi_slot, sc->nsc_pi->pi_func); - sc->nvstore.ctx = blockif_open(xopts, bident); - if (sc->nvstore.ctx == NULL) { - perror("Could not open backing file"); - free(uopt); - return (-1); - } - sc->nvstore.type = NVME_STOR_BLOCKIF; - sc->nvstore.size = blockif_size(sc->nvstore.ctx); - } else { - EPRINTLN("Invalid option %s", xopts); - free(uopt); + + value = get_config_value_node(nvl, "maxq"); + if (value != NULL) + sc->max_queues = atoi(value); + value = get_config_value_node(nvl, "qsz"); + if (value != NULL) { + sc->max_qentries = atoi(value); + if (sc->max_qentries <= 0) { + EPRINTLN("nvme: Invalid qsz option %d", + sc->max_qentries); return (-1); } - - optidx++; } - free(uopt); - - if (sc->nvstore.ctx == NULL || sc->nvstore.size == 0) { - EPRINTLN("backing store not specified"); - return (-1); + value = get_config_value_node(nvl, "ioslots"); + if (value != NULL) { + sc->ioslots = atoi(value); + if (sc->ioslots <= 0) { + EPRINTLN("Invalid ioslots option %d", sc->ioslots); + return (-1); + } } + value = get_config_value_node(nvl, "sectsz"); + if (value != NULL) + sectsz = atoi(value); + value = get_config_value_node(nvl, "ser"); + if (value != NULL) { + /* + * This field indicates the Product Serial Number in + * 7-bit ASCII, unused bytes should be space characters. + * Ref: NVMe v1.3c. + */ + cpywithpad((char *)sc->ctrldata.sn, + sizeof(sc->ctrldata.sn), value, ' '); + } + value = get_config_value_node(nvl, "eui64"); + if (value != NULL) + sc->nvstore.eui64 = htobe64(strtoull(value, NULL, 0)); + value = get_config_value_node(nvl, "dsm"); + if (value != NULL) { + if (strcmp(value, "auto") == 0) + sc->dataset_management = NVME_DATASET_MANAGEMENT_AUTO; + else if (strcmp(value, "enable") == 0) + sc->dataset_management = NVME_DATASET_MANAGEMENT_ENABLE; + else if (strcmp(value, "disable") == 0) + sc->dataset_management = NVME_DATASET_MANAGEMENT_DISABLE; + } + + value = get_config_value_node(nvl, "ram"); + if (value != NULL) { + uint64_t sz = strtoull(value, NULL, 10); + + sc->nvstore.type = NVME_STOR_RAM; + sc->nvstore.size = sz * 1024 * 1024; + sc->nvstore.ctx = calloc(1, sc->nvstore.size); + sc->nvstore.sectsz = 4096; + sc->nvstore.sectsz_bits = 12; + if (sc->nvstore.ctx == NULL) { + EPRINTLN("nvme: Unable to allocate RAM"); + return (-1); + } + } else { + snprintf(bident, sizeof(bident), "%d:%d", + sc->nsc_pi->pi_slot, sc->nsc_pi->pi_func); + sc->nvstore.ctx = blockif_open(nvl, bident); + if (sc->nvstore.ctx == NULL) { + EPRINTLN("nvme: Could not open backing file: %s", + strerror(errno)); + return (-1); + } + sc->nvstore.type = NVME_STOR_BLOCKIF; + sc->nvstore.size = blockif_size(sc->nvstore.ctx); + } + if (sectsz == 512 || sectsz == 4096 || sectsz == 8192) sc->nvstore.sectsz = sectsz; else if (sc->nvstore.type != NVME_STOR_RAM) @@ -2726,20 +2754,11 @@ pci_nvme_parse_opts(struct pci_nvme_softc *sc, char *opts) if (sc->max_queues <= 0 || sc->max_queues > NVME_QUEUES) sc->max_queues = NVME_QUEUES; - if (sc->max_qentries <= 0) { - EPRINTLN("Invalid qsz option"); - return (-1); - } - if (sc->ioslots <= 0) { - EPRINTLN("Invalid ioslots option"); - return (-1); - } - return (0); } static int -pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct pci_nvme_softc *sc; uint32_t pci_membar_sz; @@ -2751,7 +2770,7 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pi->pi_arg = sc; sc->nsc_pi = pi; - error = pci_nvme_parse_opts(sc, opts); + error = pci_nvme_parse_config(sc, nvl); if (error < 0) goto done; else @@ -2828,6 +2847,7 @@ done: struct pci_devemu pci_de_nvme = { .pe_emu = "nvme", .pe_init = pci_nvme_init, + .pe_legacy_config = blockif_legacy_config, .pe_barwrite = pci_nvme_write, .pe_barread = pci_nvme_read }; diff --git a/usr/src/cmd/bhyve/pci_passthru.c b/usr/src/cmd/bhyve/pci_passthru.c index c777c56cb1..30f0823726 100644 --- a/usr/src/cmd/bhyve/pci_passthru.c +++ b/usr/src/cmd/bhyve/pci_passthru.c @@ -62,6 +62,9 @@ __FBSDID("$FreeBSD$"); #include <machine/vmm.h> #include <vmmapi.h> #include <sys/ppt_dev.h> + +#include "config.h" +#include "debug.h" #include "pci_emul.h" #include "mem.h" @@ -503,11 +506,11 @@ passthru_msix_table_write(struct vmctx *ctx, int vcpu, static int init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) { - int error, idx; - size_t len, remaining; + int idx; + size_t remaining __unused; uint32_t table_size, table_offset; uint32_t pba_size, pba_offset; - vm_paddr_t start; + vm_paddr_t start __unused; struct pci_devinst *pi = sc->psc_pi; assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0); @@ -561,31 +564,6 @@ init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) } } - /* Map everything before the MSI-X table */ - if (table_offset > 0) { - len = table_offset; - error = vm_map_pptdev_mmio(ctx, sc->pptfd, start, len, base); - if (error) - return (error); - - base += len; - start += len; - remaining -= len; - } - - /* Skip the MSI-X table */ - base += table_size; - start += table_size; - remaining -= table_size; - - /* Map everything beyond the end of the MSI-X table */ - if (remaining > 0) { - len = remaining; - error = vm_map_pptdev_mmio(ctx, sc->pptfd, start, len, base); - if (error) - return (error); - } - return (0); } @@ -631,12 +609,6 @@ cfginitbar(struct vmctx *ctx, struct passthru_softc *sc) error = init_msix_table(ctx, sc, base); if (error) return (-1); - } else if (bartype != PCIBAR_IO) { - /* Map the physical BAR in the guest MMIO space */ - error = vm_map_pptdev_mmio(ctx, sc->pptfd, - pi->pi_bar[i].addr, pi->pi_bar[i].size, base); - if (error) - return (-1); } /* @@ -672,10 +644,23 @@ cfginit(struct vmctx *ctx, struct passthru_softc *sc) } static int -passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +passthru_legacy_config(nvlist_t *nvl, const char *opts) +{ + if (opts == NULL) + return (0); + + if (strncmp(opts, "/dev/ppt", 8) == 0) + set_config_value_node(nvl, "path", opts); + + return (0); +} + +static int +passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { int error, memflags, pptfd; struct passthru_softc *sc; + const char *path; sc = NULL; error = 1; @@ -686,7 +671,8 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) goto done; } - if (opts == NULL || passthru_dev_open(opts, &pptfd) != 0) { + path = get_config_value_node(nvl, "path"); + if (path == NULL || passthru_dev_open(path, &pptfd) != 0) { warnx("invalid passthru options"); goto done; } @@ -930,12 +916,85 @@ passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, return (val); } +static void +passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, + int enabled, uint64_t address) +{ + struct passthru_softc *sc; + size_t remaining; + uint32_t table_size, table_offset; + + sc = pi->pi_arg; + table_offset = rounddown2(pi->pi_msix.table_offset, 4096); + if (table_offset > 0) { + if (!enabled) { + if (vm_unmap_pptdev_mmio(ctx, sc->pptfd, address, + table_offset) != 0) + warnx("pci_passthru: unmap_pptdev_mmio failed"); + } else { + if (vm_map_pptdev_mmio(ctx, sc->pptfd, address, + table_offset, sc->psc_bar[baridx].addr) != 0) + warnx("pci_passthru: map_pptdev_mmio failed"); + } + } + table_size = pi->pi_msix.table_offset - table_offset; + table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; + table_size = roundup2(table_size, 4096); + remaining = pi->pi_bar[baridx].size - table_offset - table_size; + if (remaining > 0) { + address += table_offset + table_size; + if (!enabled) { + if (vm_unmap_pptdev_mmio(ctx, sc->pptfd, address, + remaining) != 0) + warnx("pci_passthru: unmap_pptdev_mmio failed"); + } else { + if (vm_map_pptdev_mmio(ctx, sc->pptfd, address, + remaining, sc->psc_bar[baridx].addr + + table_offset + table_size) != 0) + warnx("pci_passthru: map_pptdev_mmio failed"); + } + } +} + +static void +passthru_mmio_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, + int enabled, uint64_t address) +{ + struct passthru_softc *sc; + + sc = pi->pi_arg; + if (!enabled) { + if (vm_unmap_pptdev_mmio(ctx, sc->pptfd, address, + sc->psc_bar[baridx].size) != 0) + warnx("pci_passthru: unmap_pptdev_mmio failed"); + } else { + if (vm_map_pptdev_mmio(ctx, sc->pptfd, address, + sc->psc_bar[baridx].size, sc->psc_bar[baridx].addr) != 0) + warnx("pci_passthru: map_pptdev_mmio failed"); + } +} + +static void +passthru_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, + int enabled, uint64_t address) +{ + + if (pi->pi_bar[baridx].type == PCIBAR_IO) + return; + if (baridx == pci_msix_table_bar(pi)) + passthru_msix_addr(ctx, pi, baridx, enabled, address); + else + passthru_mmio_addr(ctx, pi, baridx, enabled, address); +} + struct pci_devemu passthru = { .pe_emu = "passthru", .pe_init = passthru_init, + .pe_legacy_config = passthru_legacy_config, .pe_cfgwrite = passthru_cfgwrite, .pe_cfgread = passthru_cfgread, .pe_barwrite = passthru_write, .pe_barread = passthru_read, + .pe_baraddr = passthru_addr, }; PCI_EMUL_SET(passthru); diff --git a/usr/src/cmd/bhyve/pci_uart.c b/usr/src/cmd/bhyve/pci_uart.c index 2e8177bafb..25ef1ed662 100644 --- a/usr/src/cmd/bhyve/pci_uart.c +++ b/usr/src/cmd/bhyve/pci_uart.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #include "uart_emul.h" @@ -89,9 +90,19 @@ pci_uart_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, } static int -pci_uart_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_uart_legacy_config(nvlist_t *nvl, const char *opts) +{ + + if (opts != NULL) + set_config_value_node(nvl, "path", opts); + return (0); +} + +static int +pci_uart_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct uart_softc *sc; + const char *device; pci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_IO_BAR_SIZE); pci_lintr_request(pi); @@ -104,9 +115,10 @@ pci_uart_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) sc = uart_init(pci_uart_intr_assert, pci_uart_intr_deassert, pi); pi->pi_arg = sc; - if (uart_set_backend(sc, opts) != 0) { + device = get_config_value_node(nvl, "path"); + if (uart_set_backend(sc, device) != 0) { EPRINTLN("Unable to initialize backend '%s' for " - "pci uart at %d:%d", opts, pi->pi_slot, pi->pi_func); + "pci uart at %d:%d", device, pi->pi_slot, pi->pi_func); return (-1); } @@ -116,6 +128,7 @@ pci_uart_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) struct pci_devemu pci_de_com = { .pe_emu = "uart", .pe_init = pci_uart_init, + .pe_legacy_config = pci_uart_legacy_config, .pe_barwrite = pci_uart_write, .pe_barread = pci_uart_read }; diff --git a/usr/src/cmd/bhyve/pci_virtio_block.c b/usr/src/cmd/bhyve/pci_virtio_block.c index 27d743a770..85c3f07b31 100644 --- a/usr/src/cmd/bhyve/pci_virtio_block.c +++ b/usr/src/cmd/bhyve/pci_virtio_block.c @@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include <md5.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #include "virtio.h" @@ -416,26 +417,22 @@ pci_vtblk_notify(void *vsc, struct vqueue_info *vq) } static int -pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { char bident[sizeof("XX:X:X")]; struct blockif_ctxt *bctxt; + const char *path; MD5_CTX mdctx; u_char digest[16]; struct pci_vtblk_softc *sc; off_t size; int i, sectsz, sts, sto; - if (opts == NULL) { - WPRINTF(("virtio-block: backing device required")); - return (1); - } - /* * The supplied backing file has to exist */ snprintf(bident, sizeof(bident), "%d:%d", pi->pi_slot, pi->pi_func); - bctxt = blockif_open(opts, bident); + bctxt = blockif_open(nvl, bident); if (bctxt == NULL) { perror("Could not open backing file"); return (1); @@ -478,8 +475,9 @@ pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) * Create an identifier for the backing file. Use parts of the * md5 sum of the filename */ + path = get_config_value_node(nvl, "path"); MD5Init(&mdctx); - MD5Update(&mdctx, opts, strlen(opts)); + MD5Update(&mdctx, path, strlen(path)); MD5Final(digest, &mdctx); snprintf(sc->vbsc_ident, VTBLK_BLK_ID_BYTES, "BHYVE-%02X%02X-%02X%02X-%02X%02X", @@ -520,7 +518,7 @@ pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_BLOCK); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE); - pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_BLOCK); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_BLOCK); pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); if (vi_intr_init(&sc->vbsc_vs, 1, fbsdrun_virtio_msix())) { @@ -569,6 +567,7 @@ pci_vtblk_apply_feats(void *vsc, uint64_t caps) struct pci_devemu pci_de_vblk = { .pe_emu = "virtio-blk", .pe_init = pci_vtblk_init, + .pe_legacy_config = blockif_legacy_config, .pe_barwrite = vi_pci_write, .pe_barread = vi_pci_read }; diff --git a/usr/src/cmd/bhyve/pci_virtio_console.c b/usr/src/cmd/bhyve/pci_virtio_console.c index 5799b20f6a..f4aa292536 100644 --- a/usr/src/cmd/bhyve/pci_virtio_console.c +++ b/usr/src/cmd/bhyve/pci_virtio_console.c @@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include <sysexits.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #include "virtio.h" @@ -132,7 +133,6 @@ struct pci_vtcon_softc { uint64_t vsc_features; char * vsc_rootdir; int vsc_kq; - int vsc_nports; bool vsc_ready; struct pci_vtcon_port vsc_control_port; struct pci_vtcon_port vsc_ports[VTCON_MAXPORTS]; @@ -246,18 +246,17 @@ pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue) } static struct pci_vtcon_port * -pci_vtcon_port_add(struct pci_vtcon_softc *sc, const char *name, +pci_vtcon_port_add(struct pci_vtcon_softc *sc, int port_id, const char *name, pci_vtcon_cb_t *cb, void *arg) { struct pci_vtcon_port *port; - if (sc->vsc_nports == VTCON_MAXPORTS) { + port = &sc->vsc_ports[port_id]; + if (port->vsp_enabled) { errno = EBUSY; return (NULL); } - - port = &sc->vsc_ports[sc->vsc_nports++]; - port->vsp_id = sc->vsc_nports - 1; + port->vsp_id = port_id; port->vsp_sc = sc; port->vsp_name = name; port->vsp_cb = cb; @@ -268,7 +267,7 @@ pci_vtcon_port_add(struct pci_vtcon_softc *sc, const char *name, port->vsp_txq = 0; port->vsp_rxq = 1; } else { - port->vsp_txq = sc->vsc_nports * 2; + port->vsp_txq = (port_id + 1) * 2; port->vsp_rxq = port->vsp_txq + 1; } @@ -277,22 +276,39 @@ pci_vtcon_port_add(struct pci_vtcon_softc *sc, const char *name, } static int -pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *name, - const char *path) +pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *port_name, + const nvlist_t *nvl) { - struct pci_vtcon_sock *sock; #ifdef __FreeBSD__ + struct pci_vtcon_sock *sock; struct sockaddr_un sun; - char *pathcopy; #else + struct pci_vtcon_sock *sock = NULL; /* Our compiler #defines 'sun' as '1'. Awesome. */ struct sockaddr_un addr; #endif + const char *name, *path; + char *cp, *pathcopy; + long port; int s = -1, fd = -1, error = 0; #ifndef WITHOUT_CAPSICUM cap_rights_t rights; #endif + port = strtol(port_name, &cp, 0); + if (*cp != '\0' || port < 0 || port >= VTCON_MAXPORTS) { + EPRINTLN("vtcon: Invalid port %s", port_name); + error = -1; + goto out; + } + + path = get_config_value_node(nvl, "path"); + if (path == NULL) { + EPRINTLN("vtcon: required path missing for port %ld", port); + error = -1; + goto out; + } + sock = calloc(1, sizeof(struct pci_vtcon_sock)); if (sock == NULL) { error = -1; @@ -331,8 +347,9 @@ pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *name, } #else /* __FreeBSD__ */ /* Do a simple bind rather than the FreeBSD bindat() */ + pathcopy = (char *)path; addr.sun_family = AF_UNIX; - (void) strlcpy(addr.sun_path, path, sizeof (addr.sun_path)); + (void) strlcpy(addr.sun_path, pathcopy, sizeof (addr.sun_path)); if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { error = -1; goto out; @@ -355,7 +372,13 @@ pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *name, errx(EX_OSERR, "Unable to apply rights for sandbox"); #endif - sock->vss_port = pci_vtcon_port_add(sc, name, pci_vtcon_sock_tx, sock); + name = get_config_value_node(nvl, "name"); + if (name == NULL) { + EPRINTLN("vtcon: required name missing for port %ld", port); + error = -1; + goto out; + } + sock->vss_port = pci_vtcon_port_add(sc, port, name, pci_vtcon_sock_tx, sock); if (sock->vss_port == NULL) { error = -1; goto out; @@ -467,10 +490,10 @@ pci_vtcon_sock_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov, int niov) { struct pci_vtcon_sock *sock; -#ifdef __FreeBSD__ int i, ret; -#else - int i, ret = 0; + +#ifndef __FreeBSD__ + ret = 0; #endif sock = (struct pci_vtcon_sock *)arg; @@ -521,13 +544,13 @@ pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov, break; case VTCON_PORT_READY: - if (ctrl->id >= sc->vsc_nports) { + tmp = &sc->vsc_ports[ctrl->id]; + if (ctrl->id >= VTCON_MAXPORTS || !tmp->vsp_enabled) { WPRINTF(("VTCON_PORT_READY event for unknown port %d", ctrl->id)); return; } - tmp = &sc->vsc_ports[ctrl->id]; if (tmp->vsp_console) { resp.event = VTCON_CONSOLE_PORT; resp.id = ctrl->id; @@ -638,14 +661,63 @@ pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq) } } +#ifdef __FreeBSD__ +/* + * Each console device has a "port" node which contains nodes for + * each port. Ports are numbered starting at 0. + */ +static int +pci_vtcon_legacy_config_port(nvlist_t *nvl, int port, char *opt) +{ + char *name, *path; + char node_name[sizeof("XX")]; + nvlist_t *port_nvl; + + name = strsep(&opt, "="); + path = opt; + if (path == NULL) { + EPRINTLN("vtcon: port %s requires a path", name); + return (-1); + } + if (port >= VTCON_MAXPORTS) { + EPRINTLN("vtcon: too many ports"); + return (-1); + } + snprintf(node_name, sizeof(node_name), "%d", port); + port_nvl = create_relative_config_node(nvl, node_name); + set_config_value_node(port_nvl, "name", name); + set_config_value_node(port_nvl, "path", path); + return (0); +} + static int -pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_vtcon_legacy_config(nvlist_t *nvl, const char *opts) +{ + char *opt, *str, *tofree; + nvlist_t *ports_nvl; + int error, port; + + ports_nvl = create_relative_config_node(nvl, "port"); + tofree = str = strdup(opts); + error = 0; + port = 0; + while ((opt = strsep(&str, ",")) != NULL) { + error = pci_vtcon_legacy_config_port(ports_nvl, port, opt); + if (error) + break; + port++; + } + free(tofree); + return (error); +} +#endif + +static int +pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct pci_vtcon_softc *sc; - char *portname = NULL; - char *portpath = NULL; - char *opt; - int i; + nvlist_t *ports_nvl; + int i; sc = calloc(1, sizeof(struct pci_vtcon_softc)); sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config)); @@ -667,7 +739,7 @@ pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM); - pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_CONSOLE); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_CONSOLE); pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) @@ -681,15 +753,24 @@ pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx; sc->vsc_control_port.vsp_enabled = true; - while ((opt = strsep(&opts, ",")) != NULL) { - portname = strsep(&opt, "="); - portpath = opt; - - /* create port */ - if (pci_vtcon_sock_add(sc, portname, portpath) < 0) { - EPRINTLN("cannot create port %s: %s", - portname, strerror(errno)); - return (1); + ports_nvl = find_relative_config_node(nvl, "port"); + if (ports_nvl != NULL) { + const char *name; + void *cookie; + int type; + + cookie = NULL; + while ((name = nvlist_next(ports_nvl, &type, &cookie)) != + NULL) { + if (type != NV_TYPE_NVLIST) + continue; + + if (pci_vtcon_sock_add(sc, name, + nvlist_get_nvlist(ports_nvl, name)) < 0) { + EPRINTLN("cannot create port %s: %s", + name, strerror(errno)); + return (1); + } } } diff --git a/usr/src/cmd/bhyve/pci_virtio_net.c b/usr/src/cmd/bhyve/pci_virtio_net.c index ded9ca90ea..6736603fb8 100644 --- a/usr/src/cmd/bhyve/pci_virtio_net.c +++ b/usr/src/cmd/bhyve/pci_virtio_net.c @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$"); #endif #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #ifdef __FreeBSD__ @@ -813,7 +814,7 @@ pci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq) #endif /* __FreeBSD__ */ static void -pci_vtnet_tap_setup(struct pci_vtnet_softc *sc, char *devname) +pci_vtnet_tap_setup(struct pci_vtnet_softc *sc, const char *devname) { char tbuf[80]; #ifndef WITHOUT_CAPSICUM @@ -932,17 +933,17 @@ pci_vtnet_netmap_setup(struct pci_vtnet_softc *sc, char *ifname) #endif /* __FreeBSD__ */ static int -pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct pci_vtnet_softc *sc; + const char *value; char tname[MAXCOMLEN + 1]; #ifdef __FreeBSD__ - int mac_provided; - int mtu_provided; unsigned long mtu = ETHERMTU; #else int use_msix = 1; #endif + int err; /* * Allocate data structures for further virtio initializations. @@ -962,96 +963,52 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) sc->vsc_queues[VTNET_CTLQ].vq_qsize = VTNET_RINGSZ; sc->vsc_queues[VTNET_CTLQ].vq_notify = pci_vtnet_ping_ctlq; #endif - - /* - * Attempt to open the backend device and read the MAC address - * if specified. - */ -#ifdef __FreeBSD__ - mac_provided = 0; - mtu_provided = 0; -#endif - if (opts != NULL) { - char *optscopy; - char *vtopts; - int err = 0; - /* Get the device name. */ - optscopy = vtopts = strdup(opts); - (void) strsep(&vtopts, ","); - -#ifdef __FreeBSD__ - /* - * Parse the list of options in the form - * key1=value1,...,keyN=valueN. - */ - while (vtopts != NULL) { - char *value = vtopts; - char *key; - - key = strsep(&value, "="); - if (value == NULL) - break; - vtopts = value; - (void) strsep(&vtopts, ","); - - if (strcmp(key, "mac") == 0) { - err = net_parsemac(value, sc->vsc_config.mac); - if (err) - break; - mac_provided = 1; - } else if (strcmp(key, "mtu") == 0) { - err = net_parsemtu(value, &mtu); - if (err) - break; - - if (mtu < VTNET_MIN_MTU || mtu > VTNET_MAX_MTU) { - err = EINVAL; - errno = EINVAL; - break; - } - mtu_provided = 1; - } + value = get_config_value_node(nvl, "mac"); + if (value != NULL) { + err = net_parsemac(value, sc->vsc_config.mac); + if (err) { + free(sc); + return (err); } -#endif - -#ifndef __FreeBSD__ - /* Use the already strsep(",")-ed optscopy */ - if (strncmp(optscopy, "tap", 3) == 0 || - strncmp(optscopy, "vmnet", 5) == 0) - pci_vtnet_tap_setup(sc, optscopy); -#endif - - free(optscopy); + } else + net_genmac(pi, sc->vsc_config.mac); +#ifdef __FreeBSD__ + value = get_config_value_node(nvl, "mtu"); + if (value != NULL) { + err = net_parsemtu(value, &mtu); if (err) { free(sc); return (err); } + if (mtu < VTNET_MIN_MTU || mtu > VTNET_MAX_MTU) { + err = EINVAL; + errno = EINVAL; + free(sc); + return (err); + } + sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MTU; + } +#endif + /* Permit interfaces without a configured backend. */ + if (get_config_value_node(nvl, "backend") != NULL) { #ifdef __FreeBSD__ - err = netbe_init(&sc->vsc_be, opts, pci_vtnet_rx_callback, - sc); + err = netbe_init(&sc->vsc_be, nvl, pci_vtnet_rx_callback, sc); if (err) { free(sc); return (err); } - - sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MRG_RXBUF | - netbe_get_cap(sc->vsc_be); +#else + pci_vtnet_tap_setup(sc, get_config_value_node(nvl, "backend")); #endif - } -#ifdef __FreeBSD__ - if (!mac_provided) { - net_genmac(pi, sc->vsc_config.mac); - } - sc->vsc_config.mtu = mtu; - if (mtu_provided) { - sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MTU; - } +#ifdef __FreeBSD__ + sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MRG_RXBUF | + netbe_get_cap(sc->vsc_be); #endif /* @@ -1064,16 +1021,11 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); - pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_NETWORK); pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); - /* Link is up if we managed to open tap device or vale port. */ -#ifdef __FreeBSD__ - sc->vsc_config.status = (opts == NULL || sc->vsc_tapfd >= 0 || -#else - sc->vsc_config.status = (opts == NULL || sc->vsc_dlpifd >= 0 || - sc->vsc_nmd != NULL); -#endif + /* Link is always up. */ + sc->vsc_config.status = 1; /* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */ if (vi_intr_init(&sc->vsc_vs, 1, use_msix)) @@ -1154,9 +1106,38 @@ pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) pthread_mutex_unlock(&sc->rx_mtx); } +#ifndef __FreeBSD__ +static int +pci_vtnet_legacy_config(nvlist_t *nvl, const char *opt) +{ + char *config, *name, *tofree, *value; + + if (opt == NULL) + return (0); + + config = tofree = strdup(opt); + while ((name = strsep(&config, ",")) != NULL) { + value = strchr(name, '='); + if (value != NULL) { + *value++ = '\0'; + set_config_value_node(nvl, name, value); + } else { + set_config_value_node(nvl, "backend", name); + } + } + free(tofree); + return (0); +} +#endif + struct pci_devemu pci_de_vnet = { .pe_emu = "virtio-net", .pe_init = pci_vtnet_init, +#ifdef __FreeBSD__ + .pe_legacy_config = netbe_legacy_config, +#else + .pe_legacy_config = pci_vtnet_legacy_config, +#endif .pe_barwrite = vi_pci_write, .pe_barread = vi_pci_read }; diff --git a/usr/src/cmd/bhyve/pci_virtio_rnd.c b/usr/src/cmd/bhyve/pci_virtio_rnd.c index 4f908324cf..53c3c9e2bc 100644 --- a/usr/src/cmd/bhyve/pci_virtio_rnd.c +++ b/usr/src/cmd/bhyve/pci_virtio_rnd.c @@ -143,7 +143,7 @@ pci_vtrnd_notify(void *vsc, struct vqueue_info *vq) static int -pci_vtrnd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_vtrnd_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct pci_vtrnd_softc *sc; int fd; @@ -190,7 +190,7 @@ pci_vtrnd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_RANDOM); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_CRYPTO); - pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_ENTROPY); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_ENTROPY); pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); if (vi_intr_init(&sc->vrsc_vs, 1, fbsdrun_virtio_msix())) @@ -205,6 +205,6 @@ struct pci_devemu pci_de_vrnd = { .pe_emu = "virtio-rnd", .pe_init = pci_vtrnd_init, .pe_barwrite = vi_pci_write, - .pe_barread = vi_pci_read + .pe_barread = vi_pci_read, }; PCI_EMUL_SET(pci_de_vrnd); diff --git a/usr/src/cmd/bhyve/pci_virtio_scsi.c b/usr/src/cmd/bhyve/pci_virtio_scsi.c index 92a3311b69..8edf64a113 100644 --- a/usr/src/cmd/bhyve/pci_virtio_scsi.c +++ b/usr/src/cmd/bhyve/pci_virtio_scsi.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <camlib.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #include "virtio.h" @@ -244,7 +245,7 @@ static void pci_vtscsi_eventq_notify(void *, struct vqueue_info *); static void pci_vtscsi_requestq_notify(void *, struct vqueue_info *); static int pci_vtscsi_init_queue(struct pci_vtscsi_softc *, struct pci_vtscsi_queue *, int); -static int pci_vtscsi_init(struct vmctx *, struct pci_devinst *, char *); +static int pci_vtscsi_init(struct vmctx *, struct pci_devinst *, nvlist_t *); static struct virtio_consts vtscsi_vi_consts = { "vtscsi", /* our name */ @@ -665,32 +666,36 @@ pci_vtscsi_init_queue(struct pci_vtscsi_softc *sc, } static int -pci_vtscsi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_vtscsi_legacy_config(nvlist_t *nvl, const char *opts) +{ + char *cp, *devname; + + cp = strchr(opts, ','); + if (cp == NULL) { + set_config_value_node(nvl, "dev", opts); + return (0); + } + devname = strndup(opts, cp - opts); + set_config_value_node(nvl, "dev", devname); + free(devname); + return (pci_parse_legacy_config(nvl, cp + 1)); +} + +static int +pci_vtscsi_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct pci_vtscsi_softc *sc; - char *opt, *optname; - const char *devname; - int i, optidx = 0; + const char *devname, *value;; + int i; sc = calloc(1, sizeof(struct pci_vtscsi_softc)); - devname = "/dev/cam/ctl"; - while ((opt = strsep(&opts, ",")) != NULL) { - optname = strsep(&opt, "="); - if (opt == NULL && optidx == 0) { - if (optname[0] != 0) - devname = optname; - } else if (strcmp(optname, "dev") == 0 && opt != NULL) { - devname = opt; - } else if (strcmp(optname, "iid") == 0 && opt != NULL) { - sc->vss_iid = strtoul(opt, NULL, 10); - } else { - EPRINTLN("Invalid option %s", optname); - free(sc); - return (1); - } - optidx++; - } + value = get_config_value_node(nvl, "iid"); + if (value != NULL) + sc->vss_iid = strtoul(value, NULL, 10); + devname = get_config_value_node(nvl, "dev"); + if (devname == NULL) + devname = "/dev/cam/ctl"; sc->vss_ctl_fd = open(devname, O_RDWR); if (sc->vss_ctl_fd < 0) { WPRINTF(("cannot open %s: %s", devname, strerror(errno))); @@ -720,7 +725,7 @@ pci_vtscsi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_SCSI); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE); - pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_SCSI); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_SCSI); pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); if (vi_intr_init(&sc->vss_vs, 1, fbsdrun_virtio_msix())) diff --git a/usr/src/cmd/bhyve/pci_virtio_viona.c b/usr/src/cmd/bhyve/pci_virtio_viona.c index 9cafa7b111..07abf20512 100644 --- a/usr/src/cmd/bhyve/pci_virtio_viona.c +++ b/usr/src/cmd/bhyve/pci_virtio_viona.c @@ -64,6 +64,7 @@ #include <vmmapi.h> #include "bhyverun.h" +#include "config.h" #include "pci_emul.h" #include "virtio.h" @@ -135,10 +136,12 @@ struct pci_viona_softc { static uint64_t pci_viona_iosize(struct pci_devinst *pi) { - if (pci_msix_enabled(pi)) + if (pci_msix_enabled(pi)) { return (VIONA_REGSZ); - else - return (VIONA_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX)); + } else { + return (VIONA_REGSZ - + (VIRTIO_PCI_CONFIG_OFF(1) - VIRTIO_PCI_CONFIG_OFF(0))); + } } static uint16_t @@ -301,82 +304,80 @@ pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc) } static int -pci_viona_parse_opts(struct pci_viona_softc *sc, char *opts) +pci_viona_legacy_config(nvlist_t *nvl, const char *opt) { - char *next, *cp, *vnic = NULL; + char *config, *name, *tofree, *value; + + if (opt == NULL) + return (0); + + config = tofree = strdup(opt); + while ((name = strsep(&config, ",")) != NULL) { + value = strchr(name, '='); + if (value != NULL) { + *value++ = '\0'; + set_config_value_node(nvl, name, value); + } else { + set_config_value_node(nvl, "vnic", name); + } + } + free(tofree); + return (0); +} + +static int +pci_viona_parse_opts(struct pci_viona_softc *sc, nvlist_t *nvl) +{ + const char *value; int err = 0; sc->vsc_vq_size = VIONA_RINGSZ; sc->vsc_feature_mask = 0; + sc->vsc_linkname[0] = '\0'; - for (; opts != NULL && *opts != '\0'; opts = next) { - char *val; + value = get_config_value_node(nvl, "feature_mask"); + if (value != NULL) { + long num; - if ((cp = strchr(opts, ',')) != NULL) { - *cp = '\0'; - next = cp + 1; + errno = 0; + num = strtol(value, NULL, 0); + if (errno != 0 || num < 0) { + fprintf(stderr, + "viona: invalid mask '%s'", value); } else { - next = NULL; + sc->vsc_feature_mask = num; } + } - if ((cp = strchr(opts, '=')) == NULL) { - /* vnic chosen with bare name */ - if (vnic != NULL) { - fprintf(stderr, - "viona: unexpected vnic name '%s'", opts); - err = -1; - } else { - vnic = opts; - } - continue; - } + value = get_config_value_node(nvl, "vqsize"); + if (value != NULL) { + long num; - /* <param>=<value> handling */ - val = cp + 1; - *cp = '\0'; - if (strcmp(opts, "feature_mask") == 0) { - long num; - - errno = 0; - num = strtol(val, NULL, 0); - if (errno != 0 || num < 0) { - fprintf(stderr, - "viona: invalid mask '%s'", val); - } else { - sc->vsc_feature_mask = num; - } - } else if (strcmp(opts, "vqsize") == 0) { - long num; - - errno = 0; - num = strtol(val, NULL, 0); - if (errno != 0) { - fprintf(stderr, - "viona: invalid vsqize '%s'", val); - err = -1; - } else if (num <= 2 || num > 32768) { - fprintf(stderr, - "viona: vqsize out of range", num); - err = -1; - } else if ((1 << (ffs(num) - 1)) != num) { - fprintf(stderr, - "viona: vqsize must be power of 2", num); - err = -1; - } else { - sc->vsc_vq_size = num; - } - } else { + errno = 0; + num = strtol(value, NULL, 0); + if (errno != 0) { + fprintf(stderr, + "viona: invalid vsqize '%s'", value); + err = -1; + } else if (num <= 2 || num > 32768) { + fprintf(stderr, + "viona: vqsize out of range", num); + err = -1; + } else if ((1 << (ffs(num) - 1)) != num) { fprintf(stderr, - "viona: unrecognized option '%s'", opts); + "viona: vqsize must be power of 2", num); err = -1; + } else { + sc->vsc_vq_size = num; } } - if (vnic == NULL) { + + value = get_config_value_node(nvl, "vnic"); + if (value == NULL) { fprintf(stderr, "viona: vnic name required"); - sc->vsc_linkname[0] = '\0'; err = -1; } else { - (void) strlcpy(sc->vsc_linkname, vnic, MAXLINKNAMELEN); + (void) strlcpy(sc->vsc_linkname, value, MAXLINKNAMELEN); } DPRINTF(("viona=%p dev=%s vqsize=%x feature_mask=%x\n", sc, @@ -385,7 +386,7 @@ pci_viona_parse_opts(struct pci_viona_softc *sc, char *opts) } static int -pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { dladm_handle_t handle; dladm_status_t status; @@ -394,8 +395,10 @@ pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) int error, i; struct pci_viona_softc *sc; uint64_t ioport; + const char *vnic; - if (opts == NULL) { + vnic = get_config_value_node(nvl, "vnic"); + if (vnic == NULL) { printf("virtio-viona: vnic required\n"); return (1); } @@ -408,7 +411,7 @@ pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pthread_mutex_init(&sc->vsc_mtx, NULL); - if (pci_viona_parse_opts(sc, opts) != 0) { + if (pci_viona_parse_opts(sc, nvl) != 0) { free(sc); return (1); } @@ -419,18 +422,18 @@ pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) return (1); } - if (dladm_name2info(handle, sc->vsc_linkname, &sc->vsc_linkid, - NULL, NULL, NULL) != DLADM_STATUS_OK) { - WPRINTF(("dladm_name2info() for %s failed: %s\n", opts, + if ((status = dladm_name2info(handle, sc->vsc_linkname, &sc->vsc_linkid, + NULL, NULL, NULL)) != DLADM_STATUS_OK) { + WPRINTF(("dladm_name2info() for %s failed: %s\n", vnic, dladm_status2str(status, errmsg))); dladm_close(handle); free(sc); return (1); } - if (dladm_vnic_info(handle, sc->vsc_linkid, &attr, - DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { - WPRINTF(("dladm_vnic_info() for %s failed: %s\n", opts, + if ((status = dladm_vnic_info(handle, sc->vsc_linkid, &attr, + DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + WPRINTF(("dladm_vnic_info() for %s failed: %s\n", vnic, dladm_status2str(status, errmsg))); dladm_close(handle); free(sc); @@ -454,7 +457,7 @@ pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); - pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_NETWORK); pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); /* MSI-X support */ @@ -476,7 +479,7 @@ pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) } /* Install ioport hook for virtqueue notification */ - ioport = pi->pi_bar[0].addr + VTCFG_R_QNOTIFY; + ioport = pi->pi_bar[0].addr + VIRTIO_PCI_QUEUE_NOTIFY; error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, ioport); if (error != 0) { WPRINTF(("could not install ioport hook at %x\n", ioport)); @@ -501,8 +504,10 @@ viona_adjust_offset(struct pci_devinst *pi, uint64_t offset) * whether MSI-X capability is enabled or not */ if (!pci_msix_enabled(pi)) { - if (offset >= VTCFG_R_MSIX) - return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX)); + if (offset >= VIRTIO_PCI_CONFIG_OFF(0)) { + return (offset + (VIRTIO_PCI_CONFIG_OFF(1) - + VIRTIO_PCI_CONFIG_OFF(0))); + } } return (offset); @@ -640,7 +645,7 @@ pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, offset = viona_adjust_offset(pi, offset); switch (offset) { - case VTCFG_R_GUESTCAP: + case VIRTIO_PCI_GUEST_FEATURES: assert(size == 4); value &= ~(sc->vsc_feature_mask); err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value); @@ -651,29 +656,29 @@ pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, sc->vsc_features = value; } break; - case VTCFG_R_PFN: + case VIRTIO_PCI_QUEUE_PFN: assert(size == 4); pci_viona_ring_init(sc, value); break; - case VTCFG_R_QSEL: + case VIRTIO_PCI_QUEUE_SEL: assert(size == 2); assert(value < VIONA_MAXQ); sc->vsc_curq = value; break; - case VTCFG_R_QNOTIFY: + case VIRTIO_PCI_QUEUE_NOTIFY: assert(size == 2); assert(value < VIONA_MAXQ); pci_viona_qnotify(sc, value); break; - case VTCFG_R_STATUS: + case VIRTIO_PCI_STATUS: assert(size == 1); pci_viona_update_status(sc, value); break; - case VTCFG_R_CFGVEC: + case VIRTIO_MSI_CONFIG_VECTOR: assert(size == 2); sc->vsc_msix_table_idx[VIONA_CTLQ] = value; break; - case VTCFG_R_QVEC: + case VIRTIO_MSI_QUEUE_VECTOR: assert(size == 2); assert(sc->vsc_curq != VIONA_CTLQ); sc->vsc_msix_table_idx[sc->vsc_curq] = value; @@ -699,9 +704,9 @@ pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, *(uint32_t *)ptr = value; } break; - case VTCFG_R_HOSTCAP: - case VTCFG_R_QNUM: - case VTCFG_R_ISR: + case VIRTIO_PCI_HOST_FEATURES: + case VIRTIO_PCI_QUEUE_NUM: + case VIRTIO_PCI_ISR: case VIONA_R_CFG6: case VIONA_R_CFG7: DPRINTF(("viona: write to readonly reg %ld\n\r", offset)); @@ -742,7 +747,7 @@ pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, offset = viona_adjust_offset(pi, offset); switch (offset) { - case VTCFG_R_HOSTCAP: + case VIRTIO_PCI_HOST_FEATURES: assert(size == 4); err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value); if (err != 0) { @@ -751,31 +756,31 @@ pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, } value &= ~sc->vsc_feature_mask; break; - case VTCFG_R_GUESTCAP: + case VIRTIO_PCI_GUEST_FEATURES: assert(size == 4); value = sc->vsc_features; /* XXX never read ? */ break; - case VTCFG_R_PFN: + case VIRTIO_PCI_QUEUE_PFN: assert(size == 4); value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN; break; - case VTCFG_R_QNUM: + case VIRTIO_PCI_QUEUE_NUM: assert(size == 2); value = pci_viona_qsize(sc, sc->vsc_curq); break; - case VTCFG_R_QSEL: + case VIRTIO_PCI_QUEUE_SEL: assert(size == 2); value = sc->vsc_curq; /* XXX never read ? */ break; - case VTCFG_R_QNOTIFY: + case VIRTIO_PCI_QUEUE_NOTIFY: assert(size == 2); value = sc->vsc_curq; /* XXX never read ? */ break; - case VTCFG_R_STATUS: + case VIRTIO_PCI_STATUS: assert(size == 1); value = sc->vsc_status; break; - case VTCFG_R_ISR: + case VIRTIO_PCI_ISR: assert(size == 1); value = sc->vsc_isr; sc->vsc_isr = 0; /* a read clears this flag */ @@ -783,11 +788,11 @@ pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, pci_lintr_deassert(pi); } break; - case VTCFG_R_CFGVEC: + case VIRTIO_MSI_CONFIG_VECTOR: assert(size == 2); value = sc->vsc_msix_table_idx[VIONA_CTLQ]; break; - case VTCFG_R_QVEC: + case VIRTIO_MSI_QUEUE_VECTOR: assert(size == 2); assert(sc->vsc_curq != VIONA_CTLQ); value = sc->vsc_msix_table_idx[sc->vsc_curq]; @@ -830,6 +835,7 @@ pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, struct pci_devemu pci_de_viona = { .pe_emu = "virtio-net-viona", .pe_init = pci_viona_init, + .pe_legacy_config = pci_viona_legacy_config, .pe_barwrite = pci_viona_write, .pe_barread = pci_viona_read, .pe_lintrupdate = pci_viona_lintrupdate diff --git a/usr/src/cmd/bhyve/pci_xhci.c b/usr/src/cmd/bhyve/pci_xhci.c index 587e80a91c..bbccc7f0bf 100644 --- a/usr/src/cmd/bhyve/pci_xhci.c +++ b/usr/src/cmd/bhyve/pci_xhci.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <xhcireg.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "pci_emul.h" #include "pci_xhci.h" @@ -273,7 +274,6 @@ struct pci_xhci_softc { struct pci_xhci_portregs *portregs; struct pci_xhci_dev_emu **devices; /* XHCI[port] = device */ struct pci_xhci_dev_emu **slots; /* slots assigned from 1 */ - int ndevices; int usb2_port_start; int usb3_port_start; @@ -566,7 +566,8 @@ pci_xhci_get_dev_ctx(struct pci_xhci_softc *sc, uint32_t slot) uint64_t devctx_addr; struct xhci_dev_ctx *devctx; - assert(slot > 0 && slot <= sc->ndevices); + assert(slot > 0 && slot <= XHCI_MAX_DEVS); + assert(XHCI_SLOTDEV_PTR(sc, slot) != NULL); assert(sc->opregs.dcbaa_p != NULL); devctx_addr = sc->opregs.dcbaa_p->dcba[slot]; @@ -839,7 +840,7 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_softc *sc, uint32_t slot) if (sc->portregs == NULL) goto done; - if (slot > sc->ndevices) { + if (slot > XHCI_MAX_SLOTS) { cmderr = XHCI_TRB_ERROR_SLOT_NOT_ON; goto done; } @@ -853,7 +854,8 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_softc *sc, uint32_t slot) cmderr = XHCI_TRB_ERROR_SUCCESS; /* TODO: reset events and endpoints */ } - } + } else + cmderr = XHCI_TRB_ERROR_SLOT_NOT_ON; done: return (cmderr); @@ -1912,7 +1914,7 @@ pci_xhci_device_doorbell(struct pci_xhci_softc *sc, uint32_t slot, DPRINTF(("pci_xhci doorbell slot %u epid %u stream %u", slot, epid, streamid)); - if (slot == 0 || slot > sc->ndevices) { + if (slot == 0 || slot > XHCI_MAX_SLOTS) { DPRINTF(("pci_xhci: invalid doorbell slot %u", slot)); return; } @@ -2656,67 +2658,129 @@ pci_xhci_dev_event(struct usb_hci *hci, enum hci_usbev evid, void *param) return (0); } +/* + * Each controller contains a "slot" node which contains a list of + * child nodes each of which is a device. Each slot node's name + * corresponds to a specific controller slot. These nodes + * contain a "device" variable identifying the device model of the + * USB device. For example: + * + * pci.0.1.0 + * .device="xhci" + * .slot + * .1 + * .device="tablet" + */ +static int +pci_xhci_legacy_config(nvlist_t *nvl, const char *opts) +{ + char node_name[16]; + nvlist_t *slots_nvl, *slot_nvl; + char *cp, *opt, *str, *tofree; + int slot; + if (opts == NULL) + return (0); -static void -pci_xhci_device_usage(char *opt) -{ + slots_nvl = create_relative_config_node(nvl, "slot"); + slot = 1; + tofree = str = strdup(opts); + while ((opt = strsep(&str, ",")) != NULL) { + /* device[=<config>] */ + cp = strchr(opt, '='); + if (cp != NULL) { + *cp = '\0'; + cp++; + } + + snprintf(node_name, sizeof(node_name), "%d", slot); + slot++; + slot_nvl = create_relative_config_node(slots_nvl, node_name); + set_config_value_node(slot_nvl, "device", opt); - EPRINTLN("Invalid USB emulation \"%s\"", opt); + /* + * NB: Given that we split on commas above, the legacy + * format only supports a single option. + */ + if (cp != NULL && *cp != '\0') + pci_parse_legacy_config(slot_nvl, cp); + } + free(tofree); + return (0); } static int -pci_xhci_parse_opts(struct pci_xhci_softc *sc, char *opts) +pci_xhci_parse_devices(struct pci_xhci_softc *sc, nvlist_t *nvl) { - struct pci_xhci_dev_emu **devices; struct pci_xhci_dev_emu *dev; struct usb_devemu *ue; - void *devsc; - char *uopt, *xopts, *config; - int usb3_port, usb2_port, i; + const nvlist_t *slots_nvl, *slot_nvl; + const char *name, *device; + char *cp; + void *devsc, *cookie; + long slot; + int type, usb3_port, usb2_port, i, ndevices; - uopt = NULL; - usb3_port = sc->usb3_port_start - 1; - usb2_port = sc->usb2_port_start - 1; - devices = NULL; + usb3_port = sc->usb3_port_start; + usb2_port = sc->usb2_port_start; - if (opts == NULL) - goto portsfinal; + sc->devices = calloc(XHCI_MAX_DEVS, sizeof(struct pci_xhci_dev_emu *)); + sc->slots = calloc(XHCI_MAX_SLOTS, sizeof(struct pci_xhci_dev_emu *)); - devices = calloc(XHCI_MAX_DEVS, sizeof(struct pci_xhci_dev_emu *)); + /* port and slot numbering start from 1 */ + sc->devices--; + sc->slots--; - sc->slots = calloc(XHCI_MAX_SLOTS, sizeof(struct pci_xhci_dev_emu *)); - sc->devices = devices; - sc->ndevices = 0; - - uopt = strdup(opts); - for (xopts = strtok(uopt, ","); - xopts != NULL; - xopts = strtok(NULL, ",")) { - if (usb2_port == ((sc->usb2_port_start-1) + XHCI_MAX_DEVS/2) || - usb3_port == ((sc->usb3_port_start-1) + XHCI_MAX_DEVS/2)) { + ndevices = 0; + + slots_nvl = find_relative_config_node(nvl, "slot"); + if (slots_nvl == NULL) + goto portsfinal; + + cookie = NULL; + while ((name = nvlist_next(slots_nvl, &type, &cookie)) != NULL) { + if (usb2_port == ((sc->usb2_port_start) + XHCI_MAX_DEVS/2) || + usb3_port == ((sc->usb3_port_start) + XHCI_MAX_DEVS/2)) { WPRINTF(("pci_xhci max number of USB 2 or 3 " "devices reached, max %d", XHCI_MAX_DEVS/2)); - usb2_port = usb3_port = -1; - goto done; + goto bad; } - /* device[=<config>] */ - if ((config = strchr(xopts, '=')) == NULL) - config = ""; /* no config */ - else - *config++ = '\0'; + if (type != NV_TYPE_NVLIST) { + EPRINTLN( + "pci_xhci: config variable '%s' under slot node", + name); + goto bad; + } + + slot = strtol(name, &cp, 0); + if (*cp != '\0' || slot <= 0 || slot > XHCI_MAX_SLOTS) { + EPRINTLN("pci_xhci: invalid slot '%s'", name); + goto bad; + } + + if (XHCI_SLOTDEV_PTR(sc, slot) != NULL) { + EPRINTLN("pci_xhci: duplicate slot '%s'", name); + goto bad; + } - ue = usb_emu_finddev(xopts); + slot_nvl = nvlist_get_nvlist(slots_nvl, name); + device = get_config_value_node(slot_nvl, "device"); + if (device == NULL) { + EPRINTLN( + "pci_xhci: missing \"device\" value for slot '%s'", + name); + goto bad; + } + + ue = usb_emu_finddev(device); if (ue == NULL) { - pci_xhci_device_usage(xopts); - DPRINTF(("pci_xhci device not found %s", xopts)); - usb2_port = usb3_port = -1; - goto done; + EPRINTLN("pci_xhci: unknown device model \"%s\"", + device); + goto bad; } - DPRINTF(("pci_xhci adding device %s, opts \"%s\"", - xopts, config)); + DPRINTF(("pci_xhci adding device %s", device)); dev = calloc(1, sizeof(struct pci_xhci_dev_emu)); dev->xsc = sc; @@ -2725,66 +2789,65 @@ pci_xhci_parse_opts(struct pci_xhci_softc *sc, char *opts) dev->hci.hci_event = pci_xhci_dev_event; if (ue->ue_usbver == 2) { - dev->hci.hci_port = usb2_port + 1; - devices[usb2_port] = dev; + if (usb2_port == sc->usb2_port_start + + XHCI_MAX_DEVS / 2) { + WPRINTF(("pci_xhci max number of USB 2 devices " + "reached, max %d", XHCI_MAX_DEVS / 2)); + goto bad; + } + dev->hci.hci_port = usb2_port; usb2_port++; } else { - dev->hci.hci_port = usb3_port + 1; - devices[usb3_port] = dev; + if (usb3_port == sc->usb3_port_start + + XHCI_MAX_DEVS / 2) { + WPRINTF(("pci_xhci max number of USB 3 devices " + "reached, max %d", XHCI_MAX_DEVS / 2)); + goto bad; + } + dev->hci.hci_port = usb3_port; usb3_port++; } + XHCI_DEVINST_PTR(sc, dev->hci.hci_port) = dev; dev->hci.hci_address = 0; - devsc = ue->ue_init(&dev->hci, config); + devsc = ue->ue_init(&dev->hci, nvl); if (devsc == NULL) { - pci_xhci_device_usage(xopts); - usb2_port = usb3_port = -1; - goto done; + goto bad; } dev->dev_ue = ue; dev->dev_sc = devsc; - /* assign slot number to device */ - sc->slots[sc->ndevices] = dev; - - sc->ndevices++; + XHCI_SLOTDEV_PTR(sc, slot) = dev; + ndevices++; } portsfinal: sc->portregs = calloc(XHCI_MAX_DEVS, sizeof(struct pci_xhci_portregs)); + sc->portregs--; - if (sc->ndevices > 0) { - /* port and slot numbering start from 1 */ - sc->devices--; - sc->portregs--; - sc->slots--; - + if (ndevices > 0) { for (i = 1; i <= XHCI_MAX_DEVS; i++) { pci_xhci_init_port(sc, i); } } else { WPRINTF(("pci_xhci no USB devices configured")); - sc->ndevices = 1; } + return (0); -done: - if (devices != NULL) { - if (usb2_port <= 0 && usb3_port <= 0) { - sc->devices = NULL; - for (i = 0; devices[i] != NULL; i++) - free(devices[i]); - sc->ndevices = -1; - - free(devices); - } +bad: + for (i = 1; i <= XHCI_MAX_DEVS; i++) { + free(XHCI_DEVINST_PTR(sc, i)); } - free(uopt); - return (sc->ndevices); + + free(sc->devices + 1); + free(sc->slots + 1); + + return (-1); } static int -pci_xhci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +pci_xhci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) { struct pci_xhci_softc *sc; int error; @@ -2803,7 +2866,7 @@ pci_xhci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) sc->usb3_port_start = 1; /* discover devices */ - error = pci_xhci_parse_opts(sc, opts); + error = pci_xhci_parse_devices(sc, nvl); if (error < 0) goto done; else @@ -2877,11 +2940,10 @@ done: return (error); } - - struct pci_devemu pci_de_xhci = { .pe_emu = "xhci", .pe_init = pci_xhci_init, + .pe_legacy_config = pci_xhci_legacy_config, .pe_barwrite = pci_xhci_write, .pe_barread = pci_xhci_read }; diff --git a/usr/src/cmd/bhyve/pctestdev.c b/usr/src/cmd/bhyve/pctestdev.c index be445e5c75..49e03b2a43 100644 --- a/usr/src/cmd/bhyve/pctestdev.c +++ b/usr/src/cmd/bhyve/pctestdev.c @@ -89,15 +89,6 @@ pctestdev_getname(void) } int -pctestdev_parse(const char *opts) -{ - if (opts != NULL && *opts != '\0') - return (-1); - - return (0); -} - -int pctestdev_init(struct vmctx *ctx) { struct mem_range iomem; diff --git a/usr/src/cmd/bhyve/pctestdev.h b/usr/src/cmd/bhyve/pctestdev.h index c1c940146e..5808abe6e3 100644 --- a/usr/src/cmd/bhyve/pctestdev.h +++ b/usr/src/cmd/bhyve/pctestdev.h @@ -38,6 +38,5 @@ struct vmctx; const char *pctestdev_getname(void); int pctestdev_init(struct vmctx *ctx); -int pctestdev_parse(const char *opts); #endif diff --git a/usr/src/cmd/bhyve/rfb.c b/usr/src/cmd/bhyve/rfb.c index dbd96e67cc..a8e45d03a6 100644 --- a/usr/src/cmd/bhyve/rfb.c +++ b/usr/src/cmd/bhyve/rfb.c @@ -437,7 +437,7 @@ static int rfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc) { struct rfb_srvr_updt_msg supdt_msg; - struct rfb_srvr_rect_hdr srect_hdr; + struct rfb_srvr_rect_hdr srect_hdr; ssize_t nwrite; unsigned long zlen; int err; @@ -631,11 +631,11 @@ rfb_send_screen(struct rfb_softc *rc, int cfd) } } - /* - * We only send the update if there are changes. - * Restore the pending flag since it was unconditionally cleared - * above. - */ + /* + * We only send the update if there are changes. + * Restore the pending flag since it was unconditionally cleared + * above. + */ if (!changes) { rc->pending = true; goto done; @@ -1005,7 +1005,7 @@ report_and_done: if (perror == 0) pthread_set_name_np(tid, "rfbout"); - /* Now read in client requests. 1st byte identifies type */ + /* Now read in client requests. 1st byte identifies type */ for (;;) { len = read(cfd, buf, 1); if (len <= 0) { @@ -1198,7 +1198,7 @@ rfb_init(char *hostname, int port, int wait, char *password) #ifndef __FreeBSD__ int -rfb_init_unix(char *path, int wait, char *password) +rfb_init_unix(const char *path, int wait, char *password) { struct rfb_softc *rc; struct sockaddr_un sock; diff --git a/usr/src/cmd/bhyve/rfb.h b/usr/src/cmd/bhyve/rfb.h index 990e2075ac..71227c59ac 100644 --- a/usr/src/cmd/bhyve/rfb.h +++ b/usr/src/cmd/bhyve/rfb.h @@ -36,7 +36,7 @@ int rfb_init(char *hostname, int port, int wait, char *password); #ifndef __FreeBSD__ -int rfb_init_unix(char *path, int wait, char *password); +int rfb_init_unix(const char *path, int wait, char *password); #endif #endif /* _RFB_H_ */ diff --git a/usr/src/cmd/bhyve/rtc.c b/usr/src/cmd/bhyve/rtc.c index 09ca3f61ae..0f63156adb 100644 --- a/usr/src/cmd/bhyve/rtc.c +++ b/usr/src/cmd/bhyve/rtc.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <vmmapi.h> #include "acpi.h" +#include "config.h" #include "pci_lpc.h" #include "rtc.h" @@ -59,13 +60,13 @@ __FBSDID("$FreeBSD$"); * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970 */ static time_t -rtc_time(struct vmctx *ctx, int use_localtime) +rtc_time(struct vmctx *ctx) { struct tm tm; time_t t; time(&t); - if (use_localtime) { + if (get_config_bool_default("rtc.use_localtime", true)) { localtime_r(&t, &tm); t = timegm(&tm); } @@ -73,7 +74,7 @@ rtc_time(struct vmctx *ctx, int use_localtime) } void -rtc_init(struct vmctx *ctx, int use_localtime) +rtc_init(struct vmctx *ctx) { size_t himem; size_t lomem; @@ -101,7 +102,7 @@ rtc_init(struct vmctx *ctx, int use_localtime) err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16); assert(err == 0); - err = vm_rtc_settime(ctx, rtc_time(ctx, use_localtime)); + err = vm_rtc_settime(ctx, rtc_time(ctx)); assert(err == 0); } diff --git a/usr/src/cmd/bhyve/rtc.h b/usr/src/cmd/bhyve/rtc.h index 1c108eed99..c8b3572e93 100644 --- a/usr/src/cmd/bhyve/rtc.h +++ b/usr/src/cmd/bhyve/rtc.h @@ -31,6 +31,6 @@ #ifndef _RTC_H_ #define _RTC_H_ -void rtc_init(struct vmctx *ctx, int use_localtime); +void rtc_init(struct vmctx *ctx); #endif /* _RTC_H_ */ diff --git a/usr/src/cmd/bhyve/smbiostbl.c b/usr/src/cmd/bhyve/smbiostbl.c index 3df2012f10..21185292a2 100644 --- a/usr/src/cmd/bhyve/smbiostbl.c +++ b/usr/src/cmd/bhyve/smbiostbl.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <vmmapi.h> #include "bhyverun.h" +#include "config.h" #include "debug.h" #include "smbiostbl.h" @@ -589,11 +590,13 @@ smbios_type1_initializer(struct smbios_structure *template_entry, uint16_t *n, uint16_t *size) { struct smbios_table_type1 *type1; + const char *guest_uuid_str; smbios_generic_initializer(template_entry, template_strings, curaddr, endaddr, n, size); type1 = (struct smbios_table_type1 *)curaddr; + guest_uuid_str = get_config_value("uuid"); if (guest_uuid_str != NULL) { uuid_t uuid; uint32_t status; @@ -607,6 +610,7 @@ smbios_type1_initializer(struct smbios_structure *template_entry, MD5_CTX mdctx; u_char digest[16]; char hostname[MAXHOSTNAMELEN]; + const char *vmname; /* * Universally unique and yet reproducible are an @@ -617,6 +621,7 @@ smbios_type1_initializer(struct smbios_structure *template_entry, return (-1); MD5Init(&mdctx); + vmname = get_config_value("name"); MD5Update(&mdctx, vmname, strlen(vmname)); MD5Update(&mdctx, hostname, sizeof(hostname)); MD5Final(digest, &mdctx); @@ -863,27 +868,44 @@ smbios_build(struct vmctx *ctx) return (0); } +#ifndef __FreeBSD__ +struct { + const char *key; + const char **targetp; +} type1_map[] = { + { "manufacturer", &smbios_type1_strings[0] }, + { "product", &smbios_type1_strings[1] }, + { "version", &smbios_type1_strings[2] }, + { "serial", &smbios_type1_strings[3] }, + { "sku", &smbios_type1_strings[4] }, + { "family", &smbios_type1_strings[5] }, + { 0 } +}; + +void +smbios_apply(void) +{ + nvlist_t *nvl; + + nvl = find_config_node("smbios"); + if (nvl == NULL) + return; + + for (uint_t i = 0; type1_map[i].key != NULL; i++) { + const char *value; + + value = get_config_value_node(nvl, type1_map[i].key); + if (value != NULL) + *type1_map[i].targetp = value; + } +} + int smbios_parse(const char *opts) { - char *buf; - char *lasts; - char *token; - char *end; + char *buf, *lasts, *token, *end; + nvlist_t *nvl; long type; - struct { - const char *key; - const char **targetp; - } type1_map[] = { - { "manufacturer", &smbios_type1_strings[0] }, - { "product", &smbios_type1_strings[1] }, - { "version", &smbios_type1_strings[2] }, - { "serial", &smbios_type1_strings[3] }, - { "sku", &smbios_type1_strings[4] }, - { "family", &smbios_type1_strings[5] }, - { "uuid", (const char **)&guest_uuid_str }, - { 0 } - }; if ((buf = strdup(opts)) == NULL) { (void) fprintf(stderr, "out of memory\n"); @@ -909,9 +931,15 @@ smbios_parse(const char *opts) goto fail; } + nvl = create_config_node("smbios"); + if (nvl == NULL) { + (void) fprintf(stderr, "out of memory\n"); + return (-1); + } + while ((token = strtok_r(NULL, ",", &lasts)) != NULL) { char *val; - int i; + uint_t i; if ((val = strchr(token, '=')) == NULL) { (void) fprintf(stderr, "invalid key=value: '%s'\n", @@ -921,6 +949,11 @@ smbios_parse(const char *opts) *val = '\0'; val++; + if (strcmp(token, "uuid") == 0) { + set_config_value_node(nvl, token, val); + continue; + } + for (i = 0; type1_map[i].key != NULL; i++) { if (strcmp(token, type1_map[i].key) == 0) { break; @@ -930,7 +963,7 @@ smbios_parse(const char *opts) (void) fprintf(stderr, "invalid key '%s'\n", token); goto fail; } - *type1_map[i].targetp = val; + set_config_value_node(nvl, token, val); } return (0); @@ -939,3 +972,4 @@ fail: free(buf); return (-1); } +#endif diff --git a/usr/src/cmd/bhyve/smbiostbl.h b/usr/src/cmd/bhyve/smbiostbl.h index 81e26309e5..2438fc9083 100644 --- a/usr/src/cmd/bhyve/smbiostbl.h +++ b/usr/src/cmd/bhyve/smbiostbl.h @@ -38,6 +38,9 @@ struct vmctx; int smbios_build(struct vmctx *ctx); +#ifndef __FreeBSD__ int smbios_parse(const char *opts); +void smbios_apply(void); +#endif #endif /* _SMBIOSTBL_H_ */ diff --git a/usr/src/cmd/bhyve/test/Makefile.com b/usr/src/cmd/bhyve/test/Makefile.com index a2e5bce08f..64f1819b76 100644 --- a/usr/src/cmd/bhyve/test/Makefile.com +++ b/usr/src/cmd/bhyve/test/Makefile.com @@ -21,7 +21,6 @@ include $(SRC)/cmd/Makefile.cmd.64 # Force c99 for everything # CSTD= $(CSTD_GNU99) -C99MODE= -xc99=%all CFLAGS += $(CCVERBOSE) -_gcc=-Wimplicit-function-declaration \ -_gcc=-Wno-parentheses diff --git a/usr/src/cmd/bhyve/uart_emul.c b/usr/src/cmd/bhyve/uart_emul.c index 077380a422..a04229b288 100644 --- a/usr/src/cmd/bhyve/uart_emul.c +++ b/usr/src/cmd/bhyve/uart_emul.c @@ -77,6 +77,10 @@ __FBSDID("$FreeBSD$"); #define COM1_IRQ 4 #define COM2_BASE 0x2F8 #define COM2_IRQ 3 +#define COM3_BASE 0x3E8 +#define COM3_IRQ 4 +#define COM4_BASE 0x2E8 +#define COM4_IRQ 3 #define DEFAULT_RCLK 1843200 #define DEFAULT_BAUD 9600 @@ -104,6 +108,8 @@ static struct { } uart_lres[] = { { COM1_BASE, COM1_IRQ, false}, { COM2_BASE, COM2_IRQ, false}, + { COM3_BASE, COM3_IRQ, false}, + { COM4_BASE, COM4_IRQ, false}, }; #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) @@ -916,7 +922,7 @@ uart_stdio_backend(struct uart_softc *sc) } static int -uart_tty_backend(struct uart_softc *sc, const char *opts) +uart_tty_backend(struct uart_softc *sc, const char *path) { #ifndef WITHOUT_CAPSICUM cap_rights_t rights; @@ -924,7 +930,7 @@ uart_tty_backend(struct uart_softc *sc, const char *opts) #endif int fd; - fd = open(opts, O_RDWR | O_NONBLOCK); + fd = open(path, O_RDWR | O_NONBLOCK); if (fd < 0) return (-1); @@ -948,21 +954,21 @@ uart_tty_backend(struct uart_softc *sc, const char *opts) } int -uart_set_backend(struct uart_softc *sc, const char *opts) +uart_set_backend(struct uart_softc *sc, const char *device) { int retval; - if (opts == NULL) + if (device == NULL) return (0); #ifndef __FreeBSD__ - if (strncmp("socket,", opts, 7) == 0) - return (uart_sock_backend(sc, opts)); + if (strncmp("socket,", device, 7) == 0) + return (uart_sock_backend(sc, device)); #endif - if (strcmp("stdio", opts) == 0) + if (strcmp("stdio", device) == 0) retval = uart_stdio_backend(sc); else - retval = uart_tty_backend(sc, opts); + retval = uart_tty_backend(sc, device); if (retval == 0) uart_opentty(sc); diff --git a/usr/src/cmd/bhyve/uart_emul.h b/usr/src/cmd/bhyve/uart_emul.h index a87202df1f..8c5b983a08 100644 --- a/usr/src/cmd/bhyve/uart_emul.h +++ b/usr/src/cmd/bhyve/uart_emul.h @@ -43,5 +43,5 @@ struct uart_softc *uart_init(uart_intr_func_t intr_assert, int uart_legacy_alloc(int unit, int *ioaddr, int *irq); uint8_t uart_read(struct uart_softc *sc, int offset); void uart_write(struct uart_softc *sc, int offset, uint8_t value); -int uart_set_backend(struct uart_softc *sc, const char *opt); +int uart_set_backend(struct uart_softc *sc, const char *device); #endif diff --git a/usr/src/cmd/bhyve/usb_emul.c b/usr/src/cmd/bhyve/usb_emul.c index 6ecdd9530e..d97d7b38d2 100644 --- a/usr/src/cmd/bhyve/usb_emul.c +++ b/usr/src/cmd/bhyve/usb_emul.c @@ -43,7 +43,7 @@ __FBSDID("$FreeBSD$"); SET_DECLARE(usb_emu_set, struct usb_devemu); struct usb_devemu * -usb_emu_finddev(char *name) +usb_emu_finddev(const char *name) { struct usb_devemu **udpp, *udp; diff --git a/usr/src/cmd/bhyve/usb_emul.h b/usr/src/cmd/bhyve/usb_emul.h index e55a421b6f..ede0fe0154 100644 --- a/usr/src/cmd/bhyve/usb_emul.h +++ b/usr/src/cmd/bhyve/usb_emul.h @@ -32,6 +32,7 @@ #ifndef _USB_EMUL_H_ #define _USB_EMUL_H_ +#include <sys/nv.h> #include <stdlib.h> #include <sys/linker_set.h> #include <pthread.h> @@ -57,7 +58,7 @@ struct usb_devemu { int ue_usbspeed; /* usb device speed */ /* instance creation */ - void *(*ue_init)(struct usb_hci *hci, char *opt); + void *(*ue_init)(struct usb_hci *hci, nvlist_t *nvl); /* handlers */ int (*ue_request)(void *sc, struct usb_data_xfer *xfer); @@ -155,7 +156,7 @@ enum USB_ERRCODE { #define USB_DATA_XFER_LOCK_HELD(x) MUTEX_HELD(&((x)->mtx)) #endif -struct usb_devemu *usb_emu_finddev(char *name); +struct usb_devemu *usb_emu_finddev(const char *name); struct usb_data_xfer_block *usb_data_xfer_append(struct usb_data_xfer *xfer, void *buf, int blen, void *hci_data, int ccs); diff --git a/usr/src/cmd/bhyve/usb_mouse.c b/usr/src/cmd/bhyve/usb_mouse.c index 7790fe0ec9..340fdc0cb0 100644 --- a/usr/src/cmd/bhyve/usb_mouse.c +++ b/usr/src/cmd/bhyve/usb_mouse.c @@ -239,8 +239,6 @@ struct umouse_bos_desc umouse_bosd = { struct umouse_softc { struct usb_hci *hci; - char *opt; - struct umouse_report um_report; int newdata; struct { @@ -297,7 +295,7 @@ umouse_event(uint8_t button, int x, int y, void *arg) } static void * -umouse_init(struct usb_hci *hci, char *opt) +umouse_init(struct usb_hci *hci, nvlist_t *nvl) { struct umouse_softc *sc; @@ -305,7 +303,6 @@ umouse_init(struct usb_hci *hci, char *opt) sc->hci = hci; sc->hid.protocol = 1; /* REPORT protocol */ - sc->opt = strdup(opt); pthread_mutex_init(&sc->mtx, NULL); pthread_mutex_init(&sc->ev_mtx, NULL); diff --git a/usr/src/cmd/bhyve/virtio.c b/usr/src/cmd/bhyve/virtio.c index d899a57795..b7e858694f 100644 --- a/usr/src/cmd/bhyve/virtio.c +++ b/usr/src/cmd/bhyve/virtio.c @@ -35,6 +35,10 @@ __FBSDID("$FreeBSD$"); #include <machine/atomic.h> +#ifdef __FreeBSD__ +#include <dev/virtio/pci/virtio_pci_legacy_var.h> +#endif + #include <stdio.h> #include <stdint.h> #include <pthread.h> @@ -126,10 +130,10 @@ vi_set_io_bar(struct virtio_softc *vs, int barnum) size_t size; /* - * ??? should we use CFG0 if MSI-X is disabled? + * ??? should we use VIRTIO_PCI_CONFIG_OFF(0) if MSI-X is disabled? * Existing code did not... */ - size = VTCFG_R_CFG1 + vs->vs_vc->vc_cfgsize; + size = VIRTIO_PCI_CONFIG_OFF(1) + vs->vs_vc->vc_cfgsize; pci_emul_alloc_bar(vs->vs_pi, barnum, PCIBAR_IO, size); } @@ -181,12 +185,12 @@ vi_vq_init(struct virtio_softc *vs, uint32_t pfn) vq = &vs->vs_queues[vs->vs_curq]; vq->vq_pfn = pfn; phys = (uint64_t)pfn << VRING_PFN; - size = vring_size(vq->vq_qsize); + size = vring_size_aligned(vq->vq_qsize); base = paddr_guest2host(vs->vs_pi->pi_vmctx, phys, size); /* First page(s) are descriptors... */ - vq->vq_desc = (struct virtio_desc *)base; - base += vq->vq_qsize * sizeof(struct virtio_desc); + vq->vq_desc = (struct vring_desc *)base; + base += vq->vq_qsize * sizeof(struct vring_desc); /* ... immediately followed by "avail" ring (entirely uint16_t's) */ vq->vq_avail = (struct vring_avail *)base; @@ -210,15 +214,15 @@ vi_vq_init(struct virtio_softc *vs, uint32_t pfn) * descriptor. */ static inline void -_vq_record(int i, volatile struct virtio_desc *vd, struct vmctx *ctx, +_vq_record(int i, volatile struct vring_desc *vd, struct vmctx *ctx, struct iovec *iov, int n_iov, uint16_t *flags) { if (i >= n_iov) return; - iov[i].iov_base = paddr_guest2host(ctx, vd->vd_addr, vd->vd_len); - iov[i].iov_len = vd->vd_len; + iov[i].iov_base = paddr_guest2host(ctx, vd->addr, vd->len); + iov[i].iov_len = vd->len; if (flags != NULL) - flags[i] = vd->vd_flags; + flags[i] = vd->flags; } #define VQ_MAX_DESCRIPTORS 512 /* see below */ @@ -235,7 +239,7 @@ _vq_record(int i, volatile struct virtio_desc *vd, struct vmctx *ctx, * i.e., we do not count the indirect descriptors, only the "real" * ones. * - * Basically, this vets the vd_flags and vd_next field of each + * Basically, this vets the "flags" and "next" field of each * descriptor and tells you how many are involved. Since some may * be indirect, this also needs the vmctx (in the pci_devinst * at vs->vs_pi) so that it can find indirect descriptors. @@ -252,7 +256,7 @@ _vq_record(int i, volatile struct virtio_desc *vd, struct vmctx *ctx, * * If you want to verify the WRITE flag on each descriptor, pass a * non-NULL "flags" pointer to an array of "uint16_t" of the same size - * as n_iov and we'll copy each vd_flags field after unwinding any + * as n_iov and we'll copy each "flags" field after unwinding any * indirects. * * If some descriptor(s) are invalid, this prints a diagnostic message @@ -268,7 +272,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, int i; u_int ndesc, n_indir; u_int idx, next; - volatile struct virtio_desc *vdir, *vindir, *vp; + volatile struct vring_desc *vdir, *vindir, *vp; struct vmctx *ctx; struct virtio_softc *vs; const char *name; @@ -278,11 +282,11 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, /* * Note: it's the responsibility of the guest not to - * update vq->vq_avail->va_idx until all of the descriptors + * update vq->vq_avail->idx until all of the descriptors * the guest has written are valid (including all their - * vd_next fields and vd_flags). + * "next" fields and "flags"). * - * Compute (va_idx - last_avail) in integers mod 2**16. This is + * Compute (vq_avail->idx - last_avail) in integers mod 2**16. This is * the number of descriptors the device has made available * since the last time we updated vq->vq_last_avail. * @@ -290,7 +294,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, * then trim off excess bits. */ idx = vq->vq_last_avail; - ndesc = (uint16_t)((u_int)vq->vq_avail->va_idx - idx); + ndesc = (uint16_t)((u_int)vq->vq_avail->idx - idx); if (ndesc == 0) return (0); if (ndesc > vq->vq_qsize) { @@ -310,9 +314,9 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, * index, but we just abort if the count gets excessive. */ ctx = vs->vs_pi->pi_vmctx; - *pidx = next = vq->vq_avail->va_ring[idx & (vq->vq_qsize - 1)]; + *pidx = next = vq->vq_avail->ring[idx & (vq->vq_qsize - 1)]; vq->vq_last_avail++; - for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->vd_next) { + for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->next) { if (next >= vq->vq_qsize) { EPRINTLN( "%s: descriptor index %u out of range, " @@ -321,7 +325,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, return (-1); } vdir = &vq->vq_desc[next]; - if ((vdir->vd_flags & VRING_DESC_F_INDIRECT) == 0) { + if ((vdir->flags & VRING_DESC_F_INDIRECT) == 0) { _vq_record(i, vdir, ctx, iov, n_iov, flags); i++; } else if ((vs->vs_vc->vc_hv_caps & @@ -332,16 +336,16 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, name); return (-1); } else { - n_indir = vdir->vd_len / 16; - if ((vdir->vd_len & 0xf) || n_indir == 0) { + n_indir = vdir->len / 16; + if ((vdir->len & 0xf) || n_indir == 0) { EPRINTLN( "%s: invalid indir len 0x%x, " "driver confused?", - name, (u_int)vdir->vd_len); + name, (u_int)vdir->len); return (-1); } vindir = paddr_guest2host(ctx, - vdir->vd_addr, vdir->vd_len); + vdir->addr, vdir->len); /* * Indirects start at the 0th, then follow * their own embedded "next"s until those run @@ -352,7 +356,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, next = 0; for (;;) { vp = &vindir[next]; - if (vp->vd_flags & VRING_DESC_F_INDIRECT) { + if (vp->flags & VRING_DESC_F_INDIRECT) { EPRINTLN( "%s: indirect desc has INDIR flag," " driver confused?", @@ -362,9 +366,9 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, _vq_record(i, vp, ctx, iov, n_iov, flags); if (++i > VQ_MAX_DESCRIPTORS) goto loopy; - if ((vp->vd_flags & VRING_DESC_F_NEXT) == 0) + if ((vp->flags & VRING_DESC_F_NEXT) == 0) break; - next = vp->vd_next; + next = vp->next; if (next >= n_indir) { EPRINTLN( "%s: invalid next %u > %u, " @@ -374,7 +378,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx, } } } - if ((vdir->vd_flags & VRING_DESC_F_NEXT) == 0) + if ((vdir->flags & VRING_DESC_F_NEXT) == 0) return (i); } loopy: @@ -401,7 +405,7 @@ void vq_relchain_prepare(struct vqueue_info *vq, uint16_t idx, uint32_t iolen) { volatile struct vring_used *vuh; - volatile struct virtio_used *vue; + volatile struct vring_used_elem *vue; uint16_t mask; /* @@ -409,16 +413,13 @@ vq_relchain_prepare(struct vqueue_info *vq, uint16_t idx, uint32_t iolen) * - mask is N-1 where N is a power of 2 so computes x % N * - vuh points to the "used" data shared with guest * - vue points to the "used" ring entry we want to update - * - * (I apologize for the two fields named vu_idx; the - * virtio spec calls the one that vue points to, "id"...) */ mask = vq->vq_qsize - 1; vuh = vq->vq_used; - vue = &vuh->vu_ring[vq->vq_next_used++ & mask]; - vue->vu_idx = idx; - vue->vu_tlen = iolen; + vue = &vuh->ring[vq->vq_next_used++ & mask]; + vue->id = idx; + vue->len = iolen; } void @@ -430,7 +431,7 @@ vq_relchain_publish(struct vqueue_info *vq) * (and even on x86 to act as a compiler barrier). */ atomic_thread_fence_rel(); - vq->vq_used->vu_idx = vq->vq_next_used; + vq->vq_used->idx = vq->vq_next_used; } /* @@ -480,12 +481,12 @@ vq_endchains(struct vqueue_info *vq, int used_all_avail) */ vs = vq->vq_vs; old_idx = vq->vq_save_used; - vq->vq_save_used = new_idx = vq->vq_used->vu_idx; + vq->vq_save_used = new_idx = vq->vq_used->idx; /* - * Use full memory barrier between vu_idx store from preceding + * Use full memory barrier between "idx" store from preceding * vq_relchain() call and the loads from VQ_USED_EVENT_IDX() or - * va_flags below. + * "flags" field below. */ atomic_thread_fence_seq_cst(); if (used_all_avail && @@ -501,7 +502,7 @@ vq_endchains(struct vqueue_info *vq, int used_all_avail) (uint16_t)(new_idx - old_idx); } else { intr = new_idx != old_idx && - !(vq->vq_avail->va_flags & VRING_AVAIL_F_NO_INTERRUPT); + !(vq->vq_avail->flags & VRING_AVAIL_F_NO_INTERRUPT); } if (intr) vq_interrupt(vs, vq); @@ -514,16 +515,16 @@ static struct config_reg { uint8_t cr_ro; /* true => reg is read only */ const char *cr_name; /* name of reg */ } config_regs[] = { - { VTCFG_R_HOSTCAP, 4, 1, "HOSTCAP" }, - { VTCFG_R_GUESTCAP, 4, 0, "GUESTCAP" }, - { VTCFG_R_PFN, 4, 0, "PFN" }, - { VTCFG_R_QNUM, 2, 1, "QNUM" }, - { VTCFG_R_QSEL, 2, 0, "QSEL" }, - { VTCFG_R_QNOTIFY, 2, 0, "QNOTIFY" }, - { VTCFG_R_STATUS, 1, 0, "STATUS" }, - { VTCFG_R_ISR, 1, 0, "ISR" }, - { VTCFG_R_CFGVEC, 2, 0, "CFGVEC" }, - { VTCFG_R_QVEC, 2, 0, "QVEC" }, + { VIRTIO_PCI_HOST_FEATURES, 4, 1, "HOST_FEATURES" }, + { VIRTIO_PCI_GUEST_FEATURES, 4, 0, "GUEST_FEATURES" }, + { VIRTIO_PCI_QUEUE_PFN, 4, 0, "QUEUE_PFN" }, + { VIRTIO_PCI_QUEUE_NUM, 2, 1, "QUEUE_NUM" }, + { VIRTIO_PCI_QUEUE_SEL, 2, 0, "QUEUE_SEL" }, + { VIRTIO_PCI_QUEUE_NOTIFY, 2, 0, "QUEUE_NOTIFY" }, + { VIRTIO_PCI_STATUS, 1, 0, "STATUS" }, + { VIRTIO_PCI_ISR, 1, 0, "ISR" }, + { VIRTIO_MSI_CONFIG_VECTOR, 2, 0, "CONFIG_VECTOR" }, + { VIRTIO_MSI_QUEUE_VECTOR, 2, 0, "QUEUE_VECTOR" }, }; static inline struct config_reg * @@ -585,10 +586,7 @@ vi_pci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, if (size != 1 && size != 2 && size != 4) goto bad; - if (pci_msix_enabled(pi)) - virtio_config_size = VTCFG_R_CFG1; - else - virtio_config_size = VTCFG_R_CFG0; + virtio_config_size = VIRTIO_PCI_CONFIG_OFF(pci_msix_enabled(pi)); if (offset >= virtio_config_size) { /* @@ -622,39 +620,39 @@ bad: } switch (offset) { - case VTCFG_R_HOSTCAP: + case VIRTIO_PCI_HOST_FEATURES: value = vc->vc_hv_caps; break; - case VTCFG_R_GUESTCAP: + case VIRTIO_PCI_GUEST_FEATURES: value = vs->vs_negotiated_caps; break; - case VTCFG_R_PFN: + case VIRTIO_PCI_QUEUE_PFN: if (vs->vs_curq < vc->vc_nvq) value = vs->vs_queues[vs->vs_curq].vq_pfn; break; - case VTCFG_R_QNUM: + case VIRTIO_PCI_QUEUE_NUM: value = vs->vs_curq < vc->vc_nvq ? vs->vs_queues[vs->vs_curq].vq_qsize : 0; break; - case VTCFG_R_QSEL: + case VIRTIO_PCI_QUEUE_SEL: value = vs->vs_curq; break; - case VTCFG_R_QNOTIFY: + case VIRTIO_PCI_QUEUE_NOTIFY: value = 0; /* XXX */ break; - case VTCFG_R_STATUS: + case VIRTIO_PCI_STATUS: value = vs->vs_status; break; - case VTCFG_R_ISR: + case VIRTIO_PCI_ISR: value = vs->vs_isr; vs->vs_isr = 0; /* a read clears this flag */ if (value) pci_lintr_deassert(pi); break; - case VTCFG_R_CFGVEC: + case VIRTIO_MSI_CONFIG_VECTOR: value = vs->vs_msix_cfg_idx; break; - case VTCFG_R_QVEC: + case VIRTIO_MSI_QUEUE_VECTOR: value = vs->vs_curq < vc->vc_nvq ? vs->vs_queues[vs->vs_curq].vq_msix_idx : VIRTIO_MSI_NO_VECTOR; @@ -705,10 +703,7 @@ vi_pci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, if (size != 1 && size != 2 && size != 4) goto bad; - if (pci_msix_enabled(pi)) - virtio_config_size = VTCFG_R_CFG1; - else - virtio_config_size = VTCFG_R_CFG0; + virtio_config_size = VIRTIO_PCI_CONFIG_OFF(pci_msix_enabled(pi)); if (offset >= virtio_config_size) { /* @@ -746,18 +741,18 @@ bad: } switch (offset) { - case VTCFG_R_GUESTCAP: + case VIRTIO_PCI_GUEST_FEATURES: vs->vs_negotiated_caps = value & vc->vc_hv_caps; if (vc->vc_apply_features) (*vc->vc_apply_features)(DEV_SOFTC(vs), vs->vs_negotiated_caps); break; - case VTCFG_R_PFN: + case VIRTIO_PCI_QUEUE_PFN: if (vs->vs_curq >= vc->vc_nvq) goto bad_qindex; vi_vq_init(vs, value); break; - case VTCFG_R_QSEL: + case VIRTIO_PCI_QUEUE_SEL: /* * Note that the guest is allowed to select an * invalid queue; we just need to return a QNUM @@ -765,7 +760,7 @@ bad: */ vs->vs_curq = value; break; - case VTCFG_R_QNOTIFY: + case VIRTIO_PCI_QUEUE_NOTIFY: if (value >= vc->vc_nvq) { EPRINTLN("%s: queue %d notify out of range", name, (int)value); @@ -781,15 +776,15 @@ bad: "%s: qnotify queue %d: missing vq/vc notify", name, (int)value); break; - case VTCFG_R_STATUS: + case VIRTIO_PCI_STATUS: vs->vs_status = value; if (value == 0) (*vc->vc_reset)(DEV_SOFTC(vs)); break; - case VTCFG_R_CFGVEC: + case VIRTIO_MSI_CONFIG_VECTOR: vs->vs_msix_cfg_idx = value; break; - case VTCFG_R_QVEC: + case VIRTIO_MSI_QUEUE_VECTOR: if (vs->vs_curq >= vc->vc_nvq) goto bad_qindex; vq = &vs->vs_queues[vs->vs_curq]; diff --git a/usr/src/cmd/bhyve/virtio.h b/usr/src/cmd/bhyve/virtio.h index b28e61d353..16d7c5c25e 100644 --- a/usr/src/cmd/bhyve/virtio.h +++ b/usr/src/cmd/bhyve/virtio.h @@ -28,12 +28,18 @@ * $FreeBSD$ */ -#ifndef _VIRTIO_H_ -#define _VIRTIO_H_ +#ifndef _BHYVE_VIRTIO_H_ +#define _BHYVE_VIRTIO_H_ #include <pthread_np.h> #include <machine/atomic.h> +#include <dev/virtio/virtio.h> +#ifdef __FreeBSD__ +#include <dev/virtio/virtio_ring.h> +#include <dev/virtio/pci/virtio_pci_var.h> +#endif + /* * These are derived from several virtio specifications. * @@ -126,39 +132,6 @@ */ #define VRING_ALIGN 4096 -#define VRING_DESC_F_NEXT (1 << 0) -#define VRING_DESC_F_WRITE (1 << 1) -#define VRING_DESC_F_INDIRECT (1 << 2) - -struct virtio_desc { /* AKA vring_desc */ - uint64_t vd_addr; /* guest physical address */ - uint32_t vd_len; /* length of scatter/gather seg */ - uint16_t vd_flags; /* VRING_F_DESC_* */ - uint16_t vd_next; /* next desc if F_NEXT */ -} __packed; - -struct virtio_used { /* AKA vring_used_elem */ - uint32_t vu_idx; /* head of used descriptor chain */ - uint32_t vu_tlen; /* length written-to */ -} __packed; - -#define VRING_AVAIL_F_NO_INTERRUPT 1 - -struct vring_avail { - uint16_t va_flags; /* VRING_AVAIL_F_* */ - uint16_t va_idx; /* counts to 65535, then cycles */ - uint16_t va_ring[]; /* size N, reported in QNUM value */ -/* uint16_t va_used_event; -- after N ring entries */ -} __packed; - -#define VRING_USED_F_NO_NOTIFY 1 -struct vring_used { - uint16_t vu_flags; /* VRING_USED_F_* */ - uint16_t vu_idx; /* counts to 65535, then cycles */ - struct virtio_used vu_ring[]; /* size N */ -/* uint16_t vu_avail_event; -- after N ring entries */ -} __packed; - /* * The address of any given virtual queue is determined by a single * Page Frame Number register. The guest writes the PFN into the @@ -192,23 +165,6 @@ struct vring_used { #define VRING_PFN 12 /* - * Virtio device types - * - * XXX Should really be merged with <dev/virtio/virtio.h> defines - */ -#define VIRTIO_TYPE_NET 1 -#define VIRTIO_TYPE_BLOCK 2 -#define VIRTIO_TYPE_CONSOLE 3 -#define VIRTIO_TYPE_ENTROPY 4 -#define VIRTIO_TYPE_BALLOON 5 -#define VIRTIO_TYPE_IOMEMORY 6 -#define VIRTIO_TYPE_RPMSG 7 -#define VIRTIO_TYPE_SCSI 8 -#define VIRTIO_TYPE_9P 9 - -/* experimental IDs start at 65535 and work down */ - -/* * PCI vendor/device IDs */ #define VIRTIO_VENDOR 0x1AF4 @@ -217,72 +173,13 @@ struct vring_used { #define VIRTIO_DEV_CONSOLE 0x1003 #define VIRTIO_DEV_RANDOM 0x1005 #define VIRTIO_DEV_SCSI 0x1008 - -/* - * PCI config space constants. - * - * If MSI-X is enabled, the ISR register is generally not used, - * and the configuration vector and queue vector appear at offsets - * 20 and 22 with the remaining configuration registers at 24. - * If MSI-X is not enabled, those two registers disappear and - * the remaining configuration registers start at offset 20. - */ -#define VTCFG_R_HOSTCAP 0 -#define VTCFG_R_GUESTCAP 4 -#define VTCFG_R_PFN 8 -#define VTCFG_R_QNUM 12 -#define VTCFG_R_QSEL 14 -#define VTCFG_R_QNOTIFY 16 -#define VTCFG_R_STATUS 18 -#define VTCFG_R_ISR 19 -#define VTCFG_R_CFGVEC 20 -#define VTCFG_R_QVEC 22 -#define VTCFG_R_CFG0 20 /* No MSI-X */ -#define VTCFG_R_CFG1 24 /* With MSI-X */ -#define VTCFG_R_MSIX 20 - -/* - * Bits in VTCFG_R_STATUS. Guests need not actually set any of these, - * but a guest writing 0 to this register means "please reset". - */ -#define VTCFG_STATUS_ACK 0x01 /* guest OS has acknowledged dev */ -#define VTCFG_STATUS_DRIVER 0x02 /* guest OS driver is loaded */ -#define VTCFG_STATUS_DRIVER_OK 0x04 /* guest OS driver ready */ -#define VTCFG_STATUS_FAILED 0x80 /* guest has given up on this dev */ - -/* - * Bits in VTCFG_R_ISR. These apply only if not using MSI-X. - * - * (We don't [yet?] ever use CONF_CHANGED.) - */ -#define VTCFG_ISR_QUEUES 0x01 /* re-scan queues */ -#define VTCFG_ISR_CONF_CHANGED 0x80 /* configuration changed */ - -#define VIRTIO_MSI_NO_VECTOR 0xFFFF - -/* - * Feature flags. - * Note: bits 0 through 23 are reserved to each device type. - */ -#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24) -#define VIRTIO_RING_F_INDIRECT_DESC (1 << 28) -#define VIRTIO_RING_F_EVENT_IDX (1 << 29) +#define VIRTIO_DEV_9P 0x1009 /* From section 2.3, "Virtqueue Configuration", of the virtio specification */ -static inline size_t -vring_size(u_int qsz) +static inline int +vring_size_aligned(u_int qsz) { - size_t size; - - /* constant 3 below = va_flags, va_idx, va_used_event */ - size = sizeof(struct virtio_desc) * qsz + sizeof(uint16_t) * (3 + qsz); - size = roundup2(size, VRING_ALIGN); - - /* constant 3 below = vu_flags, vu_idx, vu_avail_event */ - size += sizeof(uint16_t) * 3 + sizeof(struct virtio_used) * qsz; - size = roundup2(size, VRING_ALIGN); - - return (size); + return (roundup2(vring_size(qsz, VRING_ALIGN), VRING_ALIGN)); } struct vmctx; @@ -392,23 +289,23 @@ struct vqueue_info { uint16_t vq_num; /* we're the num'th queue in the softc */ uint16_t vq_flags; /* flags (see above) */ - uint16_t vq_last_avail; /* a recent value of vq_avail->va_idx */ + uint16_t vq_last_avail; /* a recent value of vq_avail->idx */ uint16_t vq_next_used; /* index of the next used slot to be filled */ - uint16_t vq_save_used; /* saved vq_used->vu_idx; see vq_endchains */ + uint16_t vq_save_used; /* saved vq_used->idx; see vq_endchains */ uint16_t vq_msix_idx; /* MSI-X index, or VIRTIO_MSI_NO_VECTOR */ uint32_t vq_pfn; /* PFN of virt queue (not shifted!) */ - volatile struct virtio_desc *vq_desc; /* descriptor array */ + volatile struct vring_desc *vq_desc; /* descriptor array */ volatile struct vring_avail *vq_avail; /* the "avail" ring */ volatile struct vring_used *vq_used; /* the "used" ring */ }; /* as noted above, these are sort of backwards, name-wise */ #define VQ_AVAIL_EVENT_IDX(vq) \ - (*(volatile uint16_t *)&(vq)->vq_used->vu_ring[(vq)->vq_qsize]) + (*(volatile uint16_t *)&(vq)->vq_used->ring[(vq)->vq_qsize]) #define VQ_USED_EVENT_IDX(vq) \ - ((vq)->vq_avail->va_ring[(vq)->vq_qsize]) + ((vq)->vq_avail->ring[(vq)->vq_qsize]) /* * Is this ring ready for I/O? @@ -429,7 +326,7 @@ vq_has_descs(struct vqueue_info *vq) { return (vq_ring_ready(vq) && vq->vq_last_avail != - vq->vq_avail->va_idx); + vq->vq_avail->idx); } /* @@ -469,11 +366,11 @@ static inline void vq_kick_enable(struct vqueue_info *vq) { - vq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY; + vq->vq_used->flags &= ~VRING_USED_F_NO_NOTIFY; /* - * Full memory barrier to make sure the store to vu_flags - * happens before the load from va_idx, which results from - * a subsequent call to vq_has_descs(). + * Full memory barrier to make sure the store to vq_used->flags + * happens before the load from vq_avail->idx, which results from a + * subsequent call to vq_has_descs(). */ atomic_thread_fence_seq_cst(); } @@ -482,7 +379,7 @@ static inline void vq_kick_disable(struct vqueue_info *vq) { - vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY; + vq->vq_used->flags |= VRING_USED_F_NO_NOTIFY; } struct iovec; @@ -506,4 +403,4 @@ uint64_t vi_pci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size); void vi_pci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size, uint64_t value); -#endif /* _VIRTIO_H_ */ +#endif /* _BHYVE_VIRTIO_H_ */ diff --git a/usr/src/cmd/bhyvectl/bhyvectl.c b/usr/src/cmd/bhyvectl/bhyvectl.c index 2948c14ebb..313a1a37f4 100644 --- a/usr/src/cmd/bhyvectl/bhyvectl.c +++ b/usr/src/cmd/bhyvectl/bhyvectl.c @@ -1959,7 +1959,9 @@ main(int argc, char *argv[]) if (!error) { ctx = vm_open(vmname); if (ctx == NULL) { - printf("VM:%s is not created.\n", vmname); + fprintf(stderr, + "vm_open: %s could not be opened: %s\n", + vmname, strerror(errno)); exit (1); } } |