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