The initrd now works. We round up to the next 4k. For older kernels, you need to set the device to 0x100; for newer kernels, set type_of_loader to 0xff. This is tested with a simple busybox initramfs from u-root. Change-Id: If14bcf613fdb06ef4147b6f27dc27c691f46bbaa Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/tests/dune/dune.c b/tests/dune/dune.c index 38dc0c5..e5446b6 100644 --- a/tests/dune/dune.c +++ b/tests/dune/dune.c
@@ -442,7 +442,7 @@ auxc = auxc + extrac; if (!test) { - entry = load_elf(argv[0], MinMemory); + entry = load_elf(argv[0], MinMemory, NULL); if (entry == 0) { fprintf(stderr, "Unable to load kernel %s\n", argv[0]); exit(1);
diff --git a/tests/vmm/vmrunkernel.c b/tests/vmm/vmrunkernel.c index ceaa200..61879b5 100644 --- a/tests/vmm/vmrunkernel.c +++ b/tests/vmm/vmrunkernel.c
@@ -373,6 +373,7 @@ int debug = 0; unsigned long long memsize = GiB; uintptr_t memstart = MinMemory; + uintptr_t memend; struct boot_params *bp; char cmdline_default[512] = {0}; char *cmdline_extra = "\0"; @@ -395,6 +396,9 @@ uint64_t num_pcs = 1; bool is_greedy = FALSE; bool is_scp = FALSE; + char *initrd = NULL; + uint64_t initrd_start = 0, initrd_size = 0; + uint64_t kernel_max_address; static struct option long_options[] = { {"debug", no_argument, 0, 'd'}, @@ -404,6 +408,7 @@ {"memstart", required_argument, 0, 'M'}, {"cmdline_extra", required_argument, 0, 'c'}, {"greedy", no_argument, 0, 'g'}, + {"initrd", required_argument, 0, 'i'}, {"scp", no_argument, 0, 's'}, {"image_file", required_argument, 0, 'f'}, {"cmdline", required_argument, 0, 'k'}, @@ -435,7 +440,7 @@ fprintf(stderr, "static initializers are broken\n"); memsize = GiB; - while ((c = getopt_long(argc, argv, "dvm:M:c:gsf:k:N:n:t:hR:", + while ((c = getopt_long(argc, argv, "dvi:m:M:c:gsf:k:N:n:t:hR:", long_options, &option_index)) != -1) { switch (c) { case 'd': @@ -471,6 +476,9 @@ case 'f': /* file to pass to blk_init */ disk_image_file = optarg; break; + case 'i': + initrd = optarg; + break; case 'k': /* specify file to get cmdline args from */ cmdline_fd = open(optarg, O_RDONLY); if (cmdline_fd < 0) { @@ -538,7 +546,8 @@ alloc_intr_pages(); - if ((uintptr_t)(memstart + memsize) >= (uintptr_t)BRK_START) { + memend = memstart + memsize - 1; + if (memend >= BRK_START) { fprintf(stderr, "memstart 0x%llx memsize 0x%llx -> 0x%llx is too large; overlaps BRK_START at %p\n", memstart, memsize, memstart + memsize, BRK_START); @@ -547,7 +556,7 @@ mmap_memory(vm, memstart, memsize); - entry = load_elf(argv[0], 0); + entry = load_elf(argv[0], 0, &kernel_max_address); if (entry == 0) { fprintf(stderr, "Unable to load kernel %s\n", argv[0]); exit(1); @@ -558,6 +567,25 @@ bp = a; a = init_e820map(bp, memstart, memsize); + if (initrd) { + initrd_start = ROUNDUP(kernel_max_address, PGSIZE); + fprintf(stderr, "kernel_max_address is %#p; Load initrd @ %#p\n", + kernel_max_address, initrd_start); + initrd_size = setup_initrd(initrd, (void *)initrd_start, + memend - initrd_start + 1); + if (initrd_size <= 0) { + fprintf(stderr, "Unable to load initrd %s\n", initrd); + exit(1); + } + + bp->hdr.ramdisk_image = initrd_start; + bp->hdr.ramdisk_size = initrd_size; + bp->hdr.root_dev = 0x100; + bp->hdr.type_of_loader = 0xff; + fprintf(stderr, "Set bp initrd to %p / %p\n", + initrd_start, initrd_size); + } + /* The MMIO address of the console device is really the address of an * unbacked EPT page: accesses to this page will cause a page fault that * traps to the host, which will examine the fault, see it was for the
diff --git a/user/vmm/include/vmm/vmm.h b/user/vmm/include/vmm/vmm.h index 13c673e..3806de4 100644 --- a/user/vmm/include/vmm/vmm.h +++ b/user/vmm/include/vmm/vmm.h
@@ -95,8 +95,8 @@ uint64_t *regp, int store); int vmm_interrupt_guest(struct virtual_machine *vm, unsigned int gpcoreid, unsigned int vector); -uintptr_t load_elf(char *filename, uint64_t offset); - +uintptr_t load_elf(char *filename, uint64_t offset, uint64_t *highest); +ssize_t setup_initrd(char *filename, void *membase, size_t memsize); /* Lookup helpers */ static struct virtual_machine *gth_to_vm(struct guest_thread *gth)
diff --git a/user/vmm/initrd.c b/user/vmm/initrd.c new file mode 100644 index 0000000..d8a7c4b --- /dev/null +++ b/user/vmm/initrd.c
@@ -0,0 +1,59 @@ +/* Copyright (c) 2017 Google Inc. + * See LICENSE for details. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <err.h> + +/* initrd loads the initrd and returns its place in the world. It has + * to avoid the already loaded kernel. */ +ssize_t setup_initrd(char *filename, void *membase, size_t memsize) +{ + int fd; + struct stat buf; + void *where = membase; + int amt; + int tot = 0; + + if (!filename) + return 0; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open %s: %r\n", filename); + return 0; + } + + if (fstat(fd, &buf) < 0) { + fprintf(stderr, "Can't stat %s: %r\n", filename); + close(fd); + return 0; + } + + if (buf.st_size > memsize) { + fprintf(stderr, + "file is %d bytes, but we only have %d bytes to place it\n", + buf.st_size, memsize); + close(fd); + return 0; + } + + while (tot < buf.st_size) { + amt = read(fd, where, buf.st_size - tot); + if (amt < 0) { + tot = 0; + break; + } + where += amt; + tot += amt; + } + + close(fd); + return tot; +}
diff --git a/user/vmm/load_elf.c b/user/vmm/load_elf.c index e16baee..69cfdbf 100644 --- a/user/vmm/load_elf.c +++ b/user/vmm/load_elf.c
@@ -10,9 +10,10 @@ /* load_elf loads and ELF file. This is almost always a kernel. * We assume that memory is set up correctly, and it will go hard - * with you if it is not. */ + * with you if it is not. The reference parameter records the highest + * address we wrote. The initrd can go there.*/ uintptr_t -load_elf(char *filename, uint64_t offset) +load_elf(char *filename, uint64_t offset, uint64_t *highest) { Elf64_Ehdr *ehdr; Elf *elf; @@ -20,6 +21,7 @@ Elf64_Phdr *hdrs; int fd; uintptr_t ret; + uintptr_t kern_end = 0; elf_version(EV_CURRENT); fd = open(filename, O_RDONLY); @@ -64,7 +66,7 @@ uintptr_t pa; fprintf(stderr, - "%d: type 0x%lx flags 0x%lx offset 0x%lx vaddr 0x%lx paddr 0x%lx size 0x%lx memsz 0x%lx align 0x%lx\n", + "%d: type 0x%lx flags 0x%lx offset 0x%lx vaddr 0x%lx\npaddr 0x%lx size 0x%lx memsz 0x%lx align 0x%lx\n", i, h->p_type, /* Segment type */ h->p_flags, /* Segment flags */ @@ -98,11 +100,15 @@ filename, tot, h->p_filesz); goto fail; } + if ((h->p_paddr + h->p_memsz) > kern_end) + kern_end = h->p_paddr + h->p_memsz; } close(fd); ret = ehdr->e_entry + offset; elf_end(elf); + if (highest) + *highest = kern_end; return ret; fail: close(fd);
diff --git a/user/vmm/pagetables.c b/user/vmm/pagetables.c index 6a69f89..023511d 100644 --- a/user/vmm/pagetables.c +++ b/user/vmm/pagetables.c
@@ -42,9 +42,10 @@ nptp += npml2; fprintf(stderr, - "Memstart is %llx, memsize is %llx, memstart + memsize is %llx; ", + "Memstart is %llx, memsize is %llx," + "memstart + memsize is %llx; \n", memstart, memsize, memstart + memsize); - fprintf(stderr, " %d pml4 %d pml3 %d pml2\n", + fprintf(stderr, "\t%d pml4 %d pml3 %d pml2\n", npml4, npml3, npml2); /* Place these page tables right after VM memory. We