vmm: Modifed load_elf to allow an offset
[akaros.git] / user / vmm / load_elf.c
1 /* Copyright (c) 2017 Google Inc.
2  * See LICENSE for details.
3  *
4  * ELF loading. */
5
6 #include <stdio.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <libelf.h>
10
11 /* load_elf loads and ELF file. This is almost always a kernel.
12  * We assume that memory is set up correctly, and it will go hard
13  * with you if it is not. */
14 uintptr_t
15 load_elf(char *filename, uint64_t offset)
16 {
17         Elf64_Ehdr *ehdr;
18         Elf *elf;
19         size_t phnum = 0;
20         Elf64_Phdr *hdrs;
21         int fd;
22         uintptr_t ret;
23
24         elf_version(EV_CURRENT);
25         fd = open(filename, O_RDONLY);
26         if (fd < 0) {
27                 fprintf(stderr, "Can't open %s: %r\n", filename);
28                 return 0;
29         }
30
31         elf = elf_begin(fd, ELF_C_READ, NULL);
32         if (elf == NULL) {
33                 fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__, filename);
34                 close(fd);
35                 return 0;
36         }
37
38         ehdr = elf64_getehdr(elf);
39         if (ehdr == NULL) {
40                 fprintf(stderr, "%s: cannot get exec header of %s.\n",
41                         __func__, filename);
42                 goto fail;
43         }
44         fprintf(stderr, "%s ELF entry point is %p\n", filename,
45                 (void *)ehdr->e_entry);
46
47         if (elf_getphdrnum(elf, &phnum) < 0) {
48                 fprintf(stderr, "%s: cannot get program header num of %s.\n",
49                         __func__, filename);
50                 goto fail;
51         }
52         fprintf(stderr, "%s has %p program headers\n", filename, phnum);
53
54         hdrs = elf64_getphdr(elf);
55         if (hdrs == NULL) {
56                 fprintf(stderr, "%s: cannot get program headers of %s.\n",
57                         __func__, filename);
58                 goto fail;
59         }
60
61         for (int i = 0; i < phnum; i++) {
62                 size_t tot;
63                 Elf64_Phdr *h = &hdrs[i];
64                 uintptr_t pa;
65
66                 fprintf(stderr,
67                         "%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",
68                         i,
69                         h->p_type,              /* Segment type */
70                         h->p_flags,             /* Segment flags */
71                         h->p_offset,            /* Segment file offset */
72                         h->p_vaddr,             /* Segment virtual address */
73                         h->p_paddr,             /* Segment physical address */
74                         h->p_filesz,            /* Segment size in file */
75                         h->p_memsz,             /* Segment size in memory */
76                         h->p_align              /* Segment alignment */);
77                 if (h->p_type != PT_LOAD)
78                         continue;
79                 if ((h->p_flags & (PF_R | PF_W | PF_X)) == 0)
80                         continue;
81
82                 pa = h->p_paddr;
83                 fprintf(stderr,
84                         "Read header %d @offset %p to %p (elf PA is %p) %d bytes:",
85                         i, h->p_offset, pa, h->p_paddr, h->p_filesz);
86                 tot = 0;
87                 while (tot < h->p_filesz) {
88                         int amt = pread(fd, (void *)(pa + tot + offset), h->p_filesz - tot,
89                                         h->p_offset + tot);
90
91                         if (amt < 1)
92                                 break;
93                         tot += amt;
94                 }
95                 fprintf(stderr, "read a total of %d bytes\n", tot);
96                 if (tot < h->p_filesz) {
97                         fprintf(stderr, "%s: got %d bytes, wanted %d bytes\n",
98                                 filename, tot, h->p_filesz);
99                         goto fail;
100                 }
101         }
102
103         close(fd);
104         ret = ehdr->e_entry + offset;
105         elf_end(elf);
106         return ret;
107 fail:
108         close(fd);
109         elf_end(elf);
110         return 0;
111 }