diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2017-03-25 16:28:26 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2017-03-25 16:28:26 +0000 |
commit | 0794fafa650ee57195391a1438b9ba412c220412 (patch) | |
tree | ee6417921af6ed135f0b0b30b9220aa9eff841a6 /usr.sbin | |
parent | 7fd154d0570bf797098441e117e6bf1aab4af5cc (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.c | 18 | ||||
-rw-r--r-- | usr.sbin/vmctl/vmctl.8 | 14 | ||||
-rw-r--r-- | usr.sbin/vmd/config.c | 17 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile.h | 6 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile_elf.c | 16 | ||||
-rw-r--r-- | usr.sbin/vmd/vm.c | 97 | ||||
-rw-r--r-- | usr.sbin/vmd/vm.conf.5 | 19 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.8 | 12 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.h | 3 |
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" |