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