1/**
2 * \file
3 * \brief Rudimentary ELF64 loader and handling routines.
4 *
5 * Note that on 32-bit platforms, this loader is only able to load
6 * ELF64 files that it can address (ie. those that are not bigger than
7 * what fits into a 32-bit address space).
8 */
9
10/*
11 * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich.
12 * All rights reserved.
13 *
14 * This file is distributed under the terms in the attached LICENSE file.
15 * If you do not find this file, copies can be found by writing to:
16 * ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich,
17 * Attn: Systems Group.
18 */
19
20/* Restricted includes, because this file is used in three environments:
21 * in the preboot loader tool "elver", in 32-bit mode
22 * in-kernel, 64-bit mode
23 * userspace, 64-bit mode
24 */
25#include <assert.h>
26#include <stdio.h>
27#include <stdint.h>
28#include <stddef.h>
29#include <string.h>
30#include <barrelfish_kpi/paging_arch.h>
31#include <barrelfish_kpi/types.h>
32#include <errors/errno.h>
33#include <elf/elf.h>
34
35#define XEON_PHI_SBOX_BASE           0x08007D0000ULL     /* PCIE Box Registers */
36union status
37{
38    uint32_t raw;
39    char vals[4];
40};
41
42static void
43print_status(char a,
44             char b)
45{
46
47    volatile uint32_t *p = (volatile uint32_t *) ((XEON_PHI_SBOX_BASE) + 0x0000AB40);
48    volatile uint32_t *p2 = (volatile uint32_t *) ((XEON_PHI_SBOX_BASE) + 0x0000AB5C);
49
50    union status s;
51
52    s.vals[3] = 0x0a;
53    s.vals[2] = b;
54    s.vals[1] = a;
55    s.vals[0] = '>';
56
57    while ((*p))
58        ;
59
60    *p2 = s.raw;
61    *p = 0x7A7A7A7A;
62}
63
64static inline void
65eabort(char a,
66       char b)
67{
68    print_status(a, b);
69    while (1)
70        ;
71}
72
73
74
75/**
76 * \brief Calculates the base of the loadable portion of the elf image in
77 * virtual memory.
78 */
79genvaddr_t elf_virtual_base64(struct Elf64_Ehdr *ehead)
80{
81    struct Elf64_Phdr *phead =
82        (struct Elf64_Phdr *)((uintptr_t)ehead + (uintptr_t)ehead->e_phoff);
83
84    genvaddr_t retval = 0;
85    int i;
86
87    for (i = 0; i < ehead->e_phnum; i++) {
88        struct Elf64_Phdr *p = &phead[i];
89        if (p->p_type == PT_LOAD) {
90            if(retval == 0) {
91                retval = p->p_vaddr;
92            }
93            retval = p->p_vaddr < retval ? p->p_vaddr : retval;
94        }
95    }
96
97    return retval;
98}
99
100/**
101 * \brief Return pointer to relocation section ELF header.
102 *
103 * This function finds and returns a pointer to the first ELF section
104 * header of type 'type'.
105 *
106 * \param shdr          Pointer to head of ELF section header table.
107 * \param entries       Number of entries in the ELF section header table.
108 * \param type          ELF section header type to look for.
109 *
110 * \return Pointer to first ELF section header of type 'type', or NULL.
111 */
112struct Elf64_Shdr *
113elf64_find_section_header_type(struct Elf64_Shdr * shdr,
114                               uint32_t entries, uint32_t type)
115{
116    int i;
117
118    for(i = 0; i < entries; i++) {
119        struct Elf64_Shdr *s = &shdr[i];
120
121        if(s->sh_type == type) {
122            return s;
123        }
124    }
125
126    return NULL;
127}
128
129/**
130 * \brief Return pointer to section header with given name.
131 *
132 * @param elf_base      Address of ELF header
133 * @param elf_bytes     Size of ELF file.
134 * @param section_name  Named section to look for.
135 *
136 * @return Pointer to ELF section header with name, or NULL.
137 */
138struct Elf64_Shdr *
139elf64_find_section_header_name(genvaddr_t  elf_base,
140                               size_t      elf_bytes,
141                               const char* section_name)
142{
143    lvaddr_t elf_lbase = (lvaddr_t)elf_base;
144    struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)elf_lbase;
145
146    if (elf_bytes < sizeof(struct Elf64_Ehdr) || !IS_ELF(*head) ||
147        head->e_ident[EI_CLASS] != ELFCLASS64) {
148        return NULL;
149    }
150
151    struct Elf64_Shdr *shead =
152        (struct Elf64_Shdr *)(elf_lbase + (uintptr_t)head->e_shoff);
153
154    struct Elf64_Shdr *strtab =
155        elf64_find_section_header_type(shead, head->e_shnum, SHT_STRTAB);
156
157    if (strtab == NULL)
158    {
159        return NULL;
160    }
161
162    for (uint32_t i = 0; i < head->e_shnum; i++)
163    {
164        const char* strings = (const char*)(elf_lbase +
165                                            (size_t)strtab->sh_offset);
166        if (!strcmp(section_name, strings + shead[i].sh_name)) {
167            return &shead[i];
168        }
169    }
170    return NULL;
171}
172
173/**
174 * \brief Return pointer to relocation section ELF header.
175 *
176 * This function finds and returns a pointer to the first ELF section
177 * header at virtual address 'addr'.
178 *
179 * \param shdr          Pointer to head of ELF section header table.
180 * \param entries       Number of entries in the ELF section header table.
181 * \param addr          Virtual address to look for
182 *
183 * \return Pointer to first ELF section header loaded at 'addr', or NULL.
184 */
185static struct Elf64_Shdr *
186elf64_find_section_header_vaddr(struct Elf64_Shdr * shdr,
187                                uint32_t entries, genvaddr_t addr)
188{
189    int i;
190
191    for(i = 0; i < entries; i++) {
192        struct Elf64_Shdr *s = &shdr[i];
193
194        if(s->sh_addr == addr) {
195            return s;
196        }
197    }
198
199    return NULL;
200}
201
202/**
203 * \brief Relocates the ELF image from src to dst.
204 *
205 * This function processes the ELF relocation section 'rela' of size 'size' of
206 * the ELF image, formerly located at 'src', to the new location 'dst'.
207 * Relocation is necessary for certain variables that cannot be coded as
208 * position-independent code.
209 *
210 * \param dst           Address to relocate to.
211 * \param src           Former base address of the ELF image.
212 * \param rela          Pointer to relocation section of the ELF image.
213 * \param size          Size in bytes of the ELF relocation section.
214 * \param symtab        Pointer to ELF symbol table.
215 * \param symsize       Size in bytes of the ELF symbol table.
216 * \param start         Original base address of the ELF image (needed for
217 * symbol-table-based relocations -- we don't touch the symbol table).
218 * \param vbase         Pointer to ELF image in virtual memory.
219 */
220void elf64_relocate(genvaddr_t dst, genvaddr_t src,
221                    struct Elf64_Rela * rela, size_t size,
222                    struct Elf64_Sym * symtab, size_t symsize,
223                    genvaddr_t start, void *vbase)
224{
225    genvaddr_t base = dst - src, abase = dst - start;
226
227    for(int i = 0; i < size / sizeof(struct Elf64_Rela); i++) {
228        struct Elf64_Rela *r = &rela[i];
229        uint32_t type = ELF64_R_TYPE(r->r_info);
230        uint64_t *addr = (uint64_t *)((char *)vbase + r->r_offset - start);
231
232        switch(type) {
233        case R_X86_64_NONE:
234            // Do nothing
235            break;
236
237        case R_X86_64_64:{
238            uint32_t sym = ELF64_R_SYM(r->r_info);
239            assert(sym < symsize / sizeof(struct Elf64_Sym));
240#if 0 // XXX: symbols should be 0 but this fires sometimes
241            assert(symtab[sym].st_value != 0);
242#endif
243            *addr = abase + symtab[sym].st_value + r->r_addend;
244            break;}
245
246        case R_X86_64_RELATIVE:
247            // FIXME: why doesn't the following work? -AB
248            // I don't think this makes sense. It is a relative
249            // relocation from the old position. Thus, base and not
250            // abase should be used. Further, since r->r_addend is not
251            // updated between relocations, this will fail as soon as
252            // a binary is relocated more than once. -SP
253            //*addr = abase + r->r_addend;
254            *addr += base;
255            break;
256
257        default:
258            eabort('E','x');
259            printf("elf_relocate: relocation %d type %"PRIu32"\n", i, type);
260            assert(!"Unimplemented: Cannot handle relocation type");
261            break;
262        }
263    }
264}
265
266/**
267 * \brief Load ELF64 binary image into memory
268 *
269 * This function loads an ELF64 binary image, based at 'base' and of size
270 * 'size' into the memory provided by 'allocate'
271 *
272 * \param em_machine    ELF machine type.
273 * \param allocate      Memory allocation function.
274 * \param state         Pointer to state for allocation function.
275 * \param base          Base address of ELF64 binary image in memory.
276 * \param size          Size of ELF64 binary image in bytes.
277 * \param retentry      Used to return entry point address
278 * \param ret_tlsbase   Used to return TLS block base address
279 * \param ret_tlsinitlen Used to return length of initialised TLS data block
280 * \param ret_tlstotallen Used to return total length of TLS data
281 */
282errval_t elf64_load(uint16_t em_machine, elf_allocator_fn allocate_func,
283                    void *state, lvaddr_t base, size_t size,
284                    genvaddr_t *retentry,
285                    genvaddr_t *ret_tlsbase, size_t *ret_tlsinitlen,
286                    size_t *ret_tlstotallen)
287{
288    struct Elf64_Ehdr   *head = (struct Elf64_Ehdr *)base;
289    errval_t err;
290    int i;
291
292    // Check for valid file size
293    if (size < sizeof(struct Elf64_Ehdr)) {
294        return ELF_ERR_FILESZ;
295    }
296
297    // Check for compatible ELF64 header
298    if (!IS_ELF(*head)
299        || head->e_ident[EI_CLASS] != ELFCLASS64
300        || head->e_ident[EI_DATA] != ELFDATA2LSB
301        || head->e_ident[EI_VERSION] != EV_CURRENT
302        || head->e_ident[EI_OSABI] != ELFOSABI_SYSV
303        || head->e_ident[EI_ABIVERSION] != 0
304        || (head->e_type != ET_EXEC && head->e_type != ET_DYN)
305        || head->e_machine != em_machine
306        || head->e_version != EV_CURRENT) {
307        return ELF_ERR_HEADER;
308    }
309
310    // More sanity checks
311    if (head->e_phoff + head->e_phentsize * head->e_phnum > size
312        || head->e_phentsize != sizeof(struct Elf64_Phdr)) {
313        return ELF_ERR_PROGHDR;
314    }
315
316    struct Elf64_Shdr *shead =
317        (struct Elf64_Shdr *)(base + (uintptr_t)head->e_shoff);
318    struct Elf64_Shdr *rela =
319        elf64_find_section_header_type(shead, head->e_shnum, SHT_RELA);
320    struct Elf64_Shdr *symtab =
321        elf64_find_section_header_type(shead, head->e_shnum, SHT_SYMTAB);
322
323    size_t rela_size = rela ? rela->sh_size : 0, new_rela_size = 0;
324    struct Elf64_Shdr *new_rela = NULL;
325
326    // Find dynamic program header, if any
327    struct Elf64_Phdr *phead =
328        (struct Elf64_Phdr *)(base + (uintptr_t)head->e_phoff);
329    for (i = 0; i < head->e_phnum; i++) {
330        struct Elf64_Phdr *p = &phead[i];
331
332        if (p->p_type == PT_DYNAMIC) {
333            struct Elf64_Dyn *dynamic = (void *)(base + (uintptr_t)p->p_offset);
334            int n_dynamic = p->p_filesz / sizeof(struct Elf64_Dyn);
335            for (int j = 0; j < n_dynamic; j++) {
336                switch (dynamic[j].d_tag) {
337                case DT_RELA:
338                    // virtual address of relocations, look for matching section
339                    new_rela =
340                        elf64_find_section_header_vaddr(shead, head->e_shnum,
341                                                        dynamic[j].d_un.d_val);
342                    break;
343
344                case DT_RELASZ:
345                    // store size of relocations, as they may cover more than
346                    // one section
347                    new_rela_size = dynamic[j].d_un.d_val;
348                    break;
349
350                case DT_SYMTAB:
351                    // virtual address of symtab, look for matching section
352                    symtab =
353                        elf64_find_section_header_vaddr(shead, head->e_shnum,
354                                                        dynamic[j].d_un.d_val);
355                    break;
356
357                case DT_SYMENT:
358                    assert(dynamic[j].d_un.d_val == sizeof(struct Elf64_Sym));
359                    break;
360                }
361            }
362
363            if (new_rela != NULL) {
364                assert(new_rela_size != 0);
365                rela = new_rela;
366                rela_size = new_rela_size;
367            }
368            break;
369        }
370    }
371
372
373    genvaddr_t tls_base = 0;
374    size_t tls_init_len = 0, tls_total_len = 0;
375
376    // Process program headers to load file
377    for (i = 0; i < head->e_phnum; i++) {
378        struct Elf64_Phdr *p = &phead[i];
379        if (p->p_type == PT_LOAD) {
380
381            // Map segment in user-space memory
382            void *dest = NULL;
383            err = allocate_func(state, p->p_vaddr, p->p_memsz, p->p_flags, &dest);
384
385            if (err_is_fail(err)) {
386                return err_push(err, ELF_ERR_ALLOCATE);
387            }
388            assert(dest != NULL);
389            // Copy file segment into memory
390            memcpy(dest, (void *)(base + (uintptr_t)p->p_offset), p->p_filesz);
391
392            // Initialize rest of memory segment (ie. BSS) with all zeroes
393            memset((char *)dest + p->p_filesz, 0, p->p_memsz - p->p_filesz);
394
395            // Apply relocations
396            if (rela != NULL && symtab != NULL) {
397                elf64_relocate(p->p_vaddr, p->p_vaddr,
398                               (struct Elf64_Rela *)
399                               (base + (uintptr_t)rela->sh_offset),
400                               rela_size,
401                               (struct Elf64_Sym *)
402                               (base + (uintptr_t)symtab->sh_offset),
403                               symtab->sh_size, p->p_vaddr, dest);
404            }
405        } else if (p->p_type == PT_TLS) {
406            assert(p->p_vaddr != 0);
407            assert(tls_base == 0); // if not we have multiple TLS sections!
408            tls_base = p->p_vaddr;
409            tls_init_len = p->p_filesz;
410            tls_total_len = p->p_memsz;
411        }
412    }
413
414    if (retentry != NULL) {
415        *retentry = head->e_entry;
416    }
417
418    if (ret_tlsbase != NULL) {
419        *ret_tlsbase = tls_base;
420    }
421
422    if (ret_tlsinitlen != NULL) {
423        *ret_tlsinitlen = tls_init_len;
424    }
425
426    if (ret_tlstotallen != NULL) {
427        *ret_tlstotallen = tls_total_len;
428    }
429
430    return SYS_ERR_OK;
431}
432