Page MenuHomeFreeBSD

D2448.diff
No OneTemporary

D2448.diff

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

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)

Event Timeline