d3de66bd3d64c6c528d83448c426f27bb9af7afd
[barrelfish] / lib / barrelfish / init.c
1 /**
2  * \file
3  * \brief Barrelfish library initialization.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <stdio.h>
16 #include <barrelfish/barrelfish.h>
17 #include <barrelfish/idc.h>
18 #include <barrelfish/dispatch.h>
19 #include <barrelfish/curdispatcher_arch.h>
20 #include <barrelfish/dispatcher_arch.h>
21 #include <barrelfish_kpi/dispatcher_shared.h>
22 #include <barrelfish/terminal.h>
23 #include <barrelfish/morecore.h>
24 #include <barrelfish/monitor_client.h>
25 #include <barrelfish/nameservice_client.h>
26 #include <barrelfish/spawn_client.h>
27 #include <barrelfish_kpi/domain_params.h>
28 #include <if/monitor_defs.h>
29 #include <trace/trace.h>
30 #include <octopus/init.h>
31 #include "threads_priv.h"
32 #include "init.h"
33
34 /// Are we the init domain (and thus need to take some special paths)?
35 static bool init_domain;
36
37 extern size_t (*_libc_terminal_read_func)(char *, size_t);
38 extern size_t (*_libc_terminal_write_func)(const char *, size_t);
39 extern void (*_libc_exit_func)(int);
40 extern void (*_libc_assert_func)(const char *, const char *, const char *, int);
41
42 void libc_exit(int);
43
44 void libc_exit(int status)
45 {
46     // Use spawnd if spawned through spawnd
47     if(disp_get_domain_id() == 0) {
48         errval_t err = cap_revoke(cap_dispatcher);
49         if (err_is_fail(err)) {
50             sys_print("revoking dispatcher failed in _Exit, spinning!", 100);
51             while (1) {}
52         }
53         err = cap_delete(cap_dispatcher);
54         sys_print("deleting dispatcher failed in _Exit, spinning!", 100);
55
56         // XXX: Leak all other domain allocations
57     } else {
58         errval_t err = spawn_exit(status);
59         if(err_is_fail(err)) {
60             DEBUG_ERR(err, "spawn_exit");
61         }
62     }
63
64     // If we're not dead by now, we wait
65     while (1) {}
66 }
67
68 static void libc_assert(const char *expression, const char *file,
69                         const char *function, int line)
70 {
71     char buf[512];
72     size_t len;
73
74     /* Formatting as per suggestion in C99 spec 7.2.1.1 */
75     len = snprintf(buf, sizeof(buf), "Assertion failed on core %d in %.*s: %s,"
76                    " function %s, file %s, line %d.\n",
77                    disp_get_core_id(), DISP_NAME_LEN,
78                    disp_name(), expression, function, file, line);
79     sys_print(buf, len < sizeof(buf) ? len : sizeof(buf));
80 }
81
82 /* Set libc function pointers */
83 void barrelfish_libc_glue_init(void)
84 {
85     _libc_terminal_read_func = terminal_read;
86     _libc_terminal_write_func = terminal_write;
87     _libc_exit_func = libc_exit;
88     _libc_assert_func = libc_assert;
89     /* morecore func is setup by morecore_init() */
90
91     // XXX: set a static buffer for stdout
92     // this avoids an implicit call to malloc() on the first printf
93     static char buf[BUFSIZ];
94     setvbuf(stdout, buf, _IOLBF, sizeof(buf));
95 }
96
97 static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b);
98
99 #ifdef CONFIG_TRACE
100 errval_t trace_my_setup(void)
101 {
102 #ifndef TRACING_EXISTS
103     return SYS_ERR_OK;
104 #else
105     errval_t err;
106
107     struct capref cap = {
108         .cnode  = cnode_task,
109         .slot   = TASKCN_SLOT_TRACEBUF
110     };
111
112     if (disp_get_core_id() >= TRACE_COREID_LIMIT) {
113         // can't support tracing on this core. sorry :(
114         return SYS_ERR_OK;
115     }
116
117     err = vspace_map_one_frame((void**)&trace_buffer_master, TRACE_BUF_SIZE,
118                                cap, NULL, NULL);
119     if (err_is_fail(err)) {
120         DEBUG_ERR(err, "vspace_map_one_frame failed");
121         return err;
122     }
123
124     trace_buffer_va = trace_buffer_master +
125         (disp_get_core_id() * TRACE_PERCORE_BUF_SIZE);
126
127     dispatcher_handle_t handle = curdispatcher();
128     struct dispatcher_generic *disp = get_dispatcher_generic(handle);
129     // Update pointer to trace buffer in child's dispatcher
130     disp->trace_buf = (struct trace_buffer *)trace_buffer_va;
131
132     return SYS_ERR_OK;
133 #endif
134 }
135 #endif
136
137 static bool request_done = false;
138
139 /** \brief Initialise libbarrelfish.
140  *
141  * This runs on a thread in every domain, after the dispatcher is setup but
142  * before main() runs.
143  */
144 errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
145 {
146     errval_t err;
147
148     // do we have an environment?
149     if (params != NULL && params->envp[0] != NULL) {
150         extern char **environ;
151         environ = params->envp;
152     }
153
154     // Init default waitset for this dispatcher
155     struct waitset *default_ws = get_default_waitset();
156     waitset_init(default_ws);
157
158     // Initialize ram_alloc state
159     ram_alloc_init();
160     /* All domains use smallcn to initialize */
161     err = ram_alloc_set(ram_alloc_fixed);
162     if (err_is_fail(err)) {
163         return err_push(err, LIB_ERR_RAM_ALLOC_SET);
164     }
165
166     err = vspace_current_init(init_domain);
167     if (err_is_fail(err)) {
168         return err_push(err, LIB_ERR_VSPACE_INIT);
169     }
170
171     err = slot_alloc_init();
172     if (err_is_fail(err)) {
173         return err_push(err, LIB_ERR_SLOT_ALLOC_INIT);
174     }
175
176     // reconstruct our pmap from data passed to us by our parent
177     if (params != NULL && params->vspace_buf != NULL) {
178         struct pmap *pmap = get_current_pmap();
179         err = pmap->f.deserialise(pmap, params->vspace_buf,
180                                   params->vspace_buf_len);
181         if (err_is_fail(err)) {
182             return err_push(err, LIB_ERR_VSPACE_INIT);
183         }
184     } else if (init_domain) {
185         // TODO: the kernel boots us with a deterministic pmap structure: use it
186     }
187
188     err = morecore_init();
189     if (err_is_fail(err)) {
190         return err_push(err, LIB_ERR_MORECORE_INIT);
191     }
192
193     lmp_endpoint_init();
194
195     // init domains only get partial init
196     if (init_domain) {
197         return SYS_ERR_OK;
198     }
199
200     /* bind to monitor */
201     struct monitor_lmp_binding *mcb =
202         malloc(sizeof(struct monitor_lmp_binding));
203     assert(mcb != NULL);
204     set_monitor_binding(&mcb->b);
205
206     errval_t init_complete_err;
207
208     request_done = false;
209     err = monitor_client_lmp_bind(mcb, monitor_bind_cont, &init_complete_err,
210                                   default_ws, DEFAULT_LMP_BUF_WORDS);
211     if (err_is_fail(err)) {
212         return err_push(err, LIB_ERR_MONITOR_CLIENT_BIND);
213     }
214
215     // dispatch events on the waitset until monitor binding completes
216     while (!request_done) {
217         err = event_dispatch(default_ws);
218         if (err_is_fail(err)) {
219             return err_push(err, LIB_ERR_EVENT_DISPATCH);
220         }
221     }
222
223     if(err_is_fail(init_complete_err)) {
224         USER_PANIC_ERR(err, "during initialization");
225     }
226
227     idc_init();
228
229     /* Bind with monitor's blocking rpc channel */
230     err = monitor_client_blocking_rpc_init();
231     if (err_is_fail(err)) {
232         return err_push(err, LIB_ERR_MONITOR_RPC_BIND);
233     }
234
235     /* XXX: Setup the channel with mem_serv and use the channel instead */
236     err = ram_alloc_set(NULL);
237     if (err_is_fail(err)) {
238         return err_push(err, LIB_ERR_RAM_ALLOC_SET);
239     }
240
241 #ifdef CONFIG_TRACE
242     err = trace_my_setup();
243     if (err_is_fail(err)) {
244         DEBUG_ERR(err, "trace_my_setup failed");
245         return err;
246     }
247 #endif
248
249     // try to connect to name service (may fail if we are the skb or ramfsd!)
250     err = nameservice_client_blocking_bind();
251     if (err_is_fail(err)) {
252         if (err_no(err) == LIB_ERR_GET_NAME_IREF) {
253             // skip everything else if we don't have a nameservice
254             return SYS_ERR_OK;
255         } else {
256             return err_push(err, LIB_ERR_NAMESERVICE_CLIENT_INIT);
257         }
258     }
259
260     // init terminal
261     err = terminal_init();
262     if (err_is_fail(err)) {
263         return err_push(err, LIB_ERR_TERMINAL_INIT);
264     }
265
266     // Init domain spanning code
267     err = domain_init();
268     if (err_is_fail(err)) {
269         return err_push(err, LIB_ERR_DOMAIN_INIT);
270     }
271
272     return err;
273 }
274
275 static void monitor_bind_cont(void *st, errval_t err, struct monitor_binding *b)
276 {
277     // hacky errval_t state pointer used to signal completion
278     errval_t *init_complete_err = st;
279
280     assert(!init_domain);
281     *init_complete_err = err;
282
283     // signal completion
284     request_done = true;
285 }
286
287 /**
288  *  \brief Initialise libbarrelfish, while disabled.
289  *
290  * This runs on the dispatcher's stack, while disabled, before the dispatcher is
291  * setup. We can't call anything that needs to be enabled (ie. cap invocations)
292  * or uses threads. This is called from crt0.
293  */
294 void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg);
295 void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg)
296 {
297     init_domain = init_dom_arg;
298     disp_init_disabled(handle);
299     thread_init_disabled(handle, init_dom_arg);
300 }