1/**
2 * \file
3 * \brief functionality to spawn domains
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <string.h>
16#include <stdio.h>
17#include <inttypes.h>
18#include <barrelfish/barrelfish.h>
19#include <spawndomain/spawndomain.h>
20#include <barrelfish/dispatcher_arch.h>
21#include <elf/elf.h>
22#include "../../spawn.h"
23#include "../../arch.h"
24
25#if defined(__i386__)
26#define EM_HOST EM_386
27#elif defined(__k1om__)
28#define EM_HOST EM_K1OM
29#elif defined(__x86_64__)
30#define EM_HOST EM_X86_64
31#else
32#error "Unexpected architecture."
33#endif
34
35/**
36 * \brief Convert elf flags to vregion flags
37 */
38static vregion_flags_t elf_to_vregion_flags(uint32_t flags)
39{
40    vregion_flags_t vregion_flags = 0;
41
42    if (flags & PF_R) {
43        vregion_flags |= VREGION_FLAGS_READ;
44    }
45    if (flags & PF_W) {
46        vregion_flags |= VREGION_FLAGS_WRITE;
47    }
48    if (flags & PF_X) {
49        vregion_flags |= VREGION_FLAGS_EXECUTE;
50    }
51
52    return vregion_flags;
53}
54
55static errval_t elf_allocate(void *state, genvaddr_t base, size_t size,
56                             uint32_t flags, void **retbase)
57{
58    errval_t err;
59
60    struct spawninfo *si = state;
61
62    // Increase size by space wasted on first page due to page-alignment
63    size_t base_offset = BASE_PAGE_OFFSET(base);
64    size += base_offset;
65    base -= base_offset;
66    // Page-align
67    size = ROUND_UP(size, BASE_PAGE_SIZE);
68
69    cslot_t vspace_slot = si->elfload_slot;
70    cslot_t spawn_vspace_slot = si->elfload_slot;
71
72    // Allocate the frames
73    size_t sz = 0;
74    for (lpaddr_t offset = 0; offset < size; offset += sz) {
75        sz = 1UL << log2floor(size - offset);
76        struct capref frame = {
77            .cnode = si->segcn,
78            .slot  = si->elfload_slot++,
79        };
80        err = frame_create(frame, sz, NULL);
81        if (err_is_fail(err)) {
82            return err_push(err, LIB_ERR_FRAME_CREATE);
83        }
84    }
85
86    /* Map into my vspace */
87    struct memobj *memobj = malloc(sizeof(struct memobj_anon));
88    if (!memobj) {
89        return LIB_ERR_MALLOC_FAIL;
90    }
91    struct vregion *vregion = malloc(sizeof(struct vregion));
92    if (!vregion) {
93        return LIB_ERR_MALLOC_FAIL;
94    }
95    // Create the objects
96    err = memobj_create_anon((struct memobj_anon*)memobj, size, 0);
97    if (err_is_fail(err)) {
98        return err_push(err, LIB_ERR_MEMOBJ_CREATE_ANON);
99    }
100    err = vregion_map(vregion, get_current_vspace(), memobj, 0, size,
101                      VREGION_FLAGS_READ_WRITE);
102    if (err_is_fail(err)) {
103        return err_push(err, LIB_ERR_VSPACE_MAP);
104    }
105    for (lvaddr_t offset = 0; offset < size; offset += sz) {
106        sz = 1UL << log2floor(size - offset);
107        struct capref frame = {
108            .cnode = si->segcn,
109            .slot  = vspace_slot++,
110        };
111        genvaddr_t genvaddr = vspace_lvaddr_to_genvaddr(offset);
112        err = memobj->f.fill(memobj, genvaddr, frame, sz);
113        if (err_is_fail(err)) {
114            return err_push(err, LIB_ERR_MEMOBJ_FILL);
115        }
116        err = memobj->f.pagefault(memobj, vregion, offset, 0);
117        if (err_is_fail(err)) {
118            DEBUG_ERR(err, "lib_err_memobj_pagefault_handler");
119            return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
120        }
121    }
122
123    /* Map into spawn vspace */
124    struct memobj *spawn_memobj = NULL;
125    struct vregion *spawn_vregion = NULL;
126    err = spawn_vspace_map_anon_fixed_attr(si, base, size, &spawn_vregion,
127                                           &spawn_memobj,
128                                           elf_to_vregion_flags(flags));
129    if (err_is_fail(err)) {
130        return err_push(err, SPAWN_ERR_VSPACE_MAP);
131    }
132    for (lvaddr_t offset = 0; offset < size; offset += sz) {
133        sz = 1UL << log2floor(size - offset);
134        struct capref frame = {
135            .cnode = si->segcn,
136            .slot = spawn_vspace_slot++,
137        };
138        err = memobj->f.fill(spawn_memobj, offset, frame, sz);
139        if (err_is_fail(err)) {
140            return err_push(err, LIB_ERR_MEMOBJ_FILL);
141        }
142        err = spawn_memobj->f.pagefault(spawn_memobj, spawn_vregion, offset, 0);
143        if (err_is_fail(err)) {
144            DEBUG_ERR(err, "lib_err_memobj_pagefault_handler");
145            return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
146        }
147    }
148
149    si->vregion[si->vregions] = vregion;
150    si->base[si->vregions++] = base;
151
152    genvaddr_t genvaddr = vregion_get_base_addr(vregion) + base_offset;
153    *retbase = (void*)vspace_genvaddr_to_lvaddr(genvaddr);
154    return SYS_ERR_OK;
155}
156
157static errval_t spawn_parse_omp_functions(const char *name,
158                                          lvaddr_t binary, size_t binary_size)
159{
160    errval_t err;
161    genvaddr_t value;
162    err = spawn_symval_lookup(name, 0, NULL, &value);
163    if (err_is_ok(err)) {
164        return SYS_ERR_OK;
165    }
166
167    uint32_t count = 0;
168
169    struct Elf64_Sym *sym = NULL;
170    struct Elf64_Shdr *shead;
171    struct Elf64_Shdr *symtab;
172    const char *symname = NULL;
173
174    lvaddr_t elfbase = (lvaddr_t)binary;
175    struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)elfbase;
176
177    // just a sanity check
178    if (!IS_ELF(*head) || head->e_ident[EI_CLASS] != ELFCLASS64) {
179        return ELF_ERR_HEADER;
180    }
181
182    shead = (struct Elf64_Shdr *)(elfbase + (uintptr_t)head->e_shoff);
183
184    symtab = elf64_find_section_header_type(shead, head->e_shnum, SHT_SYMTAB);
185
186    uintptr_t symbase = elfbase + (uintptr_t)symtab->sh_offset;
187
188    uint32_t symindex = 1;
189    for (uintptr_t i = 0; i < symtab->sh_size; i += sizeof(struct Elf64_Sym)) {
190        // getting the symbol
191        sym = (struct Elf64_Sym *)(symbase + i);
192
193        // check for matching type
194        if ((sym->st_info & 0x0F) != STT_FUNC) {
195            continue;
196        }
197
198        // find the section of the associated string table
199        struct Elf64_Shdr *strtab = shead+symtab->sh_link;
200
201        // get the pointer to the symbol name from string table + string index
202        symname = (const char *)elfbase + strtab->sh_offset + sym->st_name;
203
204        if (strstr(symname, "_omp_fn") != NULL) {
205            count++;
206            err = spawn_symval_register(name, symindex++,  symname, sym->st_value);
207            if (err_is_fail(err)) {
208                DEBUG_ERR(err, "could not register symbol. %s\n", symname);
209                return err;
210            }
211        }
212    }
213
214    err = spawn_symval_register(name, 0, "binary", count);
215    if (err_is_fail(err)) {
216        DEBUG_ERR(err, "could not register symbol: %s.binary", name);
217        return err;
218    }
219
220    return SYS_ERR_OK;
221}
222
223/**
224 * \brief Load the elf image
225 */
226errval_t spawn_arch_load(struct spawninfo *si,
227                         lvaddr_t binary, size_t binary_size,
228                         genvaddr_t *entry, void** arch_load_info)
229{
230    errval_t err;
231
232    // Reset the elfloader_slot
233    si->elfload_slot = 0;
234    si->vregions = 0;
235
236    struct capref cnode_cap = {
237        .cnode = si->rootcn,
238        .slot  = ROOTCN_SLOT_SEGCN,
239    };
240    struct capref local_cnode_cap;
241    // XXX: this code assumes that elf_load never needs more than 256 slots for
242    // text frame capabilities.
243    err = cnode_create_l2(&local_cnode_cap, &si->segcn);
244
245    if (err_is_fail(err)) {
246        return err_push(err, SPAWN_ERR_CREATE_SEGCN);
247    }
248    // Copy SegCN into new domain's cspace
249    err = cap_copy(cnode_cap, local_cnode_cap);
250    if (err_is_fail(err)) {
251        return err_push(err, SPAWN_ERR_MINT_SEGCN);
252    }
253
254    // Load the binary
255    si->tls_init_base = 0;
256    si->tls_init_len = si->tls_total_len = 0;
257    err = elf_load_tls(EM_HOST, elf_allocate, si, binary, binary_size, entry,
258                       &si->tls_init_base, &si->tls_init_len, &si->tls_total_len);
259    if (err_is_fail(err)) {
260        return err;
261    }
262
263    lvaddr_t tmp, tmp2;
264    err = elf_get_eh_info(binary, binary_size, &tmp, &si->eh_frame_size,
265                          &tmp2, &si->eh_frame_hdr_size);
266    si->eh_frame = vspace_lvaddr_to_genvaddr(tmp);
267    si->eh_frame_hdr = vspace_lvaddr_to_genvaddr(tmp2);
268
269    if (err_is_fail(err)) {
270        return err;
271    }
272
273    if ((strcmp("spawnd", disp_name())==0) && (si->flags & SPAWN_FLAGS_OMP)) {
274        return spawn_parse_omp_functions(si->name, binary, binary_size);
275    }
276
277    /* delete our copy of segcn cap */
278    err = cap_destroy(local_cnode_cap);
279    assert(err_is_ok(err));
280
281    return SYS_ERR_OK;
282}
283
284void spawn_arch_set_registers(void *arch_load_info,
285                              dispatcher_handle_t handle,
286                              arch_registers_state_t *enabled_area,
287                              arch_registers_state_t *disabled_area)
288{
289#if defined(__k1om__)
290    /* XXX: 1st argument to _start is the dispatcher pointer
291     * see lib/crt/arch/x86_64/crt0.s */
292    disabled_area->rdi = get_dispatcher_shared_generic(handle)->udisp;
293    disabled_area->fxsave_area.mxcsr = 0x200000;
294#elif defined(__x86_64__)
295    disabled_area->rdi = get_dispatcher_shared_generic(handle)->udisp;
296    disabled_area->fxsave_area.mxcsr = 0x001f80;
297#elif defined(__i386__)
298    /* XXX: 1st argument to _start is the dispatcher pointer
299     * see lib/crt/arch/x86_32/crt0.s */
300    disabled_area->edi = get_dispatcher_shared_generic(handle)->udisp;
301#endif
302}
303