3 * \brief Barrelfish library initialization.
7 * Copyright (c) 2007-2012, ETH Zurich.
8 * Copyright (c) 2014, HP Labs.
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.
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"
37 /// Are we the init domain (and thus need to take some special paths)?
38 static bool init_domain;
40 extern size_t (*_libc_terminal_read_func)(char *, size_t);
41 extern size_t (*_libc_terminal_write_func)(const char *, size_t);
42 extern void (*_libc_exit_func)(int);
43 extern void (*_libc_assert_func)(const char *, const char *, const char *, int);
47 void libc_exit(int status)
55 // Use spawnd if spawned through spawnd
56 if(disp_get_domain_id() == 0) {
57 #if 0 // XXX: revocation goes through the mon, but monitor ep is revoked in the process
58 err = cap_revoke(cap_dispatcher);
59 if (err_is_fail(err)) {
60 DEBUG_ERR(err, "revoking dispatcher failed in _Exit, spinning!");
61 //sys_print("revoking dispatcher failed in _Exit, spinning!", 100);
64 err = cap_delete(cap_dispatcher);
65 DEBUG_ERR(err, "deleting dispatcher failed in _Exit, spinning!");
66 //sys_print("deleting dispatcher failed in _Exit, spinning!", 100);
69 // XXX: Leak all other domain allocations
71 err = spawn_exit(status);
72 if(err_is_fail(err)) {
73 DEBUG_ERR(err, "spawn_exit");
78 // If we're not dead by now, we wait
82 static void libc_assert(const char *expression, const char *file,
83 const char *function, int line)
88 /* Formatting as per suggestion in C99 spec 7.2.1.1 */
89 len = snprintf(buf, sizeof(buf), "Assertion failed on core %d in %.*s: %s,"
90 " function %s, file %s, line %d.\n",
91 disp_get_core_id(), DISP_NAME_LEN,
92 disp_name(), expression, function, file, line);
93 sys_print(buf, len < sizeof(buf) ? len : sizeof(buf));
96 /* Set libc function pointers */
97 void barrelfish_libc_glue_init(void)
99 _libc_terminal_read_func = terminal_read;
100 _libc_terminal_write_func = terminal_write;
101 _libc_exit_func = libc_exit;
102 _libc_assert_func = libc_assert;
103 /* morecore func is setup by morecore_init() */
105 // XXX: set a static buffer for stdout
106 // this avoids an implicit call to malloc() on the first printf
107 static char buf[BUFSIZ];
108 setvbuf(stdout, buf, _IOLBF, sizeof(buf));
111 static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b);
114 errval_t trace_my_setup(void)
116 #ifndef TRACING_EXISTS
121 struct capref cap = {
123 .slot = TASKCN_SLOT_TRACEBUF
126 if (disp_get_core_id() >= TRACE_COREID_LIMIT) {
127 // can't support tracing on this core. sorry :(
131 err = vspace_map_one_frame((void**)&trace_buffer_master, TRACE_ALLOC_SIZE,
133 if (err_is_fail(err)) {
134 DEBUG_ERR(err, "vspace_map_one_frame failed");
138 trace_buffer_va = trace_buffer_master +
139 (disp_get_core_id() * TRACE_PERCORE_BUF_SIZE);
141 dispatcher_handle_t handle = curdispatcher();
142 struct dispatcher_generic *disp = get_dispatcher_generic(handle);
143 // Update pointer to trace buffer in child's dispatcher
144 disp->trace_buf = (struct trace_buffer *)trace_buffer_va;
151 static bool request_done = false;
153 static bool parse_argv(struct spawn_domain_params *params, size_t *morecore_alignment)
156 // grab pagesize config from argv if available
157 size_t morecore_pagesize = MORECORE_PAGESIZE;
160 for (; i < params->argc; i++) {
162 if (!strncmp(params->argv[i], "morecore=", 9)) {
163 morecore_pagesize = strtol(params->argv[i]+9, NULL, 0);
164 // check for valid page size
165 switch (morecore_pagesize) {
170 case LARGE_PAGE_SIZE:
173 morecore_pagesize = MORECORE_PAGESIZE;
178 // found so move all other args one to the front
179 params->argv[i-1] = params->argv[i];
186 if (morecore_alignment) {
187 *morecore_alignment = morecore_pagesize;
193 /** \brief Initialise libbarrelfish.
195 * This runs on a thread in every domain, after the dispatcher is setup but
196 * before main() runs.
198 errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
202 // do we have an environment?
203 if (params != NULL && params->envp[0] != NULL) {
204 extern char **environ;
205 environ = params->envp;
208 // Init default waitset for this dispatcher
209 struct waitset *default_ws = get_default_waitset();
210 waitset_init(default_ws);
212 // Initialize ram_alloc state
214 /* All domains use smallcn to initialize */
215 err = ram_alloc_set(ram_alloc_fixed);
216 if (err_is_fail(err)) {
217 return err_push(err, LIB_ERR_RAM_ALLOC_SET);
220 err = vspace_current_init(init_domain);
221 if (err_is_fail(err)) {
222 return err_push(err, LIB_ERR_VSPACE_INIT);
225 err = slot_alloc_init();
226 if (err_is_fail(err)) {
227 return err_push(err, LIB_ERR_SLOT_ALLOC_INIT);
230 // reconstruct our pmap from data passed to us by our parent
231 if (params != NULL && params->vspace_buf != NULL) {
232 struct pmap *pmap = get_current_pmap();
233 err = pmap->f.deserialise(pmap, params->vspace_buf,
234 params->vspace_buf_len);
235 if (err_is_fail(err)) {
236 return err_push(err, LIB_ERR_VSPACE_INIT);
238 } else if (init_domain) {
239 // TODO: the kernel boots us with a deterministic pmap structure: use it
243 // we cannot use large pages in the init domains because we are not
244 // connected to the memory server and need to work with the 4k pages
246 err = morecore_init(BASE_PAGE_SIZE);
248 /* if there is a pagesize supplied, use this one */
249 size_t morecore_pagesize = 0;
250 if (params != NULL && params->pagesize) {
251 morecore_pagesize = params->pagesize;
253 assert(morecore_pagesize == BASE_PAGE_SIZE
255 || morecore_pagesize == HUGE_PAGE_SIZE
257 || morecore_pagesize == LARGE_PAGE_SIZE );
260 parse_argv(params, &morecore_pagesize);
261 #if defined(__i386__) && !defined(CONFIG_PSE)
262 morecore_pagesize = BASE_PAGE_SIZE;
265 err = morecore_init(morecore_pagesize);
267 if (err_is_fail(err)) {
268 return err_push(err, LIB_ERR_MORECORE_INIT);
273 // init domains only get partial init
278 /* bind to monitor */
279 struct monitor_lmp_binding *mcb =
280 malloc(sizeof(struct monitor_lmp_binding));
282 set_monitor_binding(&mcb->b);
284 errval_t init_complete_err;
286 request_done = false;
287 err = monitor_client_lmp_bind(mcb, monitor_bind_cont, &init_complete_err,
288 default_ws, DEFAULT_LMP_BUF_WORDS);
289 if (err_is_fail(err)) {
290 return err_push(err, LIB_ERR_MONITOR_CLIENT_BIND);
293 // dispatch events on the waitset until monitor binding completes
294 while (!request_done) {
295 err = event_dispatch(default_ws);
296 if (err_is_fail(err)) {
297 return err_push(err, LIB_ERR_EVENT_DISPATCH);
301 if(err_is_fail(init_complete_err)) {
302 USER_PANIC_ERR(err, "during initialization");
307 /* Bind with monitor's blocking rpc channel */
308 err = monitor_client_blocking_rpc_init();
309 if (err_is_fail(err)) {
310 return err_push(err, LIB_ERR_MONITOR_RPC_BIND);
313 /* XXX: Setup the channel with mem_serv and use the channel instead */
314 err = ram_alloc_set(NULL);
315 if (err_is_fail(err)) {
316 return err_push(err, LIB_ERR_RAM_ALLOC_SET);
319 // switch morecore to intended configuration
320 err = morecore_reinit();
321 if (err_is_fail(err)) {
322 return err_push(err, LIB_ERR_MORECORE_INIT);
326 err = trace_my_setup();
327 if (err_is_fail(err)) {
328 DEBUG_ERR(err, "trace_my_setup failed");
333 // try to connect to name service (may fail if we are the skb or ramfsd!)
334 err = nameservice_client_blocking_bind();
335 if (err_is_fail(err)) {
336 if (err_no(err) == LIB_ERR_GET_NAME_IREF) {
337 // skip everything else if we don't have a nameservice
340 return err_push(err, LIB_ERR_NAMESERVICE_CLIENT_INIT);
345 err = terminal_init();
346 if (err_is_fail(err)) {
347 return err_push(err, LIB_ERR_TERMINAL_INIT);
350 // Init domain spanning code
352 if (err_is_fail(err)) {
353 return err_push(err, LIB_ERR_DOMAIN_INIT);
356 // XXX: Record text/data mappings from environment
357 char *p = getenv("ARRAKIS_PMAP");
359 struct morecore_state *mcstate = get_morecore_state();
360 for(mcstate->v2p_entries = 0; *p != '\0'; mcstate->v2p_entries++) {
361 assert(mcstate->v2p_entries < MAX_V2P_MAPPINGS);
362 struct v2pmap *e = &mcstate->v2p_mappings[mcstate->v2p_entries];
363 int r = sscanf(p, "%" PRIxGENVADDR ":%" PRIxGENPADDR ":%zx ", &e->va, &e->pa, &e->size);
365 p = strchr(p, ' ') + 1;
369 dispatcher_handle_t handle = curdispatcher();
370 systime_frequency = get_dispatcher_shared_generic(handle)->systime_frequency;
374 static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b)
376 // hacky errval_t state pointer used to signal completion
377 errval_t *init_complete_err = st;
379 assert(!init_domain);
380 *init_complete_err = err;
387 * \brief Initialise libbarrelfish, while disabled.
389 * This runs on the dispatcher's stack, while disabled, before the dispatcher is
390 * setup. We can't call anything that needs to be enabled (ie. cap invocations)
391 * or uses threads. This is called from crt0.
393 void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg);
394 void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg)
396 init_domain = init_dom_arg;
397 disp_init_disabled(handle);
398 thread_init_disabled(handle, init_dom_arg);