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