user/vmm: add and use a load_elf function
[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)
16 {
17         Elf64_Ehdr *ehdr;
18         Elf *elf;
19         size_t phnum = 0;
20         Elf64_Phdr *hdrs;
21         int fd;
22
23         elf_version(EV_CURRENT);
24         fd = open(filename, O_RDONLY);
25         if (fd < 0) {
26                 fprintf(stderr, "Can't open %s: %r\n", filename);
27                 return 0;
28         }
29
30         elf = elf_begin(fd, ELF_C_READ, NULL);
31         if (elf == NULL) {
32                 fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__, filename);
33                 close(fd);
34                 return 0;
35         }
36
37         ehdr = elf64_getehdr(elf);
38         if (ehdr == NULL) {
39                 fprintf(stderr, "%s: cannot get exec header of %s.\n",
40                         __func__, filename);
41                 goto fail;
42         }
43         fprintf(stderr, "%s ELF entry point is %p\n", filename,
44                 (void *)ehdr->e_entry);
45
46         if (elf_getphdrnum(elf, &phnum) < 0) {
47                 fprintf(stderr, "%s: cannot get program header num of %s.\n",
48                         __func__, filename);
49                 goto fail;
50         }
51         fprintf(stderr, "%s has %p program headers\n", filename, phnum);
52
53         hdrs = elf64_getphdr(elf);
54         if (hdrs == NULL) {
55                 fprintf(stderr, "%s: cannot get program headers of %s.\n",
56                         __func__, filename);
57                 goto fail;
58         }
59
60         for (int i = 0; i < phnum; i++) {
61                 size_t tot;
62                 Elf64_Phdr *h = &hdrs[i];
63                 uintptr_t pa;
64
65                 fprintf(stderr,
66                         "%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",
67                         i,
68                         h->p_type,              /* Segment type */
69                         h->p_flags,             /* Segment flags */
70                         h->p_offset,            /* Segment file offset */
71                         h->p_vaddr,             /* Segment virtual address */
72                         h->p_paddr,             /* Segment physical address */
73                         h->p_filesz,            /* Segment size in file */
74                         h->p_memsz,             /* Segment size in memory */
75                         h->p_align              /* Segment alignment */);
76                 if (h->p_type != PT_LOAD)
77                         continue;
78                 if ((h->p_flags & (PF_R | PF_W | PF_X)) == 0)
79                         continue;
80
81                 pa = h->p_paddr;
82                 fprintf(stderr,
83                         "Read header %d @offset %p to %p (elf PA is %p) %d bytes:",
84                         i, h->p_offset, pa, h->p_paddr, h->p_filesz);
85                 tot = 0;
86                 while (tot < h->p_filesz) {
87                         int amt = pread(fd, (void *)(pa + tot), h->p_filesz - tot,
88                                         h->p_offset + tot);
89
90                         if (amt < 1)
91                                 break;
92                         tot += amt;
93                 }
94                 fprintf(stderr, "read a total of %d bytes\n", tot);
95                 if (tot < h->p_filesz) {
96                         fprintf(stderr, "%s: got %d bytes, wanted %d bytes\n",
97                                 filename, tot, h->p_filesz);
98                         goto fail;
99                 }
100         }
101
102         close(fd);
103         elf_end(elf);
104         return ehdr->e_entry;
105 fail:
106         close(fd);
107         elf_end(elf);
108         return 0;
109 }