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