The initrd now works.
authorRonald G. Minnich <rminnich@gmail.com>
Thu, 13 Jul 2017 00:08:43 +0000 (17:08 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 30 Aug 2017 17:49:47 +0000 (13:49 -0400)
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>
tests/dune/dune.c
tests/vmm/vmrunkernel.c
user/vmm/include/vmm/vmm.h
user/vmm/initrd.c [new file with mode: 0644]
user/vmm/load_elf.c
user/vmm/pagetables.c

index 38dc0c5..e5446b6 100644 (file)
@@ -442,7 +442,7 @@ int main(int argc, char **argv)
        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);
index ceaa200..61879b5 100644 (file)
@@ -373,6 +373,7 @@ int main(int argc, char **argv)
        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 @@ int main(int argc, char **argv)
        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 @@ int main(int argc, char **argv)
                {"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 @@ int main(int argc, char **argv)
                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 @@ int main(int argc, char **argv)
                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 @@ int main(int argc, char **argv)
 
        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 @@ int main(int argc, char **argv)
 
        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 @@ int main(int argc, char **argv)
        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
index 13c673e..3806de4 100644 (file)
@@ -95,8 +95,8 @@ int __apic_access(struct guest_thread *vm_thread, uint64_t gpa, int destreg,
                   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 (file)
index 0000000..d8a7c4b
--- /dev/null
@@ -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;
+}
index e16baee..69cfdbf 100644 (file)
 
 /* 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 @@ load_elf(char *filename, uint64_t offset)
        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 @@ load_elf(char *filename, uint64_t offset)
                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 @@ load_elf(char *filename, uint64_t offset)
                                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);
index 6a69f89..023511d 100644 (file)
@@ -42,9 +42,10 @@ void *setup_paging(struct virtual_machine *vm, bool debug)
        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