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