diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2016-11-24 07:58:56 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2016-11-24 07:58:56 +0000 |
commit | 81d8dac5286fc0d2981df1a3284c184ae3c6e9d5 (patch) | |
tree | 02c8d9ed18b4e832e7e4f28e5f1a183d2be41829 | |
parent | 318a7884e9d299146de19d369e29bf264cc1180c (diff) |
Add support for booting the kernel from the disk image.
This make the kernel/-k argument optional and, if not specified, tries
to find the /bsd kernel in the primary hd0a partition of the first
disk image itself. It doesn't support hd0a:/etc/boot.conf yet, and it
is no BIOS or full boot loader, but it makes booting and handling of
VMs a bit easier - booting an external kernel is still supported.
The UFS file system code ufs.c is directly from libsa which is also
used by the real boot loader. The code compiles with a few signedness
warning which will be fixed separately.
OK mlarkin@
-rw-r--r-- | usr.sbin/vmctl/vmctl.c | 9 | ||||
-rw-r--r-- | usr.sbin/vmd/Makefile | 3 | ||||
-rw-r--r-- | usr.sbin/vmd/config.c | 14 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile.h | 4 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile_elf.c | 76 | ||||
-rw-r--r-- | usr.sbin/vmd/ufs.c | 718 | ||||
-rw-r--r-- | usr.sbin/vmd/vmboot.c | 237 | ||||
-rw-r--r-- | usr.sbin/vmd/vmboot.h | 70 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.c | 18 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.h | 8 | ||||
-rw-r--r-- | usr.sbin/vmd/vmm.c | 18 |
11 files changed, 1111 insertions, 64 deletions
diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c index c4861260513..3f69c4b6bcf 100644 --- a/usr.sbin/vmctl/vmctl.c +++ b/usr.sbin/vmctl/vmctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.c,v 1.17 2016/11/22 11:31:38 edd Exp $ */ +/* $OpenBSD: vmctl.c,v 1.18 2016/11/24 07:58:55 reyk Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> @@ -70,12 +70,12 @@ start_vm(const char *name, int memsize, int nnics, int ndisks, char **disks, if (memsize < 1) errx(1, "specified memory size too small"); - if (kernel == NULL) - errx(1, "no kernel specified"); if (ndisks > VMM_MAX_DISKS_PER_VM) errx(1, "too many disks"); else if (ndisks == 0) warnx("starting without disks"); + if (kernel == NULL && ndisks == 0) + errx(1, "no kernel or disk specified"); if (nnics == -1) nnics = 0; if (nnics == 0) @@ -103,7 +103,8 @@ start_vm(const char *name, int memsize, int nnics, int ndisks, char **disks, if (name != NULL) strlcpy(vcp->vcp_name, name, VMM_MAX_NAME_LEN); - strlcpy(vcp->vcp_kernel, kernel, VMM_MAX_KERNEL_PATH); + if (kernel != NULL) + strlcpy(vcp->vcp_kernel, kernel, VMM_MAX_KERNEL_PATH); vcp->vcp_nnics = nnics; imsg_compose(ibuf, IMSG_VMDOP_START_VM_REQUEST, 0, 0, -1, diff --git a/usr.sbin/vmd/Makefile b/usr.sbin/vmd/Makefile index e85c5e98aa7..a4666ba3a07 100644 --- a/usr.sbin/vmd/Makefile +++ b/usr.sbin/vmd/Makefile @@ -1,10 +1,11 @@ -# $OpenBSD: Makefile,v 1.10 2016/10/26 05:26:36 mlarkin Exp $ +# $OpenBSD: Makefile,v 1.11 2016/11/24 07:58:55 reyk Exp $ .if ${MACHINE} == "amd64" || ${MACHINE} == "i386" PROG= vmd SRCS= vmm.c loadfile_elf.c pci.c virtio.c i8259.c mc146818.c SRCS+= vmd.c control.c log.c priv.c proc.c config.c ns8250.c i8253.c +SRCS+= vmboot.c ufs.c SRCS+= parse.y CFLAGS+= -Wall -I${.CURDIR} diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c index 76f2c8851b7..6f79fa7f212 100644 --- a/usr.sbin/vmd/config.c +++ b/usr.sbin/vmd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.20 2016/11/22 21:55:54 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.21 2016/11/24 07:58:55 reyk Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -160,8 +160,9 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid) vm->vm_peerid = peerid; - /* Open kernel for child */ - if ((kernfd = open(vcp->vcp_kernel, O_RDONLY)) == -1) { + /* 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); goto fail; @@ -305,12 +306,9 @@ config_getvm(struct privsep *ps, struct imsg *imsg) errno = 0; if (vm_register(ps, &vmc, &vm, imsg->hdr.peerid) == -1) - return (-1); - - if (imsg->fd == -1) { - log_debug("invalid kernel fd"); goto fail; - } + + /* If the fd is -1, the kernel will be searched on the disk */ vm->vm_kernel = imsg->fd; vm->vm_running = 1; diff --git a/usr.sbin/vmd/loadfile.h b/usr.sbin/vmd/loadfile.h index 1010dbb6e41..aff1a9fd052 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.5 2016/09/01 16:04:47 stefan Exp $ */ +/* $OpenBSD: loadfile.h,v 1.6 2016/11/24 07:58:55 reyk Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -73,7 +73,7 @@ #define PML2_PAGE 0x13000 #define NPTE_PG (PAGE_SIZE / sizeof(pt_entry_t)) -int loadelf_main(int, struct vm_create_params *, +int loadelf_main(FILE *, struct vm_create_params *, struct vcpu_reg_state *); #include <machine/loadfile_machdep.h> diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index 544795ee832..7ec9b2ae063 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.20 2016/10/26 05:26:36 mlarkin Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.21 2016/11/24 07:58:55 reyk Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -118,13 +118,13 @@ static void setsegment(struct segment_descriptor *, uint32_t, static void setsegment(struct mem_segment_descriptor *, uint32_t, size_t, int, int, int, int); #endif -static int elf32_exec(int, Elf32_Ehdr *, u_long *, int); -static int elf64_exec(int, Elf64_Ehdr *, u_long *, int); +static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int); +static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int); static size_t create_bios_memmap(struct vm_create_params *, bios_memmap_t *); static uint32_t push_bootargs(bios_memmap_t *, size_t); static size_t push_stack(uint32_t, uint32_t); static void push_gdt(void); -static size_t mread(int, paddr_t, size_t); +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); @@ -271,7 +271,7 @@ push_pt(void) * various error codes returned from read(2) or loadelf functions */ int -loadelf_main(int fd, struct vm_create_params *vcp, struct vcpu_reg_state *vrs) +loadelf_main(FILE *fp, struct vm_create_params *vcp, struct vcpu_reg_state *vrs) { int r; uint32_t bootargsz; @@ -279,16 +279,16 @@ loadelf_main(int fd, struct vm_create_params *vcp, struct vcpu_reg_state *vrs) u_long marks[MARK_MAX]; bios_memmap_t memmap[VMM_MAX_MEM_RANGES + 1]; - if ((r = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) + if ((r = fread(&hdr, 1, sizeof(hdr), fp)) != sizeof(hdr)) return 1; memset(&marks, 0, sizeof(marks)); if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 && hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { - r = elf32_exec(fd, &hdr.elf32, marks, LOAD_ALL); + r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL); } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 && hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) { - r = elf64_exec(fd, &hdr.elf64, marks, LOAD_ALL); + r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL); } if (r) @@ -476,9 +476,9 @@ push_stack(uint32_t bootargsz, uint32_t end) * returns 'sz' if successful, or 0 otherwise. */ static size_t -mread(int fd, paddr_t addr, size_t sz) +mread(FILE *fp, paddr_t addr, size_t sz) { - int ct; + size_t ct; size_t i, rd, osz; char buf[PAGE_SIZE]; @@ -496,7 +496,7 @@ mread(int fd, paddr_t addr, size_t sz) else ct = sz; - if (read(fd, buf, ct) != ct) { + if (fread(buf, 1, ct, fp) != ct) { log_warn("%s: error %d in mread", __progname, errno); return (0); } @@ -520,7 +520,7 @@ mread(int fd, paddr_t addr, size_t sz) else ct = PAGE_SIZE; - if (read(fd, buf, ct) != ct) { + if (fread(buf, 1, ct, fp) != ct) { log_warn("%s: error %d in mread", __progname, errno); return (0); } @@ -668,13 +668,13 @@ mbcopy(void *src, paddr_t dst, int sz) * 1 if unsuccessful */ static int -elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) +elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) { Elf64_Shdr *shp; Elf64_Phdr *phdr; Elf64_Off off; int i; - ssize_t sz; + size_t sz; int first; int havesyms, havelines; paddr_t minp = ~0, maxp = 0, pos = 0; @@ -683,12 +683,12 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) sz = elf->e_phnum * sizeof(Elf64_Phdr); phdr = malloc(sz); - if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1) { + if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1) { free(phdr); return 1; } - if (read(fd, phdr, sz) != sz) { + if (fread(phdr, 1, sz, fp) != sz) { free(phdr); return 1; } @@ -728,12 +728,12 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ - if (lseek(fd, (off_t)phdr[i].p_offset, + if (fseeko(fp, (off_t)phdr[i].p_offset, SEEK_SET) == -1) { free(phdr); return 1; } - if (mread(fd, phdr[i].p_paddr, phdr[i].p_filesz) != + if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) != phdr[i].p_filesz) { free(phdr); return 1; @@ -773,14 +773,14 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) maxp += sizeof(Elf64_Ehdr); if (flags & (LOAD_SYM | COUNT_SYM)) { - if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1) { + if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1) { WARN(("lseek section headers")); return 1; } sz = elf->e_shnum * sizeof(Elf64_Shdr); shp = malloc(sz); - if (read(fd, shp, sz) != sz) { + if (fread(shp, 1, sz, fp) != sz) { free(shp); return 1; } @@ -788,15 +788,15 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) shpp = maxp; maxp += roundup(sz, sizeof(Elf64_Addr)); - ssize_t shstrsz = shp[elf->e_shstrndx].sh_size; + size_t shstrsz = shp[elf->e_shstrndx].sh_size; char *shstr = malloc(shstrsz); - if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, + if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } - if (read(fd, shstr, shstrsz) != shstrsz) { + if (fread(shstr, 1, shstrsz, fp) != shstrsz) { free(shstr); free(shp); return 1; @@ -819,13 +819,13 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) !strcmp(shstr + shp[i].sh_name, ".debug_line") || !strcmp(shstr + shp[i].sh_name, ELF_CTF)) { if (havesyms && (flags & LOAD_SYM)) { - if (lseek(fd, (off_t)shp[i].sh_offset, + if (fseeko(fp, (off_t)shp[i].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } - if (mread(fd, maxp, + if (mread(fp, maxp, shp[i].sh_size) != shp[i].sh_size) { free(shstr); free(shp); @@ -890,13 +890,13 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) * 1 if unsuccessful */ static int -elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) +elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags) { Elf32_Shdr *shp; Elf32_Phdr *phdr; Elf32_Off off; int i; - ssize_t sz; + size_t sz; int first; int havesyms, havelines; paddr_t minp = ~0, maxp = 0, pos = 0; @@ -905,12 +905,12 @@ elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) sz = elf->e_phnum * sizeof(Elf32_Phdr); phdr = malloc(sz); - if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1) { + if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1) { free(phdr); return 1; } - if (read(fd, phdr, sz) != sz) { + if (fread(phdr, 1, sz, fp) != sz) { free(phdr); return 1; } @@ -950,12 +950,12 @@ elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ - if (lseek(fd, (off_t)phdr[i].p_offset, + if (fseeko(fp, (off_t)phdr[i].p_offset, SEEK_SET) == -1) { free(phdr); return 1; } - if (mread(fd, phdr[i].p_paddr, phdr[i].p_filesz) != + if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) != phdr[i].p_filesz) { free(phdr); return 1; @@ -995,14 +995,14 @@ elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) maxp += sizeof(Elf32_Ehdr); if (flags & (LOAD_SYM | COUNT_SYM)) { - if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1) { + if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1) { WARN(("lseek section headers")); return 1; } sz = elf->e_shnum * sizeof(Elf32_Shdr); shp = malloc(sz); - if (read(fd, shp, sz) != sz) { + if (fread(shp, 1, sz, fp) != sz) { free(shp); return 1; } @@ -1010,15 +1010,15 @@ elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) shpp = maxp; maxp += roundup(sz, sizeof(Elf32_Addr)); - ssize_t shstrsz = shp[elf->e_shstrndx].sh_size; + size_t shstrsz = shp[elf->e_shstrndx].sh_size; char *shstr = malloc(shstrsz); - if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, + if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } - if (read(fd, shstr, shstrsz) != shstrsz) { + if (fread(shstr, 1, shstrsz, fp) != shstrsz) { free(shstr); free(shp); return 1; @@ -1040,13 +1040,13 @@ elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) shp[i].sh_type == SHT_STRTAB || !strcmp(shstr + shp[i].sh_name, ".debug_line")) { if (havesyms && (flags & LOAD_SYM)) { - if (lseek(fd, (off_t)shp[i].sh_offset, + if (fseeko(fp, (off_t)shp[i].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } - if (mread(fd, maxp, + if (mread(fp, maxp, shp[i].sh_size) != shp[i].sh_size) { free(shstr); free(shp); diff --git a/usr.sbin/vmd/ufs.c b/usr.sbin/vmd/ufs.c new file mode 100644 index 00000000000..ce55a288ac8 --- /dev/null +++ b/usr.sbin/vmd/ufs.c @@ -0,0 +1,718 @@ +/* $OpenBSD: ufs.c,v 1.1 2016/11/24 07:58:55 reyk Exp $ */ +/* $NetBSD: ufs.c,v 1.16 1996/09/30 16:01:22 ws Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Stand-alone file reading package. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <ufs/ffs/fs.h> +#include <ufs/ufs/dinode.h> +#include <ufs/ufs/dir.h> + +#include "vmboot.h" + +/* Used in the kernel by libsa */ +#define alloc malloc +#define free(_p, _n) free(_p) +#define twiddle() do { } while(0) + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + struct fs *f_fs; /* pointer to super-block */ + struct ufs1_dinode f_di; /* copy of on-disk inode */ + int f_nindir[NIADDR]; + /* number of blocks mapped by + indirect block at level i */ + char *f_blk[NIADDR]; /* buffer for indirect block at + level i */ + size_t f_blksize[NIADDR]; + /* size of buffer */ + daddr32_t f_blkno[NIADDR];/* disk address of block in buffer */ + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ + daddr32_t f_buf_blkno; /* block number of data block */ +}; + +static int read_inode(ufsino_t, struct open_file *); +static int block_map(struct open_file *, daddr32_t, daddr32_t *); +static int buf_read_file(struct open_file *, char **, size_t *); +static int search_directory(char *, struct open_file *, ufsino_t *); +static int ufs_close_internal(struct file *); +#ifdef COMPAT_UFS +static void ffs_oldfscompat(struct fs *); +#endif + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(ufsino_t inumber, struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + char *buf; + size_t rsize; + int rc; + + /* + * Read inode and save it. + */ + buf = alloc(fs->fs_bsize); + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, (daddr32_t)ino_to_fsba(fs, inumber)), fs->fs_bsize, + buf, &rsize); + if (rc) + goto out; + if (rsize != (size_t)fs->fs_bsize) { + rc = EIO; + goto out; + } + + { + struct ufs1_dinode *dp; + + dp = (struct ufs1_dinode *)buf; + fp->f_di = dp[ino_to_fsbo(fs, inumber)]; + } + + /* + * Clear out the old buffers + */ + { + int level; + + for (level = 0; level < NIADDR; level++) + fp->f_blkno[level] = -1; + fp->f_buf_blkno = -1; + fp->f_seekp = 0; + } +out: + free(buf, fs->fs_bsize); + return (rc); +} + +/* + * Given an offset in a file, find the disk block number that + * contains that block. + */ +static int +block_map(struct open_file *f, daddr32_t file_block, daddr32_t *disk_block_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + daddr32_t ind_block_num, *ind_p; + struct fs *fs = fp->f_fs; + int level, idx, rc; + + /* + * Index structure of an inode: + * + * di_db[0..NDADDR-1] hold block numbers for blocks + * 0..NDADDR-1 + * + * di_ib[0] index block 0 is the single indirect block + * holds block numbers for blocks + * NDADDR .. NDADDR + NINDIR(fs)-1 + * + * di_ib[1] index block 1 is the double indirect block + * holds block numbers for INDEX blocks for blocks + * NDADDR + NINDIR(fs) .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 + * + * di_ib[2] index block 2 is the triple indirect block + * holds block numbers for double-indirect + * blocks for blocks + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 + * + NINDIR(fs)**3 - 1 + */ + + if (file_block < NDADDR) { + /* Direct block. */ + *disk_block_p = fp->f_di.di_db[file_block]; + return (0); + } + + file_block -= NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < NIADDR; level++) { + if (file_block < fp->f_nindir[level]) + break; + file_block -= fp->f_nindir[level]; + } + if (level == NIADDR) { + /* Block number too high */ + return (EFBIG); + } + + ind_block_num = fp->f_di.di_ib[level]; + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *disk_block_p = 0; /* missing */ + return (0); + } + + if (fp->f_blkno[level] != ind_block_num) { + if (fp->f_blk[level] == NULL) + fp->f_blk[level] = + alloc(fs->fs_bsize); + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize, + fp->f_blk[level], &fp->f_blksize[level]); + if (rc) + return (rc); + if (fp->f_blksize[level] != (size_t)fs->fs_bsize) + return (EIO); + fp->f_blkno[level] = ind_block_num; + } + + ind_p = (daddr32_t *)fp->f_blk[level]; + + if (level > 0) { + idx = file_block / fp->f_nindir[level - 1]; + file_block %= fp->f_nindir[level - 1]; + } else + idx = file_block; + + ind_block_num = ind_p[idx]; + } + + *disk_block_p = ind_block_num; + return (0); +} + +/* + * Read a portion of a file into an internal buffer. Return + * the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + daddr32_t file_block, disk_block; + size_t block_size; + long off; + int rc; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = dblksize(fs, &fp->f_di, file_block); + + if (file_block != fp->f_buf_blkno) { + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (fp->f_buf == NULL) + fp->f_buf = alloc(fs->fs_bsize); + + if (disk_block == 0) { + bzero(fp->f_buf, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + } + + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > fp->f_di.di_size - fp->f_seekp) + *size_p = fp->f_di.di_size - fp->f_seekp; + + return (0); +} + +/* + * Search a directory for a name and return its + * i_number. + */ +static int +search_directory(char *name, struct open_file *f, ufsino_t *inumber_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + int namlen, length, rc; + struct direct *dp, *edp; + size_t buf_size; + char *buf; + + length = strlen(name); + + fp->f_seekp = 0; + while (fp->f_seekp < fp->f_di.di_size) { + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + return (rc); + + dp = (struct direct *)buf; + edp = (struct direct *)(buf + buf_size); + while (dp < edp) { + if (dp->d_ino == 0) + goto next; +#if BYTE_ORDER == LITTLE_ENDIAN + if (fp->f_fs->fs_maxsymlinklen <= 0) + namlen = dp->d_type; + else +#endif + namlen = dp->d_namlen; + if (namlen == length && + !strcmp(name, dp->d_name)) { + /* found entry */ + *inumber_p = dp->d_ino; + return (0); + } + next: + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + fp->f_seekp += buf_size; + } + return (ENOENT); +} + +/* + * Open a file. + */ +int +ufs_open(char *path, struct open_file *f) +{ + char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL; + ufsino_t inumber, parent_inumber; + int rc, c, nlinks = 0; + struct file *fp; + size_t buf_size; + struct fs *fs; + + /* allocate file system specific data structure */ + fp = alloc(sizeof(struct file)); + bzero(fp, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = alloc(SBSIZE); + fp->f_fs = fs; + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + SBLOCK, SBSIZE, (char *)fs, &buf_size); + if (rc) + goto out; + + if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || + fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { + rc = EINVAL; + goto out; + } +#ifdef COMPAT_UFS + ffs_oldfscompat(fs); +#endif + + /* + * Calculate indirect block levels. + */ + { + int mult; + int level; + + mult = 1; + for (level = 0; level < NIADDR; level++) { + mult *= NINDIR(fs); + fp->f_nindir[level] = mult; + } + } + + inumber = ROOTINO; + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + cp = path; + while (*cp) { + + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if ((fp->f_di.di_mode & IFMT) != IFDIR) { + rc = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > MAXNAMLEN) { + rc = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ + parent_inumber = inumber; + rc = search_directory(ncp, f, &inumber); + *cp = c; + if (rc) + goto out; + + /* + * Open next component. + */ + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + /* + * Check for symbolic link. + */ + if ((fp->f_di.di_mode & IFMT) == IFLNK) { + u_int64_t link_len = fp->f_di.di_size; + size_t len; + + len = strlen(cp); + + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + rc = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + + if (link_len < fs->fs_maxsymlinklen) { + bcopy(fp->f_di.di_shortlink, namebuf, link_len); + } else { + /* + * Read file for symbolic link + */ + size_t buf_size; + daddr32_t disk_block; + struct fs *fs = fp->f_fs; + + if (!buf) + buf = alloc(fs->fs_bsize); + rc = block_map(f, (daddr32_t)0, &disk_block); + if (rc) + goto out; + + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsbtodb(fs, disk_block), + fs->fs_bsize, buf, &buf_size); + if (rc) + goto out; + + bcopy(buf, namebuf, link_len); + } + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = ROOTINO; + + if ((rc = read_inode(inumber, f)) != 0) + goto out; + } + } + + /* + * Found terminal component. + */ + rc = 0; +out: + if (buf) + free(buf, fs->fs_bsize); + if (rc) + (void)ufs_close_internal(fp); + + return (rc); +} + +int +ufs_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + f->f_fsdata = NULL; + if (fp == NULL) + return (0); + + return (ufs_close_internal(fp)); +} + +static int +ufs_close_internal(struct file *fp) +{ + int level; + + for (level = 0; level < NIADDR; level++) { + if (fp->f_blk[level]) + free(fp->f_blk[level], fp->f_fs->fs_bsize); + } + if (fp->f_buf) + free(fp->f_buf, fp->f_fs->fs_bsize); + free(fp->f_fs, SBSIZE); + free(fp, sizeof(struct file)); + return (0); +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +int +ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + char *buf, *addr = start; + size_t csize, buf_size; + int rc = 0; + + while (size != 0) { + if (fp->f_seekp >= fp->f_di.di_size) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +/* + * Not implemented. + */ +int +ufs_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + + return (EROFS); +} + +off_t +ufs_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = fp->f_di.di_size - offset; + break; + default: + return (-1); + } + return (fp->f_seekp); +} + +int +ufs_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = fp->f_di.di_mode; + sb->st_uid = fp->f_di.di_uid; + sb->st_gid = fp->f_di.di_gid; + sb->st_size = fp->f_di.di_size; + return (0); +} + +#ifndef NO_READDIR +int +ufs_readdir(struct open_file *f, char *name) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp, *edp; + size_t buf_size; + int rc, namlen; + char *buf; + + if (name == NULL) + fp->f_seekp = 0; + else { + /* end of dir */ + if (fp->f_seekp >= fp->f_di.di_size) { + *name = '\0'; + return -1; + } + + do { + if ((rc = buf_read_file(f, &buf, &buf_size)) != 0) + return rc; + + dp = (struct direct *)buf; + edp = (struct direct *)(buf + buf_size); + while (dp < edp && dp->d_ino == 0) + dp = (struct direct *)((char *)dp + dp->d_reclen); + fp->f_seekp += buf_size - + ((u_int8_t *)edp - (u_int8_t *)dp); + } while (dp >= edp); + +#if BYTE_ORDER == LITTLE_ENDIAN + if (fp->f_fs->fs_maxsymlinklen <= 0) + namlen = dp->d_type; + else +#endif + namlen = dp->d_namlen; + strncpy(name, dp->d_name, namlen + 1); + + fp->f_seekp += dp->d_reclen; + } + + return 0; +} +#endif + +#ifdef COMPAT_UFS +/* + * Sanity checks for old file systems. + * + * XXX - goes away some day. + */ +static void +ffs_oldfscompat(struct fs *fs) +{ + int i; + + fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ + fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + fs->fs_nrpos = 8; /* XXX */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + quad_t sizepb = fs->fs_bsize; /* XXX */ + /* XXX */ + fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ + for (i = 0; i < NIADDR; i++) { /* XXX */ + sizepb *= NINDIR(fs); /* XXX */ + fs->fs_maxfilesize += sizepb; /* XXX */ + } /* XXX */ + fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ + fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ + } /* XXX */ +} +#endif diff --git a/usr.sbin/vmd/vmboot.c b/usr.sbin/vmd/vmboot.c new file mode 100644 index 00000000000..93b75620f5b --- /dev/null +++ b/usr.sbin/vmd/vmboot.c @@ -0,0 +1,237 @@ +/* $OpenBSD: vmboot.c,v 1.1 2016/11/24 07:58:55 reyk Exp $ */ + +/* + * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/disklabel.h> + +#include <ufs/ffs/fs.h> +#include <ufs/ufs/dinode.h> +#include <ufs/ufs/dir.h> + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <err.h> + +#include "vmd.h" +#include "vmboot.h" + +int vmboot_strategy(void *, int, daddr32_t, size_t, void *, size_t *); +off_t vmboot_findopenbsd(struct open_file *, off_t); +void *vmboot_loadfile(struct open_file *, char *, size_t *); + +/* + * For ufs.c + */ + +struct devsw vmboot_devsw = { + .dv_name = "vmboot", + .dv_strategy = vmboot_strategy, + /* other fields are not needed */ +}; + +struct open_file vmboot_file = { + .f_dev = &vmboot_devsw, + .f_devdata = NULL +}; + +struct vmboot { + int fd; + off_t partoff; +}; + +int +vmboot_strategy(void *devdata, int rw, + daddr32_t blk, size_t size, void *buf, size_t *rsize) +{ + struct vmboot *vmboot = devdata; + ssize_t rlen; + + if (vmboot->fd == -1) + return (EIO); + + switch (rw) { + case F_READ: + rlen = pread(vmboot->fd, buf, size, + (blk + vmboot->partoff) * DEV_BSIZE); + if (rlen == -1) + return (errno); + *rsize = (size_t)rlen; + break; + case F_WRITE: + rlen = pwrite(vmboot->fd, buf, size, + (blk + vmboot->partoff) * DEV_BSIZE); + if (rlen == -1) + return (errno); + *rsize = (size_t)rlen; + break; + default: + return (EINVAL); + } + return (0); +} + +/* + * Based on findopenbsd() from biosdev.c that was partially written by me. + */ +off_t +vmboot_findopenbsd(struct open_file *f, off_t mbroff) +{ + struct dos_mbr mbr; + struct dos_partition *dp; + off_t mbr_eoff = DOSBBSECTOR, nextebr; + int ret, i; + static int maxebr = DOS_MAXEBR; + size_t rsize; + + if (!maxebr--) { + log_debug("%s: too many extended partitions", __func__); + return (-1); + } + + memset(&mbr, 0, sizeof(mbr)); + ret = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + mbroff, sizeof(mbr), &mbr, &rsize); + if (ret != 0 || rsize != sizeof(mbr)) { + log_debug("%s: failed to read MBR", __func__); + return (-1); + } + + if (mbr.dmbr_sign != DOSMBR_SIGNATURE) { + log_debug("%s: bad MBR signature", __func__); + return (-1); + } + + /* Search for the first OpenBSD partition */ + nextebr = 0; + for (i = 0; i < NDOSPART; i++) { + dp = &mbr.dmbr_parts[i]; + if (!dp->dp_size) + continue; + + if (dp->dp_typ == DOSPTYP_OPENBSD) { + if (dp->dp_start > (dp->dp_start + mbroff)) + continue; + return (dp->dp_start + mbroff); + } + + if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || + dp->dp_typ == DOSPTYP_EXTENDL)) { + nextebr = dp->dp_start + mbr_eoff; + if (nextebr < dp->dp_start) + nextebr = -1; + if (mbr_eoff == DOSBBSECTOR) + mbr_eoff = dp->dp_start; + } + } + + if (nextebr && nextebr != -1) { + mbroff = nextebr; + return (vmboot_findopenbsd(f, mbroff)); + } + + return (-1); +} + +void * +vmboot_loadfile(struct open_file *f, char *file, size_t *size) +{ + char *buf = NULL; + struct stat st; + size_t rsize; + int ret; + + *size = 0; + + if ((ret = ufs_open(file, f)) != 0) { + log_debug("%s: failed to open hd0a:%s", __func__, file); + goto done; + } + + if ((ret = ufs_stat(f, &st)) != 0) { + log_debug("%s: failed to stat hd0a:%s", __func__, file); + goto done; + } + + if ((buf = calloc(1, roundup(st.st_size, DEV_BSIZE))) == NULL) { + log_debug("%s: failed to allocate buffer", __func__); + goto done; + } + + if ((ret = ufs_read(f, buf, st.st_size, &rsize)) != 0) { + log_debug("%s: failed to read hd0a:%s", __func__, file); + goto done; + } + + *size = st.st_size; + done: + ufs_close(f); + return (buf); +} + +FILE * +vmboot_open(int kernel_fd, int disk_fd, void **boot) +{ + char file[PATH_MAX]; + char *buf = NULL; + struct vmboot vmboot; + size_t size; + FILE *fp = NULL; + + *boot = NULL; + + /* First open kernel directly if specified by fd */ + if (kernel_fd != -1) + return (fdopen(kernel_fd, "r")); + + if (disk_fd == -1) + return (NULL); + + memset(&vmboot, 0, sizeof(vmboot)); + vmboot.fd = disk_fd; + vmboot_file.f_devdata = &vmboot; + + /* XXX try and parse hd0a:/etc/boot.conf */ + strlcpy(file, VM_DEFAULT_KERNEL, sizeof(file)); + + if ((vmboot.partoff = vmboot_findopenbsd(&vmboot_file, 0)) == -1) { + log_debug("%s: could not find openbsd partition", __func__); + return (NULL); + } + + if ((buf = vmboot_loadfile(&vmboot_file, file, &size)) == NULL) + return (NULL); + *boot = buf; + + if ((fp = fmemopen(buf, size, "r")) == NULL) { + log_debug("%s: failed to open memory stream", __func__); + free(buf); + *boot = NULL; + } + + return (fp); +} + +void +vmboot_close(FILE *fp, void *boot) +{ + fclose(fp); + free(boot); +} diff --git a/usr.sbin/vmd/vmboot.h b/usr.sbin/vmd/vmboot.h new file mode 100644 index 00000000000..1df187b28db --- /dev/null +++ b/usr.sbin/vmd/vmboot.h @@ -0,0 +1,70 @@ +/* $OpenBSD: vmboot.h,v 1.1 2016/11/24 07:58:55 reyk Exp $ */ + +/* + * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/stdarg.h> +#include <sys/stdint.h> + +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#ifndef VMBOOT_H +#define VMBOOT_H + +#define F_READ 1 +#define F_WRITE 2 + +struct open_file; + +struct fs_ops { + int (*open)(char *, struct open_file *); + int (*close)(struct open_file *); + int (*read)(struct open_file *, void *, size_t, size_t *); + int (*write)(struct open_file *, void *, size_t, size_t *); + off_t (*seek)(struct open_file *, off_t, int); + int (*stat)(struct open_file *, struct stat *); + int (*readdir)(struct open_file *, char *); +}; + +struct devsw { + char *dv_name; + int (*dv_strategy)(void *, int, daddr32_t, size_t, + void *, size_t *); +}; + +struct open_file { + int f_flags; + struct devsw *f_dev; + void *f_devdata; + struct fs_ops *f_ops; + void *f_fsdata; + off_t f_offset; +}; + +int ufs_open(char *, struct open_file *); +int ufs_close(struct open_file *); +int ufs_read(struct open_file *, void *, size_t, size_t *); +int ufs_write(struct open_file *, void *, size_t, size_t *); +off_t ufs_seek(struct open_file *, off_t offset, int); +int ufs_stat(struct open_file *, struct stat *); +int ufs_readdir(struct open_file *, char *); + +#endif /* VMBOOT_H */ diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c index c29d4aac3ae..857976e3e0b 100644 --- a/usr.sbin/vmd/vmd.c +++ b/usr.sbin/vmd/vmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.c,v 1.42 2016/11/22 21:55:54 reyk Exp $ */ +/* $OpenBSD: vmd.c,v 1.43 2016/11/24 07:58:55 reyk Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -199,8 +199,11 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg) break; } - log_info("%s: started vm %d successfully, tty %s", - vcp->vcp_name, vcp->vcp_id, vm->vm_ttyname); + log_info("%s: started vm %d successfully, " + "kernel %s, tty %s", vcp->vcp_name, vcp->vcp_id, + strlen(vcp->vcp_kernel) ? + vcp->vcp_kernel : "hd0a:" VM_DEFAULT_KERNEL, + vm->vm_ttyname); break; case IMSG_VMDOP_TERMINATE_VM_RESPONSE: case IMSG_VMDOP_TERMINATE_VM_EVENT: @@ -664,13 +667,16 @@ vm_register(struct privsep *ps, struct vmop_create_params *vmc, if (vcp->vcp_ncpus == 0) vcp->vcp_ncpus = 1; if (vcp->vcp_ncpus > VMM_MAX_VCPUS_PER_VM) { - log_debug("invalid number of CPUs"); + log_warnx("invalid number of CPUs"); goto fail; } else if (vcp->vcp_ndisks > VMM_MAX_DISKS_PER_VM) { - log_debug("invalid number of disks"); + log_warnx("invalid number of disks"); goto fail; } else if (vcp->vcp_nnics > VMM_MAX_NICS_PER_VM) { - log_debug("invalid number of interfaces"); + log_warnx("invalid number of interfaces"); + goto fail; + } else if (strlen(vcp->vcp_kernel) == 0 && vcp->vcp_ndisks == 0) { + log_warnx("no kernel or disk specified"); goto fail; } diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index ab414049e80..8ec1b1c1c1b 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.35 2016/11/22 11:31:38 edd Exp $ */ +/* $OpenBSD: vmd.h,v 1.36 2016/11/24 07:58:55 reyk Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -25,6 +25,7 @@ #include <net/if.h> #include <limits.h> +#include <stdio.h> #include <pthread.h> #include "proc.h" @@ -36,6 +37,7 @@ #define VMD_CONF "/etc/vm.conf" #define SOCKET_NAME "/var/run/vmd.sock" #define VMM_NODE "/dev/vmm" +#define VM_DEFAULT_KERNEL "/bsd" #define VM_NAME_MAX 64 #define VM_TTYNAME_MAX 16 #define MAX_TAP 256 @@ -202,6 +204,10 @@ int config_getvm(struct privsep *, struct imsg *); int config_getdisk(struct privsep *, struct imsg *); int config_getif(struct privsep *, struct imsg *); +/* vmboot.c */ +FILE *vmboot_open(int, int, void **); +void vmboot_close(FILE *, void *); + /* parse.y */ int parse_config(const char *); int cmdline_symset(char *); diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index 226b8ceefa4..ecd74545c1b 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.55 2016/11/22 22:51:45 reyk Exp $ */ +/* $OpenBSD: vmm.c,v 1.56 2016/11/24 07:58:55 reyk Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -465,7 +465,9 @@ start_vm(struct imsg *imsg, uint32_t *id) size_t i; int ret = EINVAL; int fds[2], nicfds[VMM_MAX_NICS_PER_VM]; - struct vcpu_reg_state vrs; + struct vcpu_reg_state vrs; + FILE *kernfp; + void *boot; if ((vm = vm_getbyvmid(imsg->hdr.peerid)) == NULL) { log_warnx("%s: can't find vm", __func__); @@ -566,14 +568,22 @@ start_vm(struct imsg *imsg, uint32_t *id) */ memcpy(&vrs, &vcpu_init_flat32, sizeof(struct vcpu_reg_state)); + /* Find and open kernel image */ + if ((kernfp = vmboot_open(vm->vm_kernel, + vm->vm_disks[0], &boot)) == NULL) + fatalx("failed to open kernel - exiting"); + /* Load kernel image */ - ret = loadelf_main(vm->vm_kernel, vcp, &vrs); + ret = loadelf_main(kernfp, vcp, &vrs); if (ret) { errno = ret; fatal("failed to load kernel - exiting"); } - close(vm->vm_kernel); + vmboot_close(kernfp, boot); + + if (vm->vm_kernel != -1) + close(vm->vm_kernel); con_fd = vm->vm_tty; if (fcntl(con_fd, F_SETFL, O_NONBLOCK) == -1) |