vmm: remove verbose output
[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 <parlib/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. The reference parameter records the highest
14  * address we wrote. The initrd can go there.*/
15 uintptr_t load_elf(char *filename, uint64_t offset, uint64_t *highest,
16                    Elf64_Ehdr *ehdr_out)
17 {
18         Elf64_Ehdr *ehdr;
19         Elf *elf;
20         size_t phnum = 0;
21         Elf64_Phdr *hdrs;
22         int fd;
23         uintptr_t ret;
24         uintptr_t kern_end = 0;
25
26         elf_version(EV_CURRENT);
27         fd = open(filename, O_RDONLY);
28         if (fd < 0) {
29                 fprintf(stderr, "Can't open %s: %r\n", filename);
30                 return 0;
31         }
32
33         elf = elf_begin(fd, ELF_C_READ, NULL);
34         if (elf == NULL) {
35                 fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__,
36                         filename);
37                 close(fd);
38                 return 0;
39         }
40
41         ehdr = elf64_getehdr(elf);
42         if (ehdr == NULL) {
43                 fprintf(stderr, "%s: cannot get exec header of %s.\n",
44                         __func__, filename);
45                 goto fail;
46         }
47
48         if (elf_getphdrnum(elf, &phnum) < 0) {
49                 fprintf(stderr, "%s: cannot get program header num of %s.\n",
50                         __func__, filename);
51                 goto fail;
52         }
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                 printd("%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",
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                 printd("Read header %d @offset %p to %p (elf PA is %p) %d bytes:",
83                        i, h->p_offset, pa, h->p_paddr, h->p_filesz);
84                 tot = 0;
85                 while (tot < h->p_filesz) {
86                         int amt = pread(fd, (void *)(pa + tot + offset),
87                                         h->p_filesz - tot, h->p_offset + tot);
88
89                         if (amt < 1)
90                                 break;
91                         tot += amt;
92                 }
93                 if (tot < h->p_filesz) {
94                         fprintf(stderr, "%s: got %d bytes, wanted %d bytes\n",
95                                 filename, tot, h->p_filesz);
96                         goto fail;
97                 }
98                 if ((h->p_paddr + h->p_memsz) > kern_end)
99                         kern_end = h->p_paddr + h->p_memsz;
100         }
101
102         close(fd);
103         ret = ehdr->e_entry + offset;
104
105         // Save the values in the header, if the caller wanted them
106         if (ehdr_out)
107                 *ehdr_out = *ehdr;
108
109         elf_end(elf);
110         if (highest)
111                 *highest = kern_end;
112         return ret;
113 fail:
114         close(fd);
115         elf_end(elf);
116         return 0;
117 }