6221a2fea33bc1bf5a8479adc893088e4a085bf7
[barrelfish] / lib / barrelfish / init.c
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)?
38 static bool init_domain;
39
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);
44
45 void libc_exit(int);
46
47 void libc_exit(int status)
48 {
49     errval_t err;
50
51     if (!init_domain) {
52         terminal_exit();
53     }
54
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);
62             while (1) {}
63         }
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);
67 #endif
68
69         // XXX: Leak all other domain allocations
70     } else {
71         err = spawn_exit(status);
72         if(err_is_fail(err)) {
73             DEBUG_ERR(err, "spawn_exit");
74         }
75     }
76
77     thread_exit(status);
78     // If we're not dead by now, we wait
79     while (1) {}
80 }
81
82 static void libc_assert(const char *expression, const char *file,
83                         const char *function, int line)
84 {
85     char buf[512];
86     size_t len;
87
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));
94 }
95
96 /* Set libc function pointers */
97 void barrelfish_libc_glue_init(void)
98 {
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() */
104
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));
109 }
110
111 static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b);
112
113 #ifdef CONFIG_TRACE
114 errval_t trace_my_setup(void)
115 {
116 #ifndef TRACING_EXISTS
117     return SYS_ERR_OK;
118 #else
119     errval_t err;
120
121     struct capref cap = {
122         .cnode  = cnode_task,
123         .slot   = TASKCN_SLOT_TRACEBUF
124     };
125
126     if (disp_get_core_id() >= TRACE_COREID_LIMIT) {
127         // can't support tracing on this core. sorry :(
128         return SYS_ERR_OK;
129     }
130
131     err = vspace_map_one_frame((void**)&trace_buffer_master, TRACE_ALLOC_SIZE,
132                                cap, NULL, NULL);
133     if (err_is_fail(err)) {
134         DEBUG_ERR(err, "vspace_map_one_frame failed");
135         return err;
136     }
137
138     trace_buffer_va = trace_buffer_master +
139         (disp_get_core_id() * TRACE_PERCORE_BUF_SIZE);
140
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;
145
146     return SYS_ERR_OK;
147 #endif
148 }
149 #endif
150
151 static bool request_done = false;
152
153 static bool parse_argv(struct spawn_domain_params *params, size_t *morecore_alignment)
154 {
155     assert(params);
156     // grab pagesize config from argv if available
157     size_t morecore_pagesize = MORECORE_PAGESIZE;
158     int i = 1;
159     bool found = false;
160     for (; i < params->argc; i++) {
161         if (!found) {
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) {
166 #ifdef __x86_64__
167                     case HUGE_PAGE_SIZE:
168 #endif
169                     case BASE_PAGE_SIZE:
170                     case LARGE_PAGE_SIZE:
171                         break;
172                     default:
173                         morecore_pagesize = MORECORE_PAGESIZE;
174                 }
175                 found = true;
176             }
177         } else {
178             // found so move all other args one to the front
179             params->argv[i-1] = params->argv[i];
180         }
181     }
182     if (found) {
183         params->argc -= 1;
184     }
185
186     if (morecore_alignment) {
187         *morecore_alignment = morecore_pagesize;
188     }
189
190     return found;
191 }
192
193 /** \brief Initialise libbarrelfish.
194  *
195  * This runs on a thread in every domain, after the dispatcher is setup but
196  * before main() runs.
197  */
198 errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
199 {
200     errval_t err;
201
202     // do we have an environment?
203     if (params != NULL && params->envp[0] != NULL) {
204         extern char **environ;
205         environ = params->envp;
206     }
207
208     // Init default waitset for this dispatcher
209     struct waitset *default_ws = get_default_waitset();
210     waitset_init(default_ws);
211
212     // Initialize ram_alloc state
213     ram_alloc_init();
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);
218     }
219
220     err = vspace_current_init(init_domain);
221     if (err_is_fail(err)) {
222         return err_push(err, LIB_ERR_VSPACE_INIT);
223     }
224
225     err = slot_alloc_init();
226     if (err_is_fail(err)) {
227         return err_push(err, LIB_ERR_SLOT_ALLOC_INIT);
228     }
229
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);
237         }
238     } else if (init_domain) {
239         // TODO: the kernel boots us with a deterministic pmap structure: use it
240     }
241
242     if (init_domain) {
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
245         // in the base cn.
246         err = morecore_init(BASE_PAGE_SIZE);
247     } else {
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;
252
253             assert(morecore_pagesize == BASE_PAGE_SIZE
254 #ifdef __x86_64__
255                    || morecore_pagesize == HUGE_PAGE_SIZE
256 #endif
257                    || morecore_pagesize == LARGE_PAGE_SIZE );
258
259         } else {
260             parse_argv(params, &morecore_pagesize);
261 #if defined(__i386__) && !defined(CONFIG_PSE)
262             morecore_pagesize = BASE_PAGE_SIZE;
263 #endif
264         }
265         err = morecore_init(morecore_pagesize);
266     }
267     if (err_is_fail(err)) {
268         return err_push(err, LIB_ERR_MORECORE_INIT);
269     }
270
271     lmp_endpoint_init();
272
273     // init domains only get partial init
274     if (init_domain) {
275         return SYS_ERR_OK;
276     }
277
278     /* bind to monitor */
279     struct monitor_lmp_binding *mcb =
280         malloc(sizeof(struct monitor_lmp_binding));
281     assert(mcb != NULL);
282     set_monitor_binding(&mcb->b);
283
284     errval_t init_complete_err;
285
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);
291     }
292
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);
298         }
299     }
300
301     if(err_is_fail(init_complete_err)) {
302         USER_PANIC_ERR(err, "during initialization");
303     }
304
305     idc_init();
306
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);
311     }
312
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);
317     }
318
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);
323     }
324
325 #ifdef CONFIG_TRACE
326     err = trace_my_setup();
327     if (err_is_fail(err)) {
328         DEBUG_ERR(err, "trace_my_setup failed");
329         return err;
330     }
331 #endif
332
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
338             return SYS_ERR_OK;
339         } else {
340             return err_push(err, LIB_ERR_NAMESERVICE_CLIENT_INIT);
341         }
342     }
343
344     // init terminal
345     err = terminal_init();
346     if (err_is_fail(err)) {
347         return err_push(err, LIB_ERR_TERMINAL_INIT);
348     }
349
350     // Init domain spanning code
351     err = domain_init();
352     if (err_is_fail(err)) {
353         return err_push(err, LIB_ERR_DOMAIN_INIT);
354     }
355
356     // XXX: Record text/data mappings from environment
357     char *p = getenv("ARRAKIS_PMAP");
358     if(p != NULL) {
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);
364             assert(r == 3);
365             p = strchr(p, ' ') + 1;
366         }
367     }
368
369     dispatcher_handle_t handle = curdispatcher();
370     systime_frequency = get_dispatcher_shared_generic(handle)->systime_frequency;
371     return err;
372 }
373
374 static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b)
375 {
376     // hacky errval_t state pointer used to signal completion
377     errval_t *init_complete_err = st;
378
379     assert(!init_domain);
380     *init_complete_err = err;
381
382     // signal completion
383     request_done = true;
384 }
385
386 /**
387  *  \brief Initialise libbarrelfish, while disabled.
388  *
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.
392  */
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)
395 {
396     init_domain = init_dom_arg;
397     disp_init_disabled(handle);
398     thread_init_disabled(handle, init_dom_arg);
399 }