summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2017-03-25 16:28:26 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2017-03-25 16:28:26 +0000
commit0794fafa650ee57195391a1438b9ba412c220412 (patch)
treeee6417921af6ed135f0b0b30b9220aa9eff841a6 /usr.sbin
parent7fd154d0570bf797098441e117e6bf1aab4af5cc (diff)
Boot using BIOS from /etc/firmware/vmm-bios by default.
Instead of using the internal "vmboot", VMs will now be booted using the external BIOS firmware in /etc/firmware/vmm-bios (which is subject to a LGPLv3 license). Direct booting of OpenBSD kernels or non-default BIOS images is still supported for now using the -b/boot option that is replacing the -k/kernel option. As requested by Theo, vmd(8) fails if neither the default BIOS is found nor a kernel has been specified in the VM configuration. The "vmm" BIOS has to be installed using fw_update(1), which will be done automatically in most cases where the OpenBSD can fetch it after install/upgrade. OK mlarkin@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/vmctl/main.c18
-rw-r--r--usr.sbin/vmctl/vmctl.814
-rw-r--r--usr.sbin/vmd/config.c17
-rw-r--r--usr.sbin/vmd/loadfile.h6
-rw-r--r--usr.sbin/vmd/loadfile_elf.c16
-rw-r--r--usr.sbin/vmd/vm.c97
-rw-r--r--usr.sbin/vmd/vm.conf.519
-rw-r--r--usr.sbin/vmd/vmd.812
-rw-r--r--usr.sbin/vmd/vmd.h3
9 files changed, 151 insertions, 51 deletions
diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c
index bf611d6c9c5..c50cdaceec0 100644
--- a/usr.sbin/vmctl/main.c
+++ b/usr.sbin/vmctl/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.23 2017/03/01 21:22:57 reyk Exp $ */
+/* $OpenBSD: main.c,v 1.24 2017/03/25 16:28:25 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -65,7 +65,7 @@ struct ctl_command ctl_commands[] = {
{ "reload", CMD_RELOAD, ctl_reload, "" },
{ "reset", CMD_RESET, ctl_reset, "[all|vms|switches]" },
{ "start", CMD_START, ctl_start, "\"name\""
- " [-c] [-k kernel] [-m size]\n"
+ " [-c] [-b image] [-m size]\n"
"\t\t[-n switch] [-i count] [-d disk]*" },
{ "status", CMD_STATUS, ctl_status, "[id]" },
{ "stop", CMD_STOP, ctl_stop, "id" },
@@ -538,19 +538,19 @@ ctl_start(struct parse_result *res, int argc, char *argv[])
argc--;
argv++;
- while ((ch = getopt(argc, argv, "ck:m:n:d:i:")) != -1) {
+ while ((ch = getopt(argc, argv, "b:cm:n:d:i:")) != -1) {
switch (ch) {
- case 'c':
- tty_autoconnect = 1;
- break;
- case 'k':
+ case 'b':
if (res->path)
- errx(1, "kernel specified multiple times");
+ errx(1, "boot image specified multiple times");
if (realpath(optarg, path) == NULL)
- err(1, "invalid kernel path");
+ err(1, "invalid boot image path");
if ((res->path = strdup(path)) == NULL)
errx(1, "strdup");
break;
+ case 'c':
+ tty_autoconnect = 1;
+ break;
case 'm':
if (res->size)
errx(1, "memory specified multiple times");
diff --git a/usr.sbin/vmctl/vmctl.8 b/usr.sbin/vmctl/vmctl.8
index 7ff74d66602..dc1d99511e4 100644
--- a/usr.sbin/vmctl/vmctl.8
+++ b/usr.sbin/vmctl/vmctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: vmctl.8,v 1.26 2017/01/24 11:29:30 jmc Exp $
+.\" $OpenBSD: vmctl.8,v 1.27 2017/03/25 16:28:25 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: January 24 2017 $
+.Dd $Mdocdate: March 25 2017 $
.Dt VMCTL 8
.Os
.Sh NAME
@@ -72,23 +72,25 @@ Reset the configured switches.
.It Cm reset vms
Reset and terminate all VMs.
.It Xo Cm start Ar name
+.Op Fl b Ar path
.Op Fl c
.Op Fl d Ar path
.Op Fl i Ar count
-.Op Fl k Ar path
.Op Fl m Ar size
.Op Fl n Ar switch
.Xc
Starts a VM defined by the specified name and parameters:
.Bl -tag -width "-i count"
+.It Fl b Ar path
+Boot the VM with the specified kernel or BIOS image.
+If not specified, the default is to boot using the BIOS image in
+.Pa /etc/firmware/vmm-bios .
.It Fl c
Automatically connect to the VM console.
.It Fl d Ar path
Disk image file (may be specified multiple times to add multiple disk images).
.It Fl i Ar count
Number of network interfaces to add to the VM.
-.It Fl k Ar path
-Boot the VM with a kernel loaded from the host, not the first disk image.
.It Fl m Ar size
Memory
.Ar size
@@ -161,7 +163,7 @@ $ vmctl create disk.img -s 4.5G
Create a new VM with 1GB memory, one network interface, one disk image
('disk.img') and boot from kernel '/bsd':
.Bd -literal -offset indent
-# vmctl start "myvm" -m 1G -i 1 -d disk.img -k /bsd
+# vmctl start "myvm" -m 1G -i 1 -d disk.img
.Ed
.Pp
.Xr vmd 8
diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c
index b0abf53b773..f0c94744b85 100644
--- a/usr.sbin/vmd/config.c
+++ b/usr.sbin/vmd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.26 2017/03/02 07:33:37 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.27 2017/03/25 16:28:25 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -163,8 +163,19 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid)
/* Open external kernel for child */
if (strlen(vcp->vcp_kernel) &&
(kernfd = open(vcp->vcp_kernel, O_RDONLY)) == -1) {
- log_warn("%s: can't open kernel %s", __func__,
- vcp->vcp_kernel);
+ log_warn("%s: can't open kernel/BIOS boot image %s",
+ __func__, vcp->vcp_kernel);
+ goto fail;
+ }
+
+ /*
+ * Try to open the default BIOS image if no kernel/BIOS has
+ * been specified. The BIOS is an external firmware file that is
+ * typically distributed separately due to an incompatible license.
+ */
+ if (kernfd == -1 &&
+ (kernfd = open(VM_DEFAULT_BIOS, O_RDONLY)) == -1) {
+ log_warn("%s: can't open %s", __func__, VM_DEFAULT_BIOS);
goto fail;
}
diff --git a/usr.sbin/vmd/loadfile.h b/usr.sbin/vmd/loadfile.h
index 7bd1e97c8b3..cc384262250 100644
--- a/usr.sbin/vmd/loadfile.h
+++ b/usr.sbin/vmd/loadfile.h
@@ -1,5 +1,5 @@
/* $NetBSD: loadfile.h,v 1.1 1999/04/28 09:08:50 christos Exp $ */
-/* $OpenBSD: loadfile.h,v 1.7 2016/11/26 20:03:42 reyk Exp $ */
+/* $OpenBSD: loadfile.h,v 1.8 2017/03/25 16:28:25 reyk Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -73,7 +73,9 @@
#define PML2_PAGE 0x13000
#define NPTE_PG (PAGE_SIZE / sizeof(pt_entry_t))
-int loadelf_main(FILE *, struct vm_create_params *,
+int loadfile_elf(FILE *, struct vm_create_params *,
struct vcpu_reg_state *, uint32_t, uint32_t);
+size_t mread(FILE *, paddr_t, size_t);
+
#include <machine/loadfile_machdep.h>
diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c
index 2f7e0462668..fe9185cd3c2 100644
--- a/usr.sbin/vmd/loadfile_elf.c
+++ b/usr.sbin/vmd/loadfile_elf.c
@@ -1,5 +1,5 @@
/* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
-/* $OpenBSD: loadfile_elf.c,v 1.24 2017/02/04 07:23:25 mlarkin Exp $ */
+/* $OpenBSD: loadfile_elf.c,v 1.25 2017/03/25 16:28:25 reyk Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -125,7 +125,6 @@ static uint32_t push_bootargs(bios_memmap_t *, size_t);
static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
static void push_gdt(void);
static void push_pt(void);
-static size_t mread(FILE *, paddr_t, size_t);
static void marc4random_buf(paddr_t, int);
static void mbzero(paddr_t, int);
static void mbcopy(void *, paddr_t, int);
@@ -257,13 +256,13 @@ push_pt(void)
}
/*
- * loadelf_main
+ * loadfile_elf
*
* Loads an ELF kernel to it's defined load address in the guest VM.
* The kernel is loaded to its defined start point as set in the ELF header.
*
* Parameters:
- * fd: file descriptor of a kernel file to load
+ * fp: file of a kernel file to load
* vcp: the VM create parameters, holding the exact memory map
* (out) vrs: register state to set on init for this kernel
* bootdev: the optional non-default boot device
@@ -274,7 +273,7 @@ push_pt(void)
* various error codes returned from read(2) or loadelf functions
*/
int
-loadelf_main(FILE *fp, struct vm_create_params *vcp,
+loadfile_elf(FILE *fp, struct vm_create_params *vcp,
struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto)
{
int r;
@@ -293,7 +292,8 @@ loadelf_main(FILE *fp, struct vm_create_params *vcp,
} else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
- }
+ } else
+ errno = ENOEXEC;
if (r)
return (r);
@@ -313,6 +313,8 @@ loadelf_main(FILE *fp, struct vm_create_params *vcp,
#endif
vrs->vrs_gdtr.vsi_base = GDT_PAGE;
+ log_debug("%s: loaded ELF kernel", __func__);
+
return (0);
}
@@ -484,7 +486,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t bootdev, uint32_t howto)
* Return values:
* returns 'sz' if successful, or 0 otherwise.
*/
-static size_t
+size_t
mread(FILE *fp, paddr_t addr, size_t sz)
{
size_t ct;
diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c
index c28e50c4d52..37b62959fd2 100644
--- a/usr.sbin/vmd/vm.c
+++ b/usr.sbin/vmd/vm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm.c,v 1.8 2017/03/25 15:47:37 mlarkin Exp $ */
+/* $OpenBSD: vm.c,v 1.9 2017/03/25 16:28:25 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -76,6 +76,7 @@ void init_emulated_hw(struct vmop_create_params *, int *, int *);
void vcpu_exit_inout(struct vm_run_params *);
uint8_t vcpu_exit_pci(struct vm_run_params *);
int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
+int loadfile_bios(FILE *, struct vcpu_reg_state *);
static struct vm_mem_range *find_gpa_range(struct vm_create_params *, paddr_t,
size_t);
@@ -135,6 +136,76 @@ static const struct vcpu_reg_state vcpu_init_flat32 = {
};
/*
+ * Represents a standard register set for an BIOS to be booted
+ * as a flat 16 bit address space.
+ */
+static const struct vcpu_reg_state vcpu_init_flat16 = {
+#ifdef __i386__
+ .vrs_gprs[VCPU_REGS_EFLAGS] = 0x2,
+ .vrs_gprs[VCPU_REGS_EIP] = 0xFFF0,
+ .vrs_gprs[VCPU_REGS_ESP] = 0x0,
+#else
+ .vrs_gprs[VCPU_REGS_RFLAGS] = 0x2,
+ .vrs_gprs[VCPU_REGS_RIP] = 0xFFF0,
+ .vrs_gprs[VCPU_REGS_RSP] = 0x0,
+#endif
+ .vrs_crs[VCPU_REGS_CR0] = 0x60000010,
+ .vrs_crs[VCPU_REGS_CR3] = 0,
+ .vrs_sregs[VCPU_REGS_CS] = { 0xF000, 0xFFFF, 0x809F, 0xF0000},
+ .vrs_sregs[VCPU_REGS_DS] = { 0x0, 0xFFFF, 0x8093, 0x0},
+ .vrs_sregs[VCPU_REGS_ES] = { 0x0, 0xFFFF, 0x8093, 0x0},
+ .vrs_sregs[VCPU_REGS_FS] = { 0x0, 0xFFFF, 0x8093, 0x0},
+ .vrs_sregs[VCPU_REGS_GS] = { 0x0, 0xFFFF, 0x8093, 0x0},
+ .vrs_sregs[VCPU_REGS_SS] = { 0x0, 0xFFFF, 0x8093, 0x0},
+ .vrs_gdtr = { 0x0, 0xFFFF, 0x0, 0x0},
+ .vrs_idtr = { 0x0, 0xFFFF, 0x0, 0x0},
+ .vrs_sregs[VCPU_REGS_LDTR] = { 0x0, 0xFFFF, 0x0082, 0x0},
+ .vrs_sregs[VCPU_REGS_TR] = { 0x0, 0xFFFF, 0x008B, 0x0},
+};
+
+/*
+ * loadfile_bios
+ *
+ * Alternatively to loadfile_elf, this function loads a non-ELF BIOS image
+ * directly into memory.
+ *
+ * Parameters:
+ * fp: file of a kernel file to load
+ * (out) vrs: register state to set on init for this kernel
+ *
+ * Return values:
+ * 0 if successful
+ * various error codes returned from read(2) or loadelf functions
+ */
+int
+loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
+{
+ off_t size, off;
+
+ /* Set up a "flat 16 bit" register state for BIOS */
+ memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
+
+ /* Get the size of the BIOS image and seek to the beginning */
+ if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
+ fseeko(fp, 0, SEEK_SET) == -1)
+ return (-1);
+
+ /* The BIOS image must end at 1M */
+ if ((off = 1048576 - size) < 0)
+ return (-1);
+
+ /* Read BIOS image into memory */
+ if (mread(fp, off, size) != (size_t)size) {
+ errno = EIO;
+ return (-1);
+ }
+
+ log_debug("%s: loaded BIOS image", __func__);
+
+ return (0);
+}
+
+/*
* start_vm
*
* After forking a new VM process, starts the new VM with the creation
@@ -163,7 +234,7 @@ start_vm(struct vmd_vm *vm, int fd)
struct vcpu_reg_state vrs;
int nicfds[VMM_MAX_NICS_PER_VM];
int ret;
- FILE *kernfp;
+ FILE *fp;
struct vmboot_params vmboot;
size_t i;
@@ -203,22 +274,28 @@ start_vm(struct vmd_vm *vm, int fd)
* Set up default "flat 32 bit" register state - RIP,
* RSP, and GDT info will be set in bootloader
*/
- memcpy(&vrs, &vcpu_init_flat32, sizeof(struct vcpu_reg_state));
+ memcpy(&vrs, &vcpu_init_flat32, sizeof(vrs));
/* Find and open kernel image */
- if ((kernfp = vmboot_open(vm->vm_kernel,
+ if ((fp = vmboot_open(vm->vm_kernel,
vm->vm_disks[0], &vmboot)) == NULL)
fatalx("failed to open kernel - exiting");
/* Load kernel image */
- ret = loadelf_main(kernfp, vcp, &vrs,
+ ret = loadfile_elf(fp, vcp, &vrs,
vmboot.vbp_bootdev, vmboot.vbp_howto);
- if (ret) {
- errno = ret;
- fatal("failed to load kernel - exiting");
- }
- vmboot_close(kernfp, &vmboot);
+ /*
+ * Try BIOS as a fallback (only if it was provided as an image
+ * with vm->vm_kernel and not loaded from the disk)
+ */
+ if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
+ ret = loadfile_bios(fp, &vrs);
+
+ if (ret)
+ fatal("failed to load kernel or BIOS - exiting");
+
+ vmboot_close(fp, &vmboot);
if (vm->vm_kernel != -1)
close(vm->vm_kernel);
diff --git a/usr.sbin/vmd/vm.conf.5 b/usr.sbin/vmd/vm.conf.5
index e58a4bd604a..6093c9d7cf4 100644
--- a/usr.sbin/vmd/vm.conf.5
+++ b/usr.sbin/vmd/vm.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: vm.conf.5,v 1.16 2017/03/02 07:33:37 reyk Exp $
+.\" $OpenBSD: vm.conf.5,v 1.17 2017/03/25 16:28:25 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\" Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: March 2 2017 $
+.Dd $Mdocdate: March 25 2017 $
.Dt VM.CONF 5
.Os
.Sh NAME
@@ -82,7 +82,7 @@ For example:
ramdisk="/bsd.rd"
vm "vm1.example.com" {
memory 512M
- kernel $ramdisk
+ boot $ramdisk
}
.Ed
.Sh VM CONFIGURATION
@@ -97,6 +97,10 @@ This name can be any string, and is typically a hostname.
.Pp
Followed by a block of parameters that is enclosed in curly brackets:
.Bl -tag -width Ds
+.It Cm boot Ar path
+Kernel or BIOS image to load when booting the VM.
+If not specified, the default is to boot using the BIOS image in
+.Pa /etc/firmware/vmm-bios .
.It Cm enable
Automatically start the VM.
This is the default if neither
@@ -161,8 +165,6 @@ If the
is greater than the number of
.Ic interface
statements, additional default interfaces will be added.
-.It Cm kernel Ar path
-Kernel to load when booting the VM.
.It Cm memory Ar bytes
Memory size of the VM, in bytes, rounded to megabytes.
The default is 512M.
@@ -265,15 +267,12 @@ Stop the switch from forwarding packets.
.Sh EXAMPLES
Create a new VM with 1GB memory, 1 network interface connected to
.Dq uplink ,
-one disk image
-.Sq disk.img
-and boot from kernel
-.Sq /bsd :
+and one disk image
+.Sq disk.img :
.Bd -literal -offset indent
vm "vm2.example.com" {
memory 1G
disk "/var/vmm/vm2-disk.img"
- kernel "/bsd"
interface { switch "uplink" }
}
.Ed
diff --git a/usr.sbin/vmd/vmd.8 b/usr.sbin/vmd/vmd.8
index 5210bd2fcbd..4bd5f1fba1c 100644
--- a/usr.sbin/vmd/vmd.8
+++ b/usr.sbin/vmd/vmd.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: vmd.8,v 1.6 2016/06/10 18:32:40 jmc Exp $
+.\" $OpenBSD: vmd.8,v 1.7 2017/03/25 16:28:25 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 10 2016 $
+.Dd $Mdocdate: March 25 2017 $
.Dt VMD 8
.Os
.Sh NAME
@@ -86,7 +86,13 @@ Multiple
options increase the verbosity.
.El
.Sh FILES
-.Bl -tag -width "/var/run/vmd.sockXX" -compact
+.Bl -tag -width "/etc/firmware/vmm-biosXX" -compact
+.It Pa /etc/firmware/vmm-bios
+Default BIOS boot image.
+The BIOS is an external firmware file that is distributed separately
+due to an incompatible license.
+A prepackaged version of the firmware can be installed using
+.Xr fw_update 1 .
.It Pa /etc/vm.conf
Default configuration file.
This is optional.
diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h
index 1c59fc484f3..762be489c9e 100644
--- a/usr.sbin/vmd/vmd.h
+++ b/usr.sbin/vmd/vmd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.h,v 1.48 2017/03/15 18:06:18 reyk Exp $ */
+/* $OpenBSD: vmd.h,v 1.49 2017/03/25 16:28:25 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -37,6 +37,7 @@
#define VMD_CONF "/etc/vm.conf"
#define SOCKET_NAME "/var/run/vmd.sock"
#define VMM_NODE "/dev/vmm"
+#define VM_DEFAULT_BIOS "/etc/firmware/vmm-bios"
#define VM_DEFAULT_KERNEL "/bsd"
#define VM_DEFAULT_DEVICE "hd0a"
#define VM_BOOT_CONF "/etc/boot.conf"