1/** 2 * \file 3 * \brief Barrelfish library initialization. 4 */ 5 6/* 7 * Copyright (c) 2007-2012, ETH Zurich. 8 * Copyright (c) 2014, HP Labs. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, 14 * Attn: Systems Group. 15 */ 16 17#include <stdio.h> 18#include <barrelfish/barrelfish.h> 19#include <barrelfish/idc.h> 20#include <barrelfish/dispatch.h> 21#include <barrelfish/curdispatcher_arch.h> 22#include <barrelfish/dispatcher_arch.h> 23#include <barrelfish_kpi/dispatcher_shared.h> 24#include <barrelfish/terminal.h> 25#include <barrelfish/morecore.h> 26#include <barrelfish/monitor_client.h> 27#include <barrelfish/nameservice_client.h> 28#include <barrelfish/spawn_client.h> 29#include <barrelfish/systime.h> 30#include <barrelfish_kpi/domain_params.h> 31#include <if/monitor_defs.h> 32#include <trace/trace.h> 33#include <octopus/init.h> 34#include "threads_priv.h" 35#include "init.h" 36 37/// Are we the init domain (and thus need to take some special paths)? 38static bool init_domain; 39 40extern size_t (*_libc_terminal_read_func)(char *, size_t); 41extern size_t (*_libc_terminal_write_func)(const char *, size_t); 42extern void (*_libc_exit_func)(int); 43extern void (*_libc_assert_func)(const char *, const char *, const char *, int); 44 45void libc_exit(int); 46 47__weak_reference(libc_exit, _exit); 48void libc_exit(int status) 49{ 50 errval_t err; 51 52 if (!init_domain) { 53 terminal_exit(); 54 } 55 56 // Use spawnd if spawned through spawnd 57 if(disp_get_domain_id() == 0) { 58#if 0 // XXX: revocation goes through the mon, but monitor ep is revoked in the process 59 err = cap_revoke(cap_dispatcher); 60 if (err_is_fail(err)) { 61 DEBUG_ERR(err, "revoking dispatcher failed in _Exit, spinning!"); 62 //sys_print("revoking dispatcher failed in _Exit, spinning!", 100); 63 while (1) {} 64 } 65 err = cap_delete(cap_dispatcher); 66 DEBUG_ERR(err, "deleting dispatcher failed in _Exit, spinning!"); 67 //sys_print("deleting dispatcher failed in _Exit, spinning!", 100); 68#endif 69 70 // XXX: Leak all other domain allocations 71 } else { 72 err = spawn_exit(status); 73 if (err_is_fail(err)) { 74 DEBUG_ERR(err, "spawn_exit"); 75 } 76 } 77 78 thread_exit(status); 79 // If we're not dead by now, we wait 80 while (1) {} 81} 82 83static void libc_assert(const char *expression, const char *file, 84 const char *function, int line) 85{ 86 char buf[512]; 87 size_t len; 88 89 /* Formatting as per suggestion in C99 spec 7.2.1.1 */ 90 len = snprintf(buf, sizeof(buf), "Assertion failed on core %d in %.*s: %s," 91 " function %s, file %s, line %d.\n", 92 disp_get_core_id(), DISP_NAME_LEN, 93 disp_name(), expression, function, file, line); 94 sys_print(buf, len < sizeof(buf) ? len : sizeof(buf)); 95} 96 97/* Set libc function pointers */ 98void barrelfish_libc_glue_init(void) 99{ 100 _libc_terminal_read_func = terminal_read; 101 _libc_terminal_write_func = terminal_write; 102 _libc_exit_func = libc_exit; 103 _libc_assert_func = libc_assert; 104 /* morecore func is setup by morecore_init() */ 105 106 // XXX: set a static buffer for stdout 107 // this avoids an implicit call to malloc() on the first printf 108 static char buf[BUFSIZ]; 109 setvbuf(stdout, buf, _IOLBF, sizeof(buf)); 110} 111 112static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b); 113 114#ifdef CONFIG_TRACE 115errval_t trace_my_setup(void) 116{ 117#ifndef TRACING_EXISTS 118 return SYS_ERR_OK; 119#else 120 errval_t err; 121 122 struct capref cap = { 123 .cnode = cnode_task, 124 .slot = TASKCN_SLOT_TRACEBUF 125 }; 126 127 if (disp_get_core_id() >= TRACE_COREID_LIMIT) { 128 // can't support tracing on this core. sorry :( 129 return SYS_ERR_OK; 130 } 131 132 err = vspace_map_one_frame((void**)&trace_buffer_master, TRACE_ALLOC_SIZE, 133 cap, NULL, NULL); 134 if (err_is_fail(err)) { 135 DEBUG_ERR(err, "vspace_map_one_frame for master trace buffer failed"); 136 return err; 137 } 138 assert(trace_buffer_master != 0); 139 140 trace_buffer_va = trace_buffer_master + 141 (disp_get_core_id() * TRACE_PERCORE_BUF_SIZE); 142 143 dispatcher_handle_t handle = curdispatcher(); 144 struct dispatcher_generic *disp = get_dispatcher_generic(handle); 145 // Update pointer to trace buffer in child's dispatcher 146 disp->trace_buf = (struct trace_buffer *)trace_buffer_va; 147 148 return SYS_ERR_OK; 149#endif 150} 151#endif 152 153static bool request_done = false; 154 155static bool parse_argv(struct spawn_domain_params *params, size_t *morecore_alignment) 156{ 157 assert(params); 158 // grab pagesize config from argv if available 159 size_t morecore_pagesize = MORECORE_PAGESIZE; 160 int i = 1; 161 bool found = false; 162 for (; i < params->argc; i++) { 163 if (!found) { 164 if (!strncmp(params->argv[i], "morecore=", 9)) { 165 morecore_pagesize = strtol(params->argv[i]+9, NULL, 0); 166 // check for valid page size 167 switch (morecore_pagesize) { 168#ifdef __x86_64__ 169 case HUGE_PAGE_SIZE: 170#endif 171 case BASE_PAGE_SIZE: 172 case LARGE_PAGE_SIZE: 173 break; 174 default: 175 morecore_pagesize = MORECORE_PAGESIZE; 176 } 177 found = true; 178 } 179 } else { 180 // found so move all other args one to the front 181 params->argv[i-1] = params->argv[i]; 182 } 183 } 184 if (found) { 185 params->argc -= 1; 186 } 187 188 if (morecore_alignment) { 189 *morecore_alignment = morecore_pagesize; 190 } 191 192 return found; 193} 194 195/** \brief Initialise libbarrelfish. 196 * 197 * This runs on a thread in every domain, after the dispatcher is setup but 198 * before main() runs. 199 */ 200errval_t barrelfish_init_onthread(struct spawn_domain_params *params) 201{ 202 errval_t err; 203 204 // do we have an environment? 205 if (params != NULL && params->envp[0] != NULL) { 206 extern char **environ; 207 environ = params->envp; 208 } 209 210 // Init default waitset for this dispatcher 211 struct waitset *default_ws = get_default_waitset(); 212 waitset_init(default_ws); 213 214 // Initialize ram_alloc state 215 ram_alloc_init(); 216 /* All domains use smallcn to initialize */ 217 err = ram_alloc_set(ram_alloc_fixed); 218 if (err_is_fail(err)) { 219 return err_push(err, LIB_ERR_RAM_ALLOC_SET); 220 } 221 222 err = vspace_current_init(init_domain); 223 if (err_is_fail(err)) { 224 return err_push(err, LIB_ERR_VSPACE_INIT); 225 } 226 227 err = slot_alloc_init(); 228 if (err_is_fail(err)) { 229 return err_push(err, LIB_ERR_SLOT_ALLOC_INIT); 230 } 231 232 // reconstruct our pmap from data passed to us by our parent 233 if (params != NULL && params->vspace_buf != NULL) { 234 struct pmap *pmap = get_current_pmap(); 235 err = pmap->f.deserialise(pmap, params->vspace_buf, 236 params->vspace_buf_len); 237 if (err_is_fail(err)) { 238 return err_push(err, LIB_ERR_VSPACE_INIT); 239 } 240 } else if (init_domain) { 241 // TODO: the kernel boots us with a deterministic pmap structure: use it 242 } 243 244 if (init_domain) { 245 // we cannot use large pages in the init domains because we are not 246 // connected to the memory server and need to work with the 4k pages 247 // in the base cn. 248 err = morecore_init(BASE_PAGE_SIZE); 249 } else { 250 /* if there is a pagesize supplied, use this one */ 251 size_t morecore_pagesize = 0; 252 if (params != NULL && params->pagesize) { 253 morecore_pagesize = params->pagesize; 254 255 assert(morecore_pagesize == BASE_PAGE_SIZE 256#ifdef __x86_64__ 257 || morecore_pagesize == HUGE_PAGE_SIZE 258#endif 259 || morecore_pagesize == LARGE_PAGE_SIZE ); 260 261 } else { 262 parse_argv(params, &morecore_pagesize); 263#if defined(__i386__) && !defined(CONFIG_PSE) 264 morecore_pagesize = BASE_PAGE_SIZE; 265#endif 266 } 267 err = morecore_init(morecore_pagesize); 268 } 269 if (err_is_fail(err)) { 270 return err_push(err, LIB_ERR_MORECORE_INIT); 271 } 272 273 lmp_endpoint_init(); 274 275 // init domains only get partial init 276 if (init_domain) { 277 return SYS_ERR_OK; 278 } 279 280 /* bind to monitor */ 281 struct monitor_lmp_binding *mcb = 282 malloc(sizeof(struct monitor_lmp_binding)); 283 assert(mcb != NULL); 284 set_monitor_binding(&mcb->b); 285 286 errval_t init_complete_err; 287 288 request_done = false; 289 err = monitor_client_lmp_bind(mcb, monitor_bind_cont, &init_complete_err, 290 default_ws, DEFAULT_LMP_BUF_WORDS); 291 if (err_is_fail(err)) { 292 return err_push(err, LIB_ERR_MONITOR_CLIENT_BIND); 293 } 294 295 // dispatch events on the waitset until monitor binding completes 296 while (!request_done) { 297 err = event_dispatch(default_ws); 298 if (err_is_fail(err)) { 299 return err_push(err, LIB_ERR_EVENT_DISPATCH); 300 } 301 } 302 303 if(err_is_fail(init_complete_err)) { 304 USER_PANIC_ERR(err, "during initialization"); 305 } 306 307 idc_init(); 308 309 /* Bind with monitor's blocking rpc channel */ 310 err = monitor_client_blocking_rpc_init(); 311 if (err_is_fail(err)) { 312 return err_push(err, LIB_ERR_MONITOR_RPC_BIND); 313 } 314 315 /* XXX: Setup the channel with mem_serv and use the channel instead */ 316 err = ram_alloc_set(NULL); 317 if (err_is_fail(err)) { 318 return err_push(err, LIB_ERR_RAM_ALLOC_SET); 319 } 320 321 // switch morecore to intended configuration 322 err = morecore_reinit(); 323 if (err_is_fail(err)) { 324 return err_push(err, LIB_ERR_MORECORE_INIT); 325 } 326 327#ifdef CONFIG_TRACE 328 err = trace_my_setup(); 329 if (err_is_fail(err)) { 330 DEBUG_ERR(err, "trace_my_setup failed"); 331 return err; 332 } 333#endif 334 335 // try to connect to name service (may fail if we are the skb or ramfsd!) 336 err = nameservice_client_blocking_bind(); 337 if (err_is_fail(err)) { 338 if (err_no(err) == LIB_ERR_GET_NAME_IREF) { 339 // skip everything else if we don't have a nameservice 340 return SYS_ERR_OK; 341 } else { 342 return err_push(err, LIB_ERR_NAMESERVICE_CLIENT_INIT); 343 } 344 } 345 346 // init terminal 347 err = terminal_init(); 348 if (err_is_fail(err)) { 349 return err_push(err, LIB_ERR_TERMINAL_INIT); 350 } 351 352 // Init domain spanning code 353 err = domain_init(); 354 if (err_is_fail(err)) { 355 return err_push(err, LIB_ERR_DOMAIN_INIT); 356 } 357 358 // XXX: Record text/data mappings from environment 359 char *p = getenv("ARRAKIS_PMAP"); 360 if(p != NULL) { 361 struct morecore_state *mcstate = get_morecore_state(); 362 for(mcstate->v2p_entries = 0; *p != '\0'; mcstate->v2p_entries++) { 363 assert(mcstate->v2p_entries < MAX_V2P_MAPPINGS); 364 struct v2pmap *e = &mcstate->v2p_mappings[mcstate->v2p_entries]; 365 int r = sscanf(p, "%" PRIxGENVADDR ":%" PRIxGENPADDR ":%zx ", &e->va, &e->pa, &e->size); 366 assert(r == 3); 367 p = strchr(p, ' ') + 1; 368 } 369 } 370 return err; 371} 372 373static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b) 374{ 375 // hacky errval_t state pointer used to signal completion 376 errval_t *init_complete_err = st; 377 378 assert(!init_domain); 379 *init_complete_err = err; 380 381 // signal completion 382 request_done = true; 383} 384 385/** 386 * \brief Initialise libbarrelfish, while disabled. 387 * 388 * This runs on the dispatcher's stack, while disabled, before the dispatcher is 389 * setup. We can't call anything that needs to be enabled (ie. cap invocations) 390 * or uses threads. This is called from crt0. 391 */ 392void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg); 393void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg) 394{ 395 init_domain = init_dom_arg; 396 disp_init_disabled(handle); 397 thread_init_disabled(handle, init_dom_arg); 398} 399