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