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