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