Skip to content

Commit

Permalink
Support booting from compressed kernel images.
Browse files Browse the repository at this point in the history
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@
  • Loading branch information
voutilad committed Apr 5, 2021
1 parent 6f88e1f commit 45bdc46
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 58 deletions.
6 changes: 3 additions & 3 deletions usr.sbin/vmd/Makefile
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -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=

Expand Down
8 changes: 5 additions & 3 deletions usr.sbin/vmd/loadfile.h
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -30,6 +30,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <zlib.h>

/*
* Array indices in the u_long position array
*/
Expand Down Expand Up @@ -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);
67 changes: 34 additions & 33 deletions usr.sbin/vmd/loadfile_elf.c
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -260,18 +260,19 @@ 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;
size_t n, stacksize;
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));
Expand Down Expand Up @@ -471,15 +472,15 @@ 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
*
* Return values:
* 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;
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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);
Expand Down
30 changes: 16 additions & 14 deletions usr.sbin/vmd/vm.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
Expand All @@ -21,6 +21,7 @@
#include <sys/queue.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/mman.h>
Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -213,23 +214,23 @@ 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:
* 0 if successful
* 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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -331,24 +333,24 @@ 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 */
ret = loadfile_elf(fp, vcp, &vrs);

/*
* 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)
Expand Down
Loading

0 comments on commit 45bdc46

Please sign in to comment.