Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143930584
D2448.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
41 KB
Referenced Files
None
Subscribers
None
D2448.diff
View Options
Index: etc/defaults/bhyve.conf
===================================================================
--- /dev/null
+++ etc/defaults/bhyve.conf
@@ -0,0 +1,16 @@
+.include(priority=3, glob=true, try=true, prefix=true) "/etc/bhyve.conf.d/*.conf"
+.include(priority=5, try=true) "/etc/bhyve.conf"
+cpus = 1;
+memory = 256MB;
+console = "stdio";
+acpi = true;
+vmexit_on_hlt = true;
+vmexit_on_pause = true;
+device {
+ slot = "0:0";
+ type = "hostbridge";
+}
+device {
+ slot = "1:0";
+ type = "lpc";
+}
Index: etc/mtree/BSD.root.dist
===================================================================
--- etc/mtree/BSD.root.dist
+++ etc/mtree/BSD.root.dist
@@ -28,6 +28,8 @@
..
autofs
..
+ bhyve.conf.d
+ ..
bluetooth
..
casper
Index: usr.sbin/bhyve/Makefile
===================================================================
--- usr.sbin/bhyve/Makefile
+++ usr.sbin/bhyve/Makefile
@@ -20,6 +20,7 @@
bootrom.c \
console.c \
consport.c \
+ config.c \
dbgport.c \
fwctl.c \
inout.c \
@@ -61,11 +62,12 @@
.PATH: ${BHYVE_SYSDIR}/sys/amd64/vmm
SRCS+= vmm_instruction_emul.c
-LIBADD= vmmapi md pthread z
+LIBADD= vmmapi md pthread ucl z
CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/e1000
CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/mii
CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/usb/controller
+CFLAGS+= -I${SRCTOP}/contrib/libucl/include
WARNS?= 2
Index: usr.sbin/bhyve/bhyve.8
===================================================================
--- usr.sbin/bhyve/bhyve.8
+++ usr.sbin/bhyve/bhyve.8
@@ -34,6 +34,7 @@
.Nm
.Op Fl abehuwxACHPSWY
.Op Fl c Ar numcpus
+.Op Fl f Ar bhyve.conf
.Op Fl g Ar gdbport
.Op Fl l Ar lpcdev Ns Op , Ns Ar conf
.Op Fl m Ar memsize Ns Op Ar K|k|M|m|G|g|T|t
@@ -41,6 +42,8 @@
.Op Fl s Ar slot,emulation Ns Op , Ns Ar conf
.Op Fl U Ar uuid
.Ar vmname
+.Nm
+.Fl f Ar bhyve.conf
.Sh DESCRIPTION
.Nm
is a hypervisor that runs guest operating systems inside a
@@ -84,6 +87,9 @@
.Nm
to exit when a guest issues an access to an I/O port that is not emulated.
This is intended for debug purposes.
+.It Fl f Ar bhyve.conf
+Read configuration from specified file.
+Supersedes any flags specified before this flag.
.It Fl g Ar gdbport
For
.Fx
@@ -389,6 +395,11 @@
-l com1,/dev/nmdm0A \\
-A -H -P -m 8G
.Ed
+.Pp
+Run a virtual machine described in a configuration file:
+.Bd -literal -offset ident
+bhyve -f guest.conf
+.Ed
.Sh SEE ALSO
.Xr bhyve 4 ,
.Xr nmdm 4 ,
Index: usr.sbin/bhyve/bhyverun.h
===================================================================
--- usr.sbin/bhyve/bhyverun.h
+++ usr.sbin/bhyve/bhyverun.h
@@ -33,9 +33,7 @@
#define VMEXIT_ABORT (-1)
struct vmctx;
-extern int guest_ncpus;
-extern char *guest_uuid_str;
-extern char *vmname;
+extern struct config_entry vmconf;
void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len);
Index: usr.sbin/bhyve/bhyverun.c
===================================================================
--- usr.sbin/bhyve/bhyverun.c
+++ usr.sbin/bhyve/bhyverun.c
@@ -44,6 +44,7 @@
#endif
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <err.h>
#include <errno.h>
@@ -62,6 +63,7 @@
#endif
#include <vmmapi.h>
+#include "config.h"
#include "bhyverun.h"
#include "acpi.h"
#include "atkbdc.h"
@@ -80,27 +82,48 @@
#include "spinup_ap.h"
#include "rtc.h"
-#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
+#include <ucl.h>
-#define MB (1024UL * 1024)
-#define GB (1024UL * MB)
+#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
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;
-char *guest_uuid_str;
-
-static int guest_vmexit_on_hlt, guest_vmexit_on_pause;
-static int virtio_msix = 1;
-static int x2apic_mode = 0; /* default is xAPIC */
+struct config_slot_entry sinit = {
+ .bnum = 0,
+ .snum = 0,
+ .fnum = 0,
+ .emul = NULL,
+ .config = NULL
+};
-static int strictio;
-static int strictmsr = 1;
+struct config_entry cinit = {
+ .vmname = NULL,
+ .vcpus = 1,
+ .memsize = 256 * MB,
+ .console = NULL,
+ .host_base = NULL,
+ .pincpu = NULL,
+ .lpc_device = NULL,
+ .uuid = NULL,
+ .env = NULL,
+ .env_count = 0,
+ .slots = {NULL},
+ .slot_count = 0,
+ .gdb_port = 0,
+ .acpi = 0,
+ .dump_memory = 0,
+ .vmexit_on_hlt = 0,
+ .vmexit_on_pause = 0,
+ .strictio = 0,
+ .rtc_localtime = 1,
+ .strictmsr = 1,
+ .virtio_msix = 1,
+ .x2apic_mode = 0,
+ .mptgen = 1
+};
-static int acpi;
+struct config_entry vmconf;
static char *progname;
static const int BSP = 0;
@@ -142,6 +165,7 @@
" -c: # cpus (default 1)\n"
" -C: include guest memory in core file\n"
" -e: exit on unhandled I/O access\n"
+ " -f: UCL config file to read\n"
" -g: gdb port\n"
" -h: help\n"
" -H: vmexit from the guest on hlt\n"
@@ -221,21 +245,21 @@
fbsdrun_vmexit_on_pause(void)
{
- return (guest_vmexit_on_pause);
+ return (vmconf.vmexit_on_pause);
}
int
fbsdrun_vmexit_on_hlt(void)
{
- return (guest_vmexit_on_hlt);
+ return (vmconf.vmexit_on_hlt);
}
int
fbsdrun_virtio_msix(void)
{
- return (virtio_msix);
+ return (vmconf.virtio_msix);
}
static void *
@@ -337,7 +361,7 @@
return (error);
}
- error = emulate_inout(ctx, vcpu, vme, strictio);
+ error = emulate_inout(ctx, vcpu, vme, vmconf.strictio);
if (error) {
fprintf(stderr, "Unhandled %s%c 0x%04x at 0x%lx\n",
in ? "in" : "out",
@@ -361,7 +385,7 @@
if (error != 0) {
fprintf(stderr, "rdmsr to register %#x on vcpu %d\n",
vme->u.msr.code, *pvcpu);
- if (strictmsr) {
+ if (vmconf.strictmsr) {
vm_inject_gp(ctx, *pvcpu);
return (VMEXIT_CONTINUE);
}
@@ -387,7 +411,7 @@
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 (vmconf.strictmsr) {
vm_inject_gp(ctx, *pvcpu);
return (VMEXIT_CONTINUE);
}
@@ -697,7 +721,7 @@
handler[VM_EXITCODE_PAUSE] = vmexit_pause;
}
- if (x2apic_mode)
+ if (vmconf.x2apic_mode)
err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED);
else
err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED);
@@ -787,49 +811,53 @@
int
main(int argc, char *argv[])
{
- int c, error, gdb_port, err, bvmcons;
- int max_vcpus, mptgen, memflags;
- int rtc_localtime;
+ int c, error, err, bvmcons;
+ int max_vcpus, memflags;
struct vmctx *ctx;
uint64_t rip;
- size_t memsize;
+ char *temp;
+ int pci_err;
+ size_t slot;
+ bool new_config;
char *optstr;
+ memcpy(&vmconf, &cinit, sizeof(struct config_entry));
bvmcons = 0;
progname = basename(argv[0]);
- gdb_port = 0;
- guest_ncpus = 1;
- memsize = 256 * MB;
- mptgen = 1;
- rtc_localtime = 1;
+ temp = NULL;
+ new_config = false;
memflags = 0;
optstr = "abehuwxACHIPSWYp:g:c:s:m:l:U:";
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
case 'a':
- x2apic_mode = 0;
+ vmconf.x2apic_mode = 0;
break;
case 'A':
- acpi = 1;
+ vmconf.acpi = 1;
break;
case 'b':
bvmcons = 1;
break;
+ case 'f':
+ new_config = true;
+ load_config(optarg, NULL, &vmconf);
+ break;
case 'p':
- if (pincpu_parse(optarg) != 0) {
- errx(EX_USAGE, "invalid vcpu pinning "
- "configuration '%s'", optarg);
- }
+ if (pincpu_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid vcpu pinning "
+ "configuration '%s'", optarg);
+ }
break;
- case 'c':
- guest_ncpus = atoi(optarg);
+ case 'c':
+ vmconf.vcpus = atoi(optarg);
break;
case 'C':
memflags |= VM_MEM_F_INCORE;
break;
case 'g':
- gdb_port = atoi(optarg);
+ vmconf.gdb_port = atoi(optarg);
break;
case 'l':
if (lpc_device_parse(optarg) != 0) {
@@ -846,12 +874,12 @@
memflags |= VM_MEM_F_WIRED;
break;
case 'm':
- error = vm_parse_memsize(optarg, &memsize);
+ error = vm_parse_memsize(optarg, &vmconf.memsize);
if (error)
errx(EX_USAGE, "invalid memsize '%s'", optarg);
break;
case 'H':
- guest_vmexit_on_hlt = 1;
+ vmconf.vmexit_on_hlt = 1;
break;
case 'I':
/*
@@ -863,31 +891,31 @@
*/
break;
case 'P':
- guest_vmexit_on_pause = 1;
+ vmconf.vmexit_on_pause = 1;
break;
case 'e':
- strictio = 1;
+ vmconf.strictio = 1;
break;
case 'u':
- rtc_localtime = 0;
+ vmconf.rtc_localtime = 0;
break;
case 'U':
- guest_uuid_str = optarg;
+ vmconf.uuid = optarg;
break;
case 'w':
- strictmsr = 0;
+ vmconf.strictmsr = 0;
break;
case 'W':
- virtio_msix = 0;
+ vmconf.virtio_msix = 0;
break;
case 'x':
- x2apic_mode = 1;
+ vmconf.x2apic_mode = 1;
break;
case 'Y':
- mptgen = 0;
+ vmconf.mptgen = 0;
break;
case 'h':
- usage(0);
+ usage(0);
default:
usage(1);
}
@@ -895,28 +923,81 @@
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (new_config) {
+ asprintf(&temp, "%zu", vmconf.memsize);
+ error = vm_parse_memsize(temp, &vmconf.memsize);
+ if (error)
+ errx(EX_USAGE, "invalid memsize '%s'", optarg);
+ free(temp);
+
+ asprintf(&temp, "com1,%s", vmconf.console);
+ if (lpc_device_parse(temp) != 0) {
+ errx(EX_USAGE, "invalid lpc device "
+ "configuration '%s'", temp);
+ }
+ free(temp);
+
+ if (vmconf.pincpu && pincpu_parse(vmconf.pincpu) != 0) {
+ errx(EX_USAGE, "invalid vcpu pinning "
+ "configuration '%s'", vmconf.pincpu);
+ }
+
+ for (slot = 0; slot < vmconf.slot_count; slot++) {
+ if (strcasecmp(vmconf.slots[slot]->emul, "virtio-blk") == 0 ||
+ strcasecmp(vmconf.slots[slot]->emul, "ahci-hd") == 0) {
+ asprintf(&vmconf.slots[slot]->config, "%s%s%s%s",
+ vmconf.slots[slot]->disk.path,
+ (vmconf.slots[slot]->disk.nocache ? ",nocache" : ""),
+ (vmconf.slots[slot]->disk.sync ? ",sync" : ""),
+ (vmconf.slots[slot]->disk.ro ? ",ro" : ""));
+ } else if (strcasecmp(vmconf.slots[slot]->emul, "ahci-cd") == 0) {
+ asprintf(&vmconf.slots[slot]->config, "%s%s%s%s",
+ vmconf.slots[slot]->disk.path,
+ (vmconf.slots[slot]->disk.nocache ? ",nocache" : ""),
+ (vmconf.slots[slot]->disk.sync ? ",sync" : ""),
+ ",ro");
+ } else if (strcasecmp(vmconf.slots[slot]->emul, "virtio-net") == 0) {
+ asprintf(&vmconf.slots[slot]->config, "%s%s%s",
+ vmconf.slots[slot]->iface.name,
+ (vmconf.slots[slot]->iface.mac != NULL ? ",mac=" : ""),
+ (vmconf.slots[slot]->iface.mac != NULL ? vmconf.slots[slot]->iface.mac : ""));
+ }
+ pci_err = pci_create_slot(vmconf.slots[slot]->bnum,
+ vmconf.slots[slot]->snum,
+ vmconf.slots[slot]->fnum,
+ vmconf.slots[slot]->emul,
+ vmconf.slots[slot]->config);
+ if (pci_err != 0)
+ errx(1, "Failed to parse PCI configuration");
+ }
+ }
+
+ if (!vmconf.vmname && argc > 1)
+ vmconf.vmname = argv[1];
+
+ if (!vmconf.vmname)
usage(1);
- vmname = argv[0];
- ctx = do_open(vmname);
+ vmconf.vmname = argv[0];
+ ctx = do_open(vmconf.vmname);
- if (guest_ncpus < 1) {
- fprintf(stderr, "Invalid guest vCPUs (%d)\n", guest_ncpus);
+ if (vmconf.vcpus < 1) {
+ fprintf(stderr, "Invalid guest vCPUs (%d)\n", vmconf.vcpus);
exit(1);
}
max_vcpus = num_vcpus_allowed(ctx);
- if (guest_ncpus > max_vcpus) {
+ if (vmconf.vcpus > max_vcpus) {
fprintf(stderr, "%d vCPUs requested but only %d available\n",
- guest_ncpus, max_vcpus);
+ vmconf.vcpus, max_vcpus);
exit(1);
}
fbsdrun_set_capabilities(ctx, BSP);
vm_set_memflags(ctx, memflags);
- err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
+
+ err = vm_setup_memory(ctx, vmconf.memsize, VM_MMAP_ALL);
if (err) {
fprintf(stderr, "Unable to setup memory (%d)\n", errno);
exit(1);
@@ -934,7 +1015,7 @@
pci_irq_init(ctx);
ioapic_init(ctx);
- rtc_init(ctx, rtc_localtime);
+ rtc_init(ctx, vmconf.rtc_localtime);
sci_init(ctx);
/*
@@ -943,8 +1024,8 @@
if (init_pci(ctx) != 0)
exit(1);
- if (gdb_port != 0)
- init_dbgport(gdb_port);
+ if (vmconf.gdb_port != 0)
+ init_dbgport(vmconf.gdb_port);
if (bvmcons)
init_bvmcons();
@@ -965,8 +1046,8 @@
/*
* build the guest tables, MP etc.
*/
- if (mptgen) {
- error = mptable_build(ctx, guest_ncpus);
+ if (vmconf.mptgen) {
+ error = mptable_build(ctx, vmconf.vcpus);
if (error)
exit(1);
}
@@ -974,8 +1055,8 @@
error = smbios_build(ctx);
assert(error == 0);
- if (acpi) {
- error = acpi_build(ctx, guest_ncpus);
+ if (vmconf.acpi) {
+ error = acpi_build(ctx, vmconf.vcpus);
assert(error == 0);
}
@@ -995,8 +1076,8 @@
/*
* Change the proc title to include the VM name.
*/
- setproctitle("%s", vmname);
-
+ setproctitle("%s", vmconf.vmname);
+
/*
* Add CPU 0
*/
Index: usr.sbin/bhyve/config.h
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/config.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2015 Marcelo Araujo <araujo@FreeBSD.org>
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * 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 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 <stdbool.h>
+
+#include <ucl.h>
+
+#define NDISKS 32
+#define MB (1024UL * 1024)
+#define GB (1024UL * MB)
+
+struct config_iface_entry {
+ char *name;
+ char *mac;
+};
+
+struct config_disk_entry {
+ char *path;
+ bool boot;
+ bool nocache;
+ bool sync;
+ bool ro;
+};
+
+struct config_slot_entry {
+ int bnum;
+ int snum;
+ int fnum;
+ char *emul;
+ char *config;
+ union {
+ struct config_iface_entry iface;
+ struct config_disk_entry disk;
+ };
+};
+
+struct config_entry {
+ char *vmname;
+ int vcpus;
+ size_t memsize;
+ char *console;
+ char *host_base;
+ char *pincpu;
+ char *lpc_device;
+ char *uuid;
+ char **env;
+ size_t env_count;
+ struct config_slot_entry *slots[255];
+ size_t slot_count;
+ int gdb_port;
+ bool acpi;
+ bool dump_memory;
+ bool vmexit_on_hlt;
+ bool vmexit_on_pause;
+ bool strictio;
+ bool rtc_localtime;
+ bool strictmsr;
+ bool virtio_msix;
+ bool x2apic_mode;
+ bool mptgen;
+};
+
+extern struct config_slot_entry sinit;
+extern struct config_entry cinit;
+
+int check_config(struct config_entry *config);
+void load_config(char *in_name, char *conf_name, struct config_entry *c);
+void parse_conf(char *conf_name, struct config_entry *c, struct ucl_parser *p);
+bool parse_pci_slot(const char *str, int *bnum, int *snum, int *fnum);
+char* parse_string_safe(const ucl_object_t *obj, char *path);
Index: usr.sbin/bhyve/config.c
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/config.c
@@ -0,0 +1,415 @@
+/*-
+ * Copyright (c) 2015 Marcelo Araujo <araujo@FreeBSD.org>
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * 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 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>
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+
+/*
+ * Load the config file.
+ */
+void
+load_config(char *in_name, char *conf_name, struct config_entry *c)
+{
+ struct ucl_parser *p = NULL;
+
+ p = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE |
+ UCL_PARSER_NO_IMPLICIT_ARRAYS);
+ if (p == NULL)
+ errx(1, "Could not allocate ucl parser");
+
+ if (!ucl_parser_add_file(p, "/etc/defaults/bhyve.conf")) {
+ if (errno != ENOENT)
+ errx(EXIT_FAILURE, "Parse error in file %s: %s",
+ in_name, ucl_parser_get_error(p));
+ ucl_parser_free(p);
+ }
+
+ if (in_name != NULL) {
+ if (!ucl_parser_add_file_priority(p, in_name, 5)) {
+ if (errno != ENOENT)
+ errx(EXIT_FAILURE, "Parse error in file %s: %s",
+ in_name, ucl_parser_get_error(p));
+ ucl_parser_free(p);
+ }
+ }
+
+ /*
+ * Load from the root of the config file. If a specific file was
+ * requested, this will load the config from that file. If no filename
+ * was provided, this will load the defaults
+ */
+ parse_conf(NULL, c, p);
+
+ /* If no filename was provided, look for a key matching the vmname */
+ if (in_name == NULL)
+ parse_conf(conf_name, c, p);
+
+ check_config(c);
+
+ if (p != NULL)
+ ucl_parser_free(p);
+}
+
+/*
+ * Check if the basic variables are setting in
+ * the config file.
+ */
+int
+check_config(struct config_entry *config)
+{
+ if (!config->vmname)
+ errx(EX_USAGE, "name not defined");
+ else if (!config->memsize)
+ errx(EX_USAGE, "memory not defined");
+ else if (!config->vcpus)
+ errx(EX_USAGE, "vcpus not defined");
+ else if (!config->console)
+ errx(EX_USAGE, "console not defined");
+
+ return (0);
+}
+
+/*
+ * Parse the config file.
+ */
+void
+parse_conf(char *conf_name, struct config_entry *c, struct ucl_parser *p)
+{
+ const char *config = conf_name;
+ ucl_object_t *root = NULL;
+ const ucl_object_t *obj = NULL;
+ const ucl_object_t *cur, *acur;
+ ucl_object_iter_t it = NULL, ait = NULL;
+ const char *key;
+ char *tmp;
+ int i;
+
+ root = ucl_parser_get_object(p);
+ if (root == NULL || ucl_object_type(root) != UCL_OBJECT)
+ errx(EXIT_FAILURE, "Invalid configuration format.\n");
+
+ if (conf_name != NULL)
+ obj = ucl_lookup_path(root, config);
+ else
+ obj = root;
+
+ if (obj == NULL)
+ errx(EXIT_FAILURE, "Could not find configuration for VM: %s", conf_name);
+
+ it = ucl_object_iterate_new(obj);
+ while ((cur = ucl_object_iterate_safe(it, true)) != NULL) {
+ key = ucl_object_key(cur);
+ if (strcasecmp(key, "name") == 0)
+ c->vmname = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "cpus") == 0) {
+ if (!ucl_object_toint_safe(cur, (long *)&c->vcpus))
+ errx(EXIT_FAILURE, "Invalid number of CPUs specified");
+ } else if (strcasecmp(key, "memory") == 0) {
+ if (!ucl_object_toint_safe(cur, (size_t *)&c->memsize))
+ errx(EXIT_FAILURE, "Invalid amount of memory specified");
+ } else if (strcasecmp(key, "console") == 0)
+ c->console = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "host_base") == 0)
+ c->host_base = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "pincpu") == 0)
+ c->pincpu = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "lpc") == 0)
+ c->lpc_device = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "uuid") == 0)
+ c->uuid = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "env") == 0) {
+ switch (ucl_object_type(cur)) {
+ case UCL_OBJECT:
+ if (cur->len == 0)
+ break;
+ c->env_count = cur->len;
+ c->env = malloc(sizeof(char *) * c->env_count);
+ i = 0;
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, false)) != NULL) {
+ asprintf(&c->env[i], "%s=%s", ucl_object_key(acur), ucl_object_tostring_forced(acur));
+ i++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ default:
+ warnx("env must be an object containing key-value pairs");
+ break;
+ }
+ } else if (strcasecmp(key, "device") == 0) {
+ switch (ucl_object_type(cur)) {
+ /* XXX: TODO: Case where machine has more than 31 devices */
+ case UCL_OBJECT:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(cur, ".slot");
+ if (tmp)
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ else
+ c->slots[c->slot_count]->snum = c->slot_count;
+ c->slots[c->slot_count]->emul = parse_string_safe(cur, ".type");
+ c->slots[c->slot_count]->config = parse_string_safe(cur, ".config");
+ free(tmp);
+ c->slot_count++;
+ break;
+ case UCL_ARRAY:
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, true)) != NULL) {
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(acur, ".slot");
+ if (tmp)
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ else
+ c->slots[c->slot_count]->snum = c->slot_count;
+ c->slots[c->slot_count]->emul = parse_string_safe(acur, ".type");
+ c->slots[c->slot_count]->config = parse_string_safe(acur, ".config");
+ free(tmp);
+ c->slot_count++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ case UCL_STRING:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = parse_string_safe(cur, NULL);
+ c->slots[c->slot_count]->snum = c->slot_count;
+ c->slot_count++;
+ break;
+ default:
+ warnx("Error parsing disk contain");
+ }
+ } else if (strcasecmp(key, "network") == 0) {
+ switch (ucl_object_type(cur)) {
+ case UCL_OBJECT:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(cur, ".slot");
+ if (tmp)
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ else
+ c->slots[c->slot_count]->snum = c->slot_count;
+ tmp = parse_string_safe(cur, ".type");
+ if (tmp)
+ c->slots[c->slot_count]->emul = tmp;
+ else
+ c->slots[c->slot_count]->emul = strdup("virtio-net");
+ c->slots[c->slot_count]->iface.name = parse_string_safe(cur, ".name");
+ c->slots[c->slot_count]->iface.mac = parse_string_safe(cur, ".mac");
+ c->slot_count++;
+ break;
+ case UCL_ARRAY:
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, true)) != NULL) {
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(acur, ".slot");
+ if (tmp)
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ else
+ c->slots[c->slot_count]->snum = c->slot_count;
+ tmp = parse_string_safe(acur, ".type");
+ if (tmp)
+ c->slots[c->slot_count]->emul = tmp;
+ else
+ c->slots[c->slot_count]->emul = strdup("virtio-net");
+ c->slots[c->slot_count]->iface.name = parse_string_safe(acur, ".name");
+ c->slots[c->slot_count]->iface.mac = parse_string_safe(acur, ".mac");
+ c->slot_count++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ case UCL_STRING:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = strdup("virtio-net");
+ c->slots[c->slot_count]->iface.name = parse_string_safe(cur, NULL);
+ c->slots[c->slot_count]->snum = c->slot_count;
+ c->slot_count++;
+ break;
+ default:
+ warnx("Error parsing disk contain");
+ }
+ } else if (strcasecmp(key, "disk") == 0) {
+ switch (ucl_object_type(cur)) {
+ case UCL_OBJECT:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(cur, ".slot");
+ if (tmp)
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ else
+ c->slots[c->slot_count]->snum = c->slot_count;
+ tmp = parse_string_safe(cur, ".type");
+ if (tmp)
+ c->slots[c->slot_count]->emul = tmp;
+ else
+ c->slots[c->slot_count]->emul = strdup("virtio-blk");
+ c->slots[c->slot_count]->disk.path = parse_string_safe(cur, ".path");
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".boot"), &c->slots[c->slot_count]->disk.boot);
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".nocache"), &c->slots[c->slot_count]->disk.nocache);
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".sync"), &c->slots[c->slot_count]->disk.sync);
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".readonly"), &c->slots[c->slot_count]->disk.ro);
+ c->slot_count++;
+ break;
+ case UCL_ARRAY:
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, true)) != NULL) {
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(acur, ".slot");
+ if (tmp)
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ else
+ c->slots[c->slot_count]->snum = c->slot_count;
+ tmp = parse_string_safe(acur, ".type");
+ if (tmp)
+ c->slots[c->slot_count]->emul = tmp;
+ else
+ c->slots[c->slot_count]->emul = strdup("virtio-blk");
+ c->slots[c->slot_count]->disk.path = parse_string_safe(acur, ".path");
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".boot"), &c->slots[c->slot_count]->disk.boot);
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".nocache"), &c->slots[c->slot_count]->disk.nocache);
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".sync"), &c->slots[c->slot_count]->disk.sync);
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".readonly"), &c->slots[c->slot_count]->disk.ro);
+ c->slot_count++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ case UCL_STRING:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = strdup("virtio-blk");
+ c->slots[c->slot_count]->disk.path = parse_string_safe(cur, NULL);
+ c->slots[c->slot_count]->snum = c->slot_count;
+ c->slot_count++;
+ break;
+ default:
+ warnx("Error parsing disk contain");
+ }
+ } else if (strcasecmp(key, "gdbport") == 0) {
+ if (!ucl_object_toint_safe(cur, (long *)&c->gdb_port))
+ warnx("Invalid GDB port specified");
+ } else if (strcasecmp(key, "acpi") == 0)
+ ucl_object_toboolean_safe(cur, &c->acpi);
+ else if (strcasecmp(key, "dump_memory") == 0)
+ ucl_object_toboolean_safe(cur, &c->dump_memory);
+ else if (strcasecmp(key, "vmexit_on_hlt") == 0)
+ ucl_object_toboolean_safe(cur, &c->vmexit_on_hlt);
+ else if (strcasecmp(key, "vmexit_on_pause") == 0)
+ ucl_object_toboolean_safe(cur, &c->vmexit_on_pause);
+ else if (strcasecmp(key, "strictio") == 0)
+ ucl_object_toboolean_safe(cur, &c->strictio);
+ else if (strcasecmp(key, "rtc_localtime") == 0)
+ ucl_object_toboolean_safe(cur, &c->rtc_localtime);
+ else if (strcasecmp(key, "strictmsr") == 0)
+ ucl_object_toboolean_safe(cur, &c->strictmsr);
+ else if (strcasecmp(key, "virtio_msix") == 0)
+ ucl_object_toboolean_safe(cur, &c->virtio_msix);
+ else if (strcasecmp(key, "x2apic_mode") == 0)
+ ucl_object_toboolean_safe(cur, &c->x2apic_mode);
+ else if (strcasecmp(key, "mptgen") == 0)
+ ucl_object_toboolean_safe(cur, &c->mptgen);
+ }
+ ucl_object_iterate_free(it);
+
+ if (root != NULL)
+ ucl_object_unref(root);
+
+}
+
+char *
+parse_string_safe(const ucl_object_t *obj, char *path)
+{
+ const ucl_object_t *target = NULL;
+ char *str = NULL;
+
+ if (path != NULL)
+ target = ucl_lookup_path(obj, path);
+ else
+ target = obj;
+
+ if (target == NULL)
+ return NULL;
+
+ str = (char *)ucl_object_tostring(target);
+ if (str != NULL)
+ return strdup(str);
+
+ return (str);
+}
+
+bool
+parse_pci_slot(const char *str, int *bnum, int *snum, int *fnum)
+{
+ if (str == NULL)
+ return (false);
+ /* <bus>:<slot>:<func> */
+ if (sscanf(str, "%d:%d:%d", bnum, snum, fnum) != 3) {
+ *bnum = 0;
+ /* <slot>:<func> */
+ if (sscanf(str, "%d:%d", snum, fnum) != 2) {
+ *fnum = 0;
+ /* <slot> */
+ if (sscanf(str, "%d", snum) != 1) {
+ *snum = -1;
+ return (false);
+ }
+ }
+ }
+ return (true);
+}
Index: usr.sbin/bhyve/fwctl.c
===================================================================
--- usr.sbin/bhyve/fwctl.c
+++ usr.sbin/bhyve/fwctl.c
@@ -43,6 +43,7 @@
#include <stdlib.h>
#include <string.h>
+#include "config.h"
#include "bhyverun.h"
#include "inout.h"
#include "fwctl.h"
@@ -158,7 +159,7 @@
/* OID search */
SET_DECLARE(ctl_set, struct ctl);
-CTL_NODE("hw.ncpu", &guest_ncpus, sizeof(guest_ncpus));
+CTL_NODE("hw.ncpu", &vmconf.vcpus, sizeof(vmconf.vcpus));
static struct ctl *
ctl_locate(const char *str, int maxlen)
Index: usr.sbin/bhyve/pci_e82545.c
===================================================================
--- usr.sbin/bhyve/pci_e82545.c
+++ usr.sbin/bhyve/pci_e82545.c
@@ -57,6 +57,7 @@
#include "e1000_defines.h"
#include "mii.h"
+#include "config.h"
#include "bhyverun.h"
#include "pci_emul.h"
#include "mevent.h"
@@ -2356,7 +2357,7 @@
*/
if (!mac_provided) {
snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
- pi->pi_func, vmname);
+ pi->pi_func, vmconf.vmname);
MD5Init(&mdctx);
MD5Update(&mdctx, nstr, strlen(nstr));
Index: usr.sbin/bhyve/pci_emul.h
===================================================================
--- usr.sbin/bhyve/pci_emul.h
+++ usr.sbin/bhyve/pci_emul.h
@@ -232,6 +232,7 @@
int pci_msix_pba_bar(struct pci_devinst *pi);
int pci_msi_maxmsgnum(struct pci_devinst *pi);
int pci_parse_slot(char *opt);
+int pci_create_slot(int bnum, int snum, int fnum, char *emul, char *config);
void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr);
int pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum);
int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
Index: usr.sbin/bhyve/pci_emul.c
===================================================================
--- usr.sbin/bhyve/pci_emul.c
+++ usr.sbin/bhyve/pci_emul.c
@@ -166,8 +166,6 @@
int
pci_parse_slot(char *opt)
{
- struct businfo *bi;
- struct slotinfo *si;
char *emul, *config, *str, *cp;
int error, bnum, snum, fnum;
@@ -200,6 +198,26 @@
}
}
+ error = pci_create_slot(bnum, snum, fnum, emul, config);
+
+done:
+ if (error)
+ free(str);
+
+ return (error);
+}
+
+int
+pci_create_slot(int bnum, int snum, int fnum, char *emul, char *config)
+{
+ struct businfo *bi;
+ struct slotinfo *si;
+ char *opt;
+ int error;
+
+ error = -1;
+ asprintf(&opt, "%d:%d:%d,%s,%s", bnum, snum, fnum, emul, config);
+
if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS ||
fnum < 0 || fnum >= MAXFUNCS) {
pci_parse_slot_usage(opt);
@@ -229,8 +247,7 @@
si->si_funcs[fnum].fi_param = config;
done:
- if (error)
- free(str);
+ free(opt);
return (error);
}
Index: usr.sbin/bhyve/pci_virtio_net.c
===================================================================
--- usr.sbin/bhyve/pci_virtio_net.c
+++ usr.sbin/bhyve/pci_virtio_net.c
@@ -59,6 +59,7 @@
#include <pthread_np.h>
#include <sysexits.h>
+#include "config.h"
#include "bhyverun.h"
#include "pci_emul.h"
#include "mevent.h"
@@ -880,7 +881,7 @@
*/
if (!mac_provided) {
snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
- pi->pi_func, vmname);
+ pi->pi_func, vmconf.vmname);
MD5Init(&mdctx);
MD5Update(&mdctx, nstr, strlen(nstr));
Index: usr.sbin/bhyve/smbiostbl.c
===================================================================
--- usr.sbin/bhyve/smbiostbl.c
+++ usr.sbin/bhyve/smbiostbl.c
@@ -40,12 +40,10 @@
#include <machine/vmm.h>
#include <vmmapi.h>
+#include "config.h"
#include "bhyverun.h"
#include "smbiostbl.h"
-#define MB (1024*1024)
-#define GB (1024ULL*1024*1024)
-
#define SMBIOS_BASE 0xF1000
/* BHYVE_ACPI_BASE - SMBIOS_BASE) */
@@ -586,11 +584,11 @@
curaddr, endaddr, n, size);
type1 = (struct smbios_table_type1 *)curaddr;
- if (guest_uuid_str != NULL) {
+ if (vmconf.uuid != NULL) {
uuid_t uuid;
uint32_t status;
- uuid_from_string(guest_uuid_str, &uuid, &status);
+ uuid_from_string(vmconf.uuid, &uuid, &status);
if (status != uuid_s_ok)
return (-1);
@@ -609,7 +607,7 @@
return (-1);
MD5Init(&mdctx);
- MD5Update(&mdctx, vmname, strlen(vmname));
+ MD5Update(&mdctx, vmconf.vmname, strlen(vmconf.vmname));
MD5Update(&mdctx, hostname, sizeof(hostname));
MD5Final(digest, &mdctx);
@@ -634,7 +632,7 @@
{
int i;
- for (i = 0; i < guest_ncpus; i++) {
+ for (i = 0; i < vmconf.vcpus; i++) {
struct smbios_table_type4 *type4;
char *p;
int nstrings, len;
Index: usr.sbin/bhyve/spinup_ap.c
===================================================================
--- usr.sbin/bhyve/spinup_ap.c
+++ usr.sbin/bhyve/spinup_ap.c
@@ -39,6 +39,7 @@
#include <stdlib.h>
#include <assert.h>
+#include "config.h"
#include "bhyverun.h"
#include "spinup_ap.h"
@@ -80,7 +81,7 @@
int error;
assert(newcpu != 0);
- assert(newcpu < guest_ncpus);
+ assert(newcpu < vmconf.vcpus);
error = vcpu_reset(ctx, newcpu);
assert(error == 0);
Index: usr.sbin/bhyveload/Makefile
===================================================================
--- usr.sbin/bhyveload/Makefile
+++ usr.sbin/bhyveload/Makefile
@@ -1,14 +1,18 @@
# $FreeBSD$
PROG= bhyveload
-SRCS= bhyveload.c
MAN= bhyveload.8
PACKAGE= bhyve
-LIBADD= vmmapi
+SRCS= bhyveload.c \
+ ${.CURDIR}/../bhyve/config.c
+
+LIBADD= vmmapi ucl
WARNS?= 3
CFLAGS+=-I${.CURDIR}/../../sys/boot/userboot
+CFLAGS+=-I${.CURDIR}/../bhyve
+CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
.include <bsd.prog.mk>
Index: usr.sbin/bhyveload/bhyveload.8
===================================================================
--- usr.sbin/bhyveload/bhyveload.8
+++ usr.sbin/bhyveload/bhyveload.8
@@ -40,10 +40,13 @@
.Op Fl c Ar cons-dev
.Op Fl d Ar disk-path
.Op Fl e Ar name=value
+.Op Fl f Ar bhyve.conf
.Op Fl h Ar host-path
.Op Fl l Ar os-loader
.Op Fl m Ar memsize Ns Op Ar K|k|M|m|G|g|T|t
.Ar vmname
+.Nm
+.Fl f Ar bhyve.conf
.Sh DESCRIPTION
.Nm
is used to load a
@@ -90,6 +93,8 @@
.Pp
The option may be used more than once to set more than one environment
variable.
+.It Fl f Ar bhyve.conf
+Read configuration from specified file.
.It Fl h Ar host-path
The
.Ar host-path
@@ -150,6 +155,10 @@
.Pa /dev/nmdm1B
.Pp
.Dl "bhyveload -m 256MB -h /usr/images/test -c /dev/nmdm1B test-vm"
+.Pp
+To create a virtual machine described in a configuration file:
+.Pp
+.Dl "bhyveload -f guest.conf"
.Sh SEE ALSO
.Xr bhyve 4 ,
.Xr nmdm 4 ,
Index: usr.sbin/bhyveload/bhyveload.c
===================================================================
--- usr.sbin/bhyveload/bhyveload.c
+++ usr.sbin/bhyveload/bhyveload.c
@@ -82,21 +82,54 @@
#include <vmmapi.h>
+#include <config.h>
+
#include "userboot.h"
-#define MB (1024 * 1024UL)
-#define GB (1024 * 1024 * 1024UL)
#define BSP 0
-#define NDISKS 32
+struct config_slot_entry sinit = {
+ .bnum = 0,
+ .snum = 0,
+ .fnum = 0,
+ .emul = NULL,
+ .config = NULL
+};
+
+struct config_entry cinit = {
+ .vmname = NULL,
+ .vcpus = 1,
+ .memsize = 256 * MB,
+ .console = NULL,
+ .host_base = NULL,
+ .pincpu = NULL,
+ .lpc_device = NULL,
+ .uuid = NULL,
+ .env = NULL,
+ .env_count = 0,
+ .slots = {NULL},
+ .slot_count = 0,
+ .gdb_port = 0,
+ .acpi = 0,
+ .dump_memory = 0,
+ .vmexit_on_hlt = 0,
+ .vmexit_on_pause = 0,
+ .strictio = 0,
+ .rtc_localtime = 1,
+ .strictmsr = 1,
+ .virtio_msix = 1,
+ .x2apic_mode = 0,
+ .mptgen = 1
+};
+
+struct config_entry vmconf;
-static char *host_base;
static struct termios term, oldterm;
static int disk_fd[NDISKS];
static int ndisks;
static int consin_fd, consout_fd;
-static char *vmname, *progname;
+static char *progname;
static struct vmctx *ctx;
static uint64_t gdtbase, cr3, rsp;
@@ -155,10 +188,10 @@
struct cb_file *cf;
char path[PATH_MAX];
- if (!host_base)
+ if (!vmconf.host_base)
return (ENOENT);
- strlcpy(path, host_base, PATH_MAX);
+ strlcpy(path, vmconf.host_base, PATH_MAX);
if (path[strlen(path) - 1] == '/')
path[strlen(path) - 1] = 0;
strlcat(path, filename, PATH_MAX);
@@ -648,7 +681,7 @@
fprintf(stderr,
"usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n"
- " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n",
+ " %*s [-f <config-file> [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n",
progname,
(int)strlen(progname), "");
exit(1);
@@ -662,6 +695,10 @@
void (*func)(struct loader_callbacks *, void *, int, int);
uint64_t mem_size;
int opt, error, need_reinit, memflags;
+ size_t slot;
+ char *temp, *bootpath;
+ const ucl_object_t *target;
+ bool new_config;
progname = basename(argv[0]);
@@ -672,29 +709,33 @@
consin_fd = STDIN_FILENO;
consout_fd = STDOUT_FILENO;
+ temp = NULL;
+ bootpath = NULL;
+ target = NULL;
+ new_config = false;
- while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) {
+ while ((opt = getopt(argc, argv, "CSc:d:e:f:h:l:m:")) != -1) {
switch (opt) {
case 'c':
error = altcons_open(optarg);
if (error != 0)
errx(EX_USAGE, "Could not open '%s'", optarg);
break;
-
case 'd':
error = disk_open(optarg);
if (error != 0)
errx(EX_USAGE, "Could not open '%s'", optarg);
break;
-
case 'e':
addenv(optarg);
break;
-
+ case 'f':
+ new_config = true;
+ load_config(optarg, NULL, &vmconf);
+ break;
case 'h':
- host_base = optarg;
+ vmconf.host_base = optarg;
break;
-
case 'l':
if (loader != NULL)
errx(EX_USAGE, "-l can only be given once");
@@ -704,7 +745,7 @@
break;
case 'm':
- error = vm_parse_memsize(optarg, &mem_size);
+ error = vm_parse_memsize(optarg, &vmconf.memsize);
if (error != 0)
errx(EX_USAGE, "Invalid memsize '%s'", optarg);
break;
@@ -722,13 +763,62 @@
argc -= optind;
argv += optind;
- if (argc != 1)
- usage();
+ if (new_config) {
+ error = altcons_open(vmconf.console);
+ if (error != 0)
+ errx(EX_USAGE, "Could not open console: %s",
+ vmconf.console);
+
+ /* Find the boot disk */
+ for (slot = 0; slot < vmconf.slot_count; slot++) {
+ if (strcasecmp(vmconf.slots[slot]->emul, "virtio-blk") == 0 ||
+ strcasecmp(vmconf.slots[slot]->emul, "ahci-hd") == 0 ||
+ strcasecmp(vmconf.slots[slot]->emul, "ahci-cd") == 0) {
+ if (vmconf.slots[slot]->disk.boot == true) {
+ bootpath = vmconf.slots[slot]->disk.path;
+ break;
+ }
+ }
+ }
+ if (bootpath != NULL) {
+ error = disk_open(bootpath);
+ if (error != 0)
+ errx(EX_USAGE, "Could not open boot disk: %s", bootpath);
+ }
+ /* Open every other disk (required for RAID etc) */
+ for (slot = 0; slot < vmconf.slot_count; slot++) {
+ if (strcasecmp(vmconf.slots[slot]->emul, "virtio-blk") == 0 ||
+ strcasecmp(vmconf.slots[slot]->emul, "ahci-hd") == 0 ||
+ strcasecmp(vmconf.slots[slot]->emul, "ahci-cd") == 0) {
+ /* Open open the first NDISKS disks */
+ if (ndisks > NDISKS)
+ break;
+ error = disk_open(vmconf.slots[slot]->disk.path);
+ if (error != 0)
+ errx(EX_USAGE, "Could not open disk: %s", vmconf.slots[slot]->disk.path);
+ }
+ }
+
+ /* build the environment */
+ for (slot = 0; slot < vmconf.env_count; slot++) {
+ addenv(vmconf.env[slot]);
+ }
+
+ asprintf(&temp, "%zu", vmconf.memsize);
+ error = vm_parse_memsize(temp, &vmconf.memsize);
+ if (error)
+ errx(EX_USAGE, "invalid memsize '%s'", optarg);
+ free(temp);
+ }
- vmname = argv[0];
+ if (!vmconf.vmname && argc > 1)
+ vmconf.vmname = argv[1];
+
+ if (!vmconf.vmname)
+ usage();
need_reinit = 0;
- error = vm_create(vmname);
+ error = vm_create(vmconf.vmname);
if (error) {
if (errno != EEXIST) {
perror("vm_create");
@@ -737,7 +827,7 @@
need_reinit = 1;
}
- ctx = vm_open(vmname);
+ ctx = vm_open(vmconf.vmname);
if (ctx == NULL) {
perror("vm_open");
exit(1);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Feb 3, 3:50 AM (10 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28420839
Default Alt Text
D2448.diff (41 KB)
Attached To
Mode
D2448: give bhyve the ability to parse a libucl guest configuration file
Attached
Detach File
Event Timeline
Log In to Comment