parlib: have 2LS libraries #include parlib/stdio.h
[akaros.git] / user / vmm / load_elf.c
index 7ab92fd..b9bc612 100644 (file)
@@ -3,22 +3,25 @@
  *
  * ELF loading. */
 
-#include <stdio.h>
+#include <parlib/stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <libelf.h>
 
 /* 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. */
-uintptr_t
-load_elf(char *filename)
+ * 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, uint64_t *highest,
+                  Elf64_Ehdr *ehdr_out)
 {
        Elf64_Ehdr *ehdr;
        Elf *elf;
        size_t phnum = 0;
        Elf64_Phdr *hdrs;
        int fd;
+       uintptr_t ret;
+       uintptr_t kern_end = 0;
 
        elf_version(EV_CURRENT);
        fd = open(filename, O_RDONLY);
@@ -29,7 +32,8 @@ load_elf(char *filename)
 
        elf = elf_begin(fd, ELF_C_READ, NULL);
        if (elf == NULL) {
-               fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__, filename);
+               fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__,
+                       filename);
                close(fd);
                return 0;
        }
@@ -63,7 +67,7 @@ load_elf(char *filename)
                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 */
@@ -84,8 +88,8 @@ load_elf(char *filename)
                        i, h->p_offset, pa, h->p_paddr, h->p_filesz);
                tot = 0;
                while (tot < h->p_filesz) {
-                       int amt = pread(fd, (void *)(pa + tot), h->p_filesz - tot,
-                                       h->p_offset + tot);
+                       int amt = pread(fd, (void *)(pa + tot + offset),
+                                       h->p_filesz - tot, h->p_offset + tot);
 
                        if (amt < 1)
                                break;
@@ -97,11 +101,21 @@ load_elf(char *filename)
                                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;
+
+       // Save the values in the header, if the caller wanted them
+       if (ehdr_out)
+               *ehdr_out = *ehdr;
+
        elf_end(elf);
-       return ehdr->e_entry;
+       if (highest)
+               *highest = kern_end;
+       return ret;
 fail:
        close(fd);
        elf_end(elf);