1/** 2 * \file 3 * \brief functionality to spawn domains 4 */ 5 6/* 7 * Copyright (c) 2007-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, Universitaetstr. 6, 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(__aarch64__) 26#define EM_HOST EM_AARCH64 27#else 28#error "Unexpected architecture." 29#endif 30 31/** 32 * \brief Convert elf flags to vregion flags 33 */ 34static vregion_flags_t elf_to_vregion_flags(uint32_t flags) 35{ 36 vregion_flags_t vregion_flags = 0; 37 38 if (flags & PF_R) { 39 vregion_flags |= VREGION_FLAGS_READ; 40 } 41 if (flags & PF_W) { 42 vregion_flags |= VREGION_FLAGS_WRITE; 43 } 44 if (flags & PF_X) { 45 vregion_flags |= VREGION_FLAGS_EXECUTE; 46 } 47 48 return vregion_flags; 49} 50 51static errval_t elf_allocate(void *state, genvaddr_t base, size_t size, 52 uint32_t flags, void **retbase) 53{ 54 errval_t err; 55 56 struct spawninfo *si = state; 57 58 // Increase size by space wasted on first page due to page-alignment 59 size_t base_offset = BASE_PAGE_OFFSET(base); 60 size += base_offset; 61 base -= base_offset; 62 // Page-align 63 size = ROUND_UP(size, BASE_PAGE_SIZE); 64 65 cslot_t vspace_slot = si->elfload_slot; 66 cslot_t spawn_vspace_slot = si->elfload_slot; 67 68 // Allocate the frames 69 size_t sz = 0; 70 for (lpaddr_t offset = 0; offset < size; offset += sz) { 71 sz = 1UL << log2floor(size - offset); 72 struct capref frame = { 73 .cnode = si->segcn, 74 .slot = si->elfload_slot++, 75 }; 76 err = frame_create(frame, sz, NULL); 77 if (err_is_fail(err)) { 78 return err_push(err, LIB_ERR_FRAME_CREATE); 79 } 80 } 81 82 /* Map into my vspace */ 83 struct memobj *memobj = malloc(sizeof(struct memobj_anon)); 84 if (!memobj) { 85 return LIB_ERR_MALLOC_FAIL; 86 } 87 struct vregion *vregion = malloc(sizeof(struct vregion)); 88 if (!vregion) { 89 return LIB_ERR_MALLOC_FAIL; 90 } 91 // Create the objects 92 err = memobj_create_anon((struct memobj_anon*)memobj, size, 0); 93 if (err_is_fail(err)) { 94 return err_push(err, LIB_ERR_MEMOBJ_CREATE_ANON); 95 } 96 err = vregion_map(vregion, get_current_vspace(), memobj, 0, size, 97 VREGION_FLAGS_READ_WRITE); 98 if (err_is_fail(err)) { 99 return err_push(err, LIB_ERR_VSPACE_MAP); 100 } 101 for (lvaddr_t offset = 0; offset < size; offset += sz) { 102 sz = 1UL << log2floor(size - offset); 103 struct capref frame = { 104 .cnode = si->segcn, 105 .slot = vspace_slot++, 106 }; 107 genvaddr_t genvaddr = vspace_lvaddr_to_genvaddr(offset); 108 err = memobj->f.fill(memobj, genvaddr, frame, sz); 109 if (err_is_fail(err)) { 110 return err_push(err, LIB_ERR_MEMOBJ_FILL); 111 } 112 err = memobj->f.pagefault(memobj, vregion, offset, 0); 113 if (err_is_fail(err)) { 114 DEBUG_ERR(err, "lib_err_memobj_pagefault_handler"); 115 return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER); 116 } 117 } 118 119 /* Map into spawn vspace */ 120 struct memobj *spawn_memobj = NULL; 121 struct vregion *spawn_vregion = NULL; 122 err = spawn_vspace_map_anon_fixed_attr(si, base, size, &spawn_vregion, 123 &spawn_memobj, 124 elf_to_vregion_flags(flags)); 125 if (err_is_fail(err)) { 126 return err_push(err, SPAWN_ERR_VSPACE_MAP); 127 } 128 for (lvaddr_t offset = 0; offset < size; offset += sz) { 129 sz = 1UL << log2floor(size - offset); 130 struct capref frame = { 131 .cnode = si->segcn, 132 .slot = spawn_vspace_slot++, 133 }; 134 genvaddr_t genvaddr = vspace_lvaddr_to_genvaddr(offset); 135 err = memobj->f.fill(spawn_memobj, genvaddr, frame, sz); 136 if (err_is_fail(err)) { 137 return err_push(err, LIB_ERR_MEMOBJ_FILL); 138 } 139 err = spawn_memobj->f.pagefault(spawn_memobj, spawn_vregion, offset, 0); 140 if (err_is_fail(err)) { 141 DEBUG_ERR(err, "lib_err_memobj_pagefault_handler"); 142 return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER); 143 } 144 } 145 146 genvaddr_t genvaddr = vregion_get_base_addr(vregion) + base_offset; 147 *retbase = (void*)vspace_genvaddr_to_lvaddr(genvaddr); 148 return SYS_ERR_OK; 149} 150 151/** 152 * \brief Load the elf image 153 */ 154errval_t spawn_arch_load(struct spawninfo *si, 155 lvaddr_t binary, size_t binary_size, 156 genvaddr_t *entry, void** arch_info) 157{ 158 errval_t err; 159 160 // Reset the elfloader_slot 161 si->elfload_slot = 0; 162 struct capref cnode_cap = { 163 .cnode = si->rootcn, 164 .slot = ROOTCN_SLOT_SEGCN, 165 }; 166 struct capref local_cnode_cap; 167 // XXX: this code assumes that elf_load never needs more than 256 slots for 168 // text frame capabilities. 169 err = cnode_create_l2(&local_cnode_cap, &si->segcn); 170 171 if (err_is_fail(err)) { 172 return err_push(err, SPAWN_ERR_CREATE_SEGCN); 173 } 174 // Copy SegCN into new domain's cspace 175 err = cap_copy(cnode_cap, local_cnode_cap); 176 if (err_is_fail(err)) { 177 return err_push(err, SPAWN_ERR_MINT_SEGCN); 178 } 179 180 181 // TLS is NYI 182 si->tls_init_base = 0; 183 si->tls_init_len = si->tls_total_len = 0; 184 185 // Load the binary 186 err = elf_load(EM_HOST, elf_allocate, si, binary, binary_size, entry); 187 if (err_is_fail(err)) { 188 return err; 189 } 190 191 struct Elf64_Shdr* got_shdr = 192 elf64_find_section_header_name(binary, binary_size, ".got"); 193 if (got_shdr) 194 { 195 *arch_info = (void*)got_shdr->sh_addr; 196 } 197 else { 198 return SPAWN_ERR_LOAD; 199 } 200 201 return SYS_ERR_OK; 202} 203 204void spawn_arch_set_registers(void *arch_load_info, 205 dispatcher_handle_t handle, 206 arch_registers_state_t *enabled_area, 207 arch_registers_state_t *disabled_area) 208{ 209 assert(arch_load_info != NULL); 210 uintptr_t got_base = (uintptr_t)arch_load_info; 211 212 struct dispatcher_shared_aarch64* disp_arm = 213 get_dispatcher_shared_aarch64(handle); 214 disp_arm->got_base = got_base; 215 216 enabled_area->regs[REG_OFFSET(PIC_REGISTER)] = got_base; 217 disabled_area->regs[REG_OFFSET(PIC_REGISTER)] = got_base; 218} 219