1/**
2 * \file
3 * \brief Rudimentary ELF loader and handling routines.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15/* Restricted includes, because this file is used in three environments:
16 * in the preboot loader tool "elver", in 32-bit mode
17 * in-kernel, 64-bit mode
18 * userspace, 64-bit mode
19 */
20#include <stddef.h>
21#include <stdint.h>
22#include <barrelfish_kpi/paging_arch.h>
23#include <barrelfish_kpi/types.h>
24#include <errors/errno.h>
25#include <elf/elf.h>
26
27/**
28 * \brief Load ELF binary image into memory
29 *
30 * This function loads an ELF binary image, based at 'base' and of size
31 * 'size' into the memory provided by 'allocate'
32 *
33 * \param em_machine    ELF machine type.
34 * \param allocate      Memory allocation function.
35 * \param state         Pointer to state for allocation function.
36 * \param base          Base address of ELF binary image in memory.
37 * \param size          Size of ELF binary image in bytes.
38 * \param retentry      Used to return entry point address
39 * \param ret_tlsbase   Used to return TLS block base address
40 * \param ret_tlssize   Used to return TLS block size
41 */
42errval_t elf_load_tls(uint16_t em_machine, elf_allocator_fn allocate_func,
43                      void *state, lvaddr_t base,
44                      size_t size, genvaddr_t *retentry,
45                      genvaddr_t *ret_tlsbase, size_t *ret_tlsinitlen,
46                      size_t *ret_tlstotallen)
47{
48    struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)base;
49
50    if(!IS_ELF(*head)) {
51        return ELF_ERR_HEADER;
52    }
53
54    switch(head->e_ident[EI_CLASS]) {
55    case ELFCLASS32:
56        return elf32_load(em_machine, allocate_func, state, base, size,
57                          retentry, ret_tlsbase, ret_tlsinitlen, ret_tlstotallen);
58
59    case ELFCLASS64:
60        return elf64_load(em_machine, allocate_func, state, base, size,
61                          retentry, ret_tlsbase, ret_tlsinitlen, ret_tlstotallen);
62    }
63
64    return ELF_ERR_HEADER;
65}
66
67errval_t elf_load(uint16_t em_machine, elf_allocator_fn allocate_func,
68                  void *state, lvaddr_t base,
69                  size_t size, genvaddr_t *retentry)
70{
71    return elf_load_tls(em_machine, allocate_func, state, base, size,
72                        retentry, NULL, NULL, NULL);
73}
74
75static size_t elf_virtual_size64(struct Elf64_Ehdr *ehead)
76{
77    struct Elf64_Phdr *phead =
78        (struct Elf64_Phdr *)((uintptr_t)ehead + (uintptr_t)ehead->e_phoff);
79
80    size_t retval = 0;
81    int i;
82
83    for (i = 0; i < ehead->e_phnum; i++) {
84        struct Elf64_Phdr *p = &phead[i];
85        if (p->p_type == PT_LOAD) {
86            retval = p->p_vaddr + p->p_memsz;
87        }
88    }
89
90    return retval - elf_virtual_base64(ehead);
91}
92
93static size_t elf_virtual_size32(struct Elf32_Ehdr *ehead)
94{
95    struct Elf32_Phdr *phead =
96        (struct Elf32_Phdr *)((uintptr_t)ehead + (uintptr_t)ehead->e_phoff);
97
98    size_t retval = 0;
99    int i;
100
101    for (i = 0; i < ehead->e_phnum; i++) {
102        struct Elf32_Phdr *p = &phead[i];
103        if (p->p_type == PT_LOAD) {
104            retval = p->p_vaddr + p->p_memsz;
105        }
106    }
107
108    return retval - elf_virtual_base32(ehead);
109}
110
111/**
112 * \brief Calculates the size of the loadable portion of the elf image in
113 * virtual memory. This is the amount of virtual memory required to load an
114 * image.
115 */
116size_t elf_virtual_size(lvaddr_t base)
117{
118    size_t elfsize = 0;
119
120    struct Elf64_Ehdr *ehead = (struct Elf64_Ehdr *)base;
121    if (IS_ELF(*ehead)) {
122        switch (ehead->e_ident[EI_CLASS]) {
123          case ELFCLASS64:
124            elfsize = elf_virtual_size64(ehead);
125            break;
126
127          case ELFCLASS32:
128            elfsize = elf_virtual_size32((struct Elf32_Ehdr*)ehead);
129            break;
130        }
131    }
132
133    return elfsize;
134}
135
136/**
137 * \brief Calculates the base of the loadable portion of the elf image in
138 * virtual memory.
139 */
140genvaddr_t elf_virtual_base(lvaddr_t base)
141{
142    genvaddr_t elfbase = 0;
143
144    struct Elf64_Ehdr *ehead = (struct Elf64_Ehdr *)base;
145    if (IS_ELF(*ehead)) {
146        switch (ehead->e_ident[EI_CLASS]) {
147          case ELFCLASS64:
148            elfbase = elf_virtual_base64(ehead);
149            break;
150
151          case ELFCLASS32:
152            elfbase = elf_virtual_base32((struct Elf32_Ehdr*)ehead);
153            break;
154        }
155    }
156
157    return elfbase;
158}
159
160static errval_t elf32_get_eh_info(lvaddr_t elfbase, size_t elfsize,
161                                  lvaddr_t *eh_frame, size_t *eh_frame_size,
162                                  lvaddr_t *eh_frame_hdr, size_t *eh_frame_hdr_size)
163{
164    struct Elf32_Shdr *shdr;
165
166    lvaddr_t addr = 0;
167    size_t size = 0;
168
169    shdr= elf32_find_section_header_name(elfbase, elfsize, ".eh_frame");
170    if (shdr != NULL) {
171        size = shdr->sh_size;
172        addr = shdr->sh_addr;
173    }
174
175    if (eh_frame) {
176        *eh_frame = addr;
177    }
178    if (eh_frame_size) {
179        *eh_frame_size = size;
180    }
181
182    size = 0;
183    addr = 0;
184
185    shdr= elf32_find_section_header_name(elfbase, elfsize, ".eh_frame_hdr");
186    if (shdr != NULL) {
187        size = shdr->sh_size;
188        addr = shdr->sh_addr;
189    }
190
191    if (eh_frame_hdr) {
192        *eh_frame_hdr = addr;
193    }
194    if (eh_frame_hdr_size) {
195        *eh_frame_hdr_size = size;
196    }
197
198    return SYS_ERR_OK;
199}
200
201static errval_t elf64_get_eh_info(lvaddr_t elfbase, size_t elfsize,
202                                  lvaddr_t *eh_frame, size_t *eh_frame_size,
203                                  lvaddr_t *eh_frame_hdr, size_t *eh_frame_hdr_size)
204{
205    struct Elf64_Shdr *shdr;
206
207    lvaddr_t addr = 0;
208    size_t size = 0;
209
210    shdr= elf64_find_section_header_name(elfbase, elfsize, ".eh_frame");
211    if (shdr != NULL) {
212        size = shdr->sh_size;
213        addr = shdr->sh_addr;
214    }
215
216    if (eh_frame) {
217        *eh_frame = addr;
218    }
219    if (eh_frame_size) {
220        *eh_frame_size = size;
221    }
222
223    size = 0;
224    addr = 0;
225
226    shdr= elf64_find_section_header_name(elfbase, elfsize, ".eh_frame_hdr");
227    if (shdr != NULL) {
228        size = shdr->sh_size;
229        addr = shdr->sh_addr;
230    }
231
232    if (eh_frame_hdr) {
233        *eh_frame_hdr = addr;
234    }
235    if (eh_frame_hdr_size) {
236        *eh_frame_hdr_size = size;
237    }
238
239    return SYS_ERR_OK;
240}
241
242/**
243 * \brief obtains the error handling frame information form the elf image
244 *
245 * \param elfbase            virtual base address of the mapped elf
246 * \param elfsize            size of the elf in bytes
247 * \param eh_frame           returns the virtual address of the eh_frame
248 * \param eh_frame_size      returns the size of the eh_frame
249 * \param eh_frame_hdr       returns the virtual address of the eh_frame_hdr
250 * \param eh_frame_hdr_size  returns the size of the eh_frame_hdr
251 *
252 * \returns SYS_ERR_OK on success
253 */
254errval_t elf_get_eh_info(lvaddr_t elfbase, size_t elfsize,
255                         lvaddr_t *eh_frame, size_t *eh_frame_size,
256                         lvaddr_t *eh_frame_hdr, size_t *eh_frame_hdr_size)
257{
258    struct Elf64_Ehdr *ehead = (struct Elf64_Ehdr *)elfbase;
259    if (IS_ELF(*ehead)) {
260        switch (ehead->e_ident[EI_CLASS]) {
261          case ELFCLASS64:
262            return elf64_get_eh_info(elfbase, elfsize, eh_frame, eh_frame_size,
263                                     eh_frame_hdr, eh_frame_hdr_size);
264            break;
265          case ELFCLASS32:
266            return  elf32_get_eh_info(elfbase, elfsize, eh_frame, eh_frame_size,
267                                      eh_frame_hdr, eh_frame_hdr_size);
268            break;
269        }
270    }
271    return ELF_ERR_HEADER;
272}
273