From: dv Date: Mon, 5 Apr 2021 18:09:48 +0000 (+0000) Subject: Support booting from compressed kernel images. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=45bdc46fd437f16fb19609ef021fcf490eb43214;p=openbsd Support booting from compressed kernel images. The bsd.rd ramdisk now ships gzip'd on amd64. Use libz in base to transparently handle decompression of any compressed kernel images. Patch from Josh Rickmar. ok kn@ --- diff --git a/usr.sbin/vmd/Makefile b/usr.sbin/vmd/Makefile index 132221fb960..0abaf00fdd1 100644 --- a/usr.sbin/vmd/Makefile +++ b/usr.sbin/vmd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.25 2021/03/19 09:29:33 kn Exp $ +# $OpenBSD: Makefile,v 1.26 2021/04/05 18:09:48 dv Exp $ .if ${MACHINE} == "amd64" @@ -14,8 +14,8 @@ CFLAGS+= -Wmissing-declarations CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+= -Wsign-compare -LDADD+= -lutil -lpthread -levent -DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT} +LDADD+= -lutil -lpthread -levent -lz +DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT} ${LIBZ} YFLAGS= diff --git a/usr.sbin/vmd/loadfile.h b/usr.sbin/vmd/loadfile.h index 43b79cf6762..fcc74642f5e 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.13 2021/03/19 09:29:33 kn Exp $ */ +/* $OpenBSD: loadfile.h,v 1.14 2021/04/05 18:09:48 dv Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -30,6 +30,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include + /* * Array indices in the u_long position array */ @@ -73,6 +75,6 @@ #define PML2_PAGE 0x13000 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t)) -int loadfile_elf(FILE *, struct vm_create_params *, struct vcpu_reg_state *); +int loadfile_elf(gzFile, struct vm_create_params *, struct vcpu_reg_state *); -size_t mread(FILE *, paddr_t, size_t); +size_t mread(gzFile, paddr_t, size_t); diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index 8485ac59ccb..8a18cb3bad8 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.37 2021/03/19 09:29:33 kn Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.38 2021/04/05 18:09:48 dv Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -115,8 +115,8 @@ union { static void setsegment(struct mem_segment_descriptor *, uint32_t, size_t, int, int, int, int); -static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int); -static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int); +static int elf32_exec(gzFile, Elf32_Ehdr *, u_long *, int); +static int elf64_exec(gzFile, 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); @@ -260,10 +260,11 @@ push_pt_64(void) * * Return values: * 0 if successful - * various error codes returned from read(2) or loadelf functions + * various error codes returned from gzread(3) or loadelf functions */ int -loadfile_elf(FILE *fp, struct vm_create_params *vcp, struct vcpu_reg_state *vrs) +loadfile_elf(gzFile fp, struct vm_create_params *vcp, + struct vcpu_reg_state *vrs) { int r, is_i386 = 0; uint32_t bootargsz; @@ -271,7 +272,7 @@ loadfile_elf(FILE *fp, 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 = fread(&hdr, 1, sizeof(hdr), fp)) != sizeof(hdr)) + if ((r = gzread(fp, &hdr, sizeof(hdr))) != sizeof(hdr)) return 1; memset(&marks, 0, sizeof(marks)); @@ -471,7 +472,7 @@ push_stack(uint32_t bootargsz, uint32_t end) * into the guest address space at paddr 'addr'. * * Parameters: - * fd: file descriptor of the kernel image file to read from. + * fp: kernel image file to read from. * addr: guest paddr_t to load to * sz: number of bytes to load * @@ -479,7 +480,7 @@ push_stack(uint32_t bootargsz, uint32_t end) * returns 'sz' if successful, or 0 otherwise. */ size_t -mread(FILE *fp, paddr_t addr, size_t sz) +mread(gzFile fp, paddr_t addr, size_t sz) { size_t ct; size_t i, rd, osz; @@ -499,7 +500,7 @@ mread(FILE *fp, paddr_t addr, size_t sz) else ct = sz; - if (fread(buf, 1, ct, fp) != ct) { + if ((size_t)gzread(fp, buf, ct) != ct) { log_warn("%s: error %d in mread", __progname, errno); return (0); } @@ -523,7 +524,7 @@ mread(FILE *fp, paddr_t addr, size_t sz) else ct = PAGE_SIZE; - if (fread(buf, 1, ct, fp) != ct) { + if ((size_t)gzread(fp, buf, ct) != ct) { log_warn("%s: error %d in mread", __progname, errno); return (0); } @@ -628,13 +629,13 @@ mbcopy(void *src, paddr_t dst, int sz) /* * elf64_exec * - * Load the kernel indicated by 'fd' into the guest physical memory + * Load the kernel indicated by 'fp' into the guest physical memory * space, at the addresses defined in the ELF header. * * This function is used for 64 bit kernels. * * Parameters: - * fd: file descriptor of the kernel to load + * fp: kernel image file to load * elf: ELF header of the kernel * marks: array to store the offsets of various kernel structures * (start, bss, etc) @@ -646,7 +647,7 @@ mbcopy(void *src, paddr_t dst, int sz) * 1 if unsuccessful */ static int -elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) +elf64_exec(gzFile fp, Elf64_Ehdr *elf, u_long *marks, int flags) { Elf64_Shdr *shp; Elf64_Phdr *phdr; @@ -661,12 +662,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) sz = elf->e_phnum * sizeof(Elf64_Phdr); phdr = malloc(sz); - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1) { + if (gzseek(fp, (off_t)elf->e_phoff, SEEK_SET) == -1) { free(phdr); return 1; } - if (fread(phdr, 1, sz, fp) != sz) { + if ((size_t)gzread(fp, phdr, sz) != sz) { free(phdr); return 1; } @@ -706,7 +707,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ - if (fseeko(fp, (off_t)phdr[i].p_offset, + if (gzseek(fp, (off_t)phdr[i].p_offset, SEEK_SET) == -1) { free(phdr); return 1; @@ -751,14 +752,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) maxp += sizeof(Elf64_Ehdr); if (flags & (LOAD_SYM | COUNT_SYM)) { - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1) { - warn("lseek section headers"); + if (gzseek(fp, (off_t)elf->e_shoff, SEEK_SET) == -1) { + warn("gzseek section headers"); return 1; } sz = elf->e_shnum * sizeof(Elf64_Shdr); shp = malloc(sz); - if (fread(shp, 1, sz, fp) != sz) { + if ((size_t)gzread(fp, shp, sz) != sz) { free(shp); return 1; } @@ -768,13 +769,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) size_t shstrsz = shp[elf->e_shstrndx].sh_size; char *shstr = malloc(shstrsz); - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset, + if (gzseek(fp, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } - if (fread(shstr, 1, shstrsz, fp) != shstrsz) { + if ((size_t)gzread(fp, shstr, shstrsz) != shstrsz) { free(shstr); free(shp); return 1; @@ -797,7 +798,7 @@ elf64_exec(FILE *fp, 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 (fseeko(fp, (off_t)shp[i].sh_offset, + if (gzseek(fp, (off_t)shp[i].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); @@ -850,13 +851,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) /* * elf32_exec * - * Load the kernel indicated by 'fd' into the guest physical memory + * Load the kernel indicated by 'fp' into the guest physical memory * space, at the addresses defined in the ELF header. * * This function is used for 32 bit kernels. * * Parameters: - * fd: file descriptor of the kernel to load + * fp: kernel image file to load * elf: ELF header of the kernel * marks: array to store the offsets of various kernel structures * (start, bss, etc) @@ -868,7 +869,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags) * 1 if unsuccessful */ static int -elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags) +elf32_exec(gzFile fp, Elf32_Ehdr *elf, u_long *marks, int flags) { Elf32_Shdr *shp; Elf32_Phdr *phdr; @@ -883,12 +884,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags) sz = elf->e_phnum * sizeof(Elf32_Phdr); phdr = malloc(sz); - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1) { + if (gzseek(fp, (off_t)elf->e_phoff, SEEK_SET) == -1) { free(phdr); return 1; } - if (fread(phdr, 1, sz, fp) != sz) { + if ((size_t)gzread(fp, phdr, sz) != sz) { free(phdr); return 1; } @@ -928,7 +929,7 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags) (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ - if (fseeko(fp, (off_t)phdr[i].p_offset, + if (gzseek(fp, (off_t)phdr[i].p_offset, SEEK_SET) == -1) { free(phdr); return 1; @@ -973,14 +974,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags) maxp += sizeof(Elf32_Ehdr); if (flags & (LOAD_SYM | COUNT_SYM)) { - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1) { + if (gzseek(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 (fread(shp, 1, sz, fp) != sz) { + if ((size_t)gzread(fp, shp, sz) != sz) { free(shp); return 1; } @@ -990,13 +991,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags) size_t shstrsz = shp[elf->e_shstrndx].sh_size; char *shstr = malloc(shstrsz); - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset, + if (gzseek(fp, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } - if (fread(shstr, 1, shstrsz, fp) != shstrsz) { + if ((size_t)gzread(fp, shstr, shstrsz) != shstrsz) { free(shstr); free(shp); return 1; @@ -1018,7 +1019,7 @@ elf32_exec(FILE *fp, 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 (fseeko(fp, (off_t)shp[i].sh_offset, + if (gzseek(fp, (off_t)shp[i].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index 9ffd1598b21..58f441172a0 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm.c,v 1.61 2021/03/29 23:37:01 dv Exp $ */ +/* $OpenBSD: vm.c,v 1.62 2021/04/05 18:09:48 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -84,7 +85,7 @@ void vcpu_exit_inout(struct vm_run_params *); int vcpu_exit_eptviolation(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 *); +int loadfile_bios(gzFile, off_t, struct vcpu_reg_state *); int send_vm(int, struct vm_create_params *); int dump_send_header(int); int dump_vmr(int , struct vm_mem_range *); @@ -213,6 +214,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 = { * * Parameters: * fp: file of a kernel file to load + * size: uncompressed size of the image * (out) vrs: register state to set on init for this kernel * * Return values: @@ -220,16 +222,15 @@ static const struct vcpu_reg_state vcpu_init_flat16 = { * various error codes returned from read(2) or loadelf functions */ int -loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs) +loadfile_bios(gzFile fp, off_t size, struct vcpu_reg_state *vrs) { - off_t size, off; + off_t 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) + /* Seek to the beginning of the BIOS image */ + if (gzseek(fp, 0, SEEK_SET) == -1) return (-1); /* The BIOS image must end at 1M */ @@ -277,9 +278,10 @@ start_vm(struct vmd_vm *vm, int fd) struct vcpu_reg_state vrs; int nicfds[VMM_MAX_NICS_PER_VM]; int ret; - FILE *fp; + gzFile fp; size_t i; struct vm_rwregs_params vrp; + struct stat sb; /* Child */ setproctitle("%s", vcp->vcp_name); @@ -331,7 +333,7 @@ start_vm(struct vmd_vm *vm, int fd) memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs)); /* Find and open kernel image */ - if ((fp = fdopen(vm->vm_kernel, "r")) == NULL) + if ((fp = gzdopen(vm->vm_kernel, "r")) == NULL) fatalx("failed to open kernel - exiting"); /* Load kernel image */ @@ -339,16 +341,16 @@ start_vm(struct vmd_vm *vm, int fd) /* * Try BIOS as a fallback (only if it was provided as an image - * with vm->vm_kernel and not loaded from the disk) + * with vm->vm_kernel and the file is not compressed) */ - if (ret && errno == ENOEXEC && vm->vm_kernel != -1) - ret = loadfile_bios(fp, &vrs); + if (ret && errno == ENOEXEC && vm->vm_kernel != -1 && + gzdirect(fp) && (ret = fstat(vm->vm_kernel, &sb)) == 0) + ret = loadfile_bios(fp, sb.st_size, &vrs); if (ret) fatal("failed to load kernel or BIOS - exiting"); - if (fp) - fclose(fp); + gzclose(fp); } if (vm->vm_kernel != -1) diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index a9d752a2c2a..79655f4a0fd 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.103 2021/03/29 23:37:01 dv Exp $ */ +/* $OpenBSD: vmd.h,v 1.104 2021/04/05 18:09:48 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -485,10 +485,6 @@ int config_getdisk(struct privsep *, struct imsg *); int config_getif(struct privsep *, struct imsg *); int config_getcdrom(struct privsep *, struct imsg *); -/* vmboot.c */ -FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *); -void vmboot_close(FILE *, struct vmboot_params *); - /* parse.y */ int parse_config(const char *); int cmdline_symset(char *);