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