6 * Copyright (c) 2009, 2010, 2011, ETH Zurich.
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
19 #include <barrelfish/barrelfish.h>
20 #include <barrelfish/nameservice_client.h>
21 #include <barrelfish/cpu_arch.h>
22 /* #include <barrelfish/terminal.h> */
24 #include <vfs/vfs_path.h>
25 #include <spawndomain/spawndomain.h>
26 #include <if/arrakis_defs.h>
27 #include <if/monitor_blocking_rpcclient_defs.h>
28 /* #include <timer/timer.h> */
31 #define SERVICE_BASENAME "arrakis" // the core ID is appended to this
33 static errval_t spawn_arrakis(const char *path, char *const argv[], const char *argbuf,
34 size_t argbytes, char *const envp[],
35 struct capref inheritcn_cap, struct capref argcn_cap,
40 /* read file into memory */
42 err = vfs_open(path, &fh);
43 if (err_is_fail(err)) {
44 return err_push(err, SPAWN_ERR_LOAD);
47 struct vfs_fileinfo info;
48 err = vfs_stat(fh, &info);
49 if (err_is_fail(err)) {
51 return err_push(err, SPAWN_ERR_LOAD);
54 assert(info.type == VFS_FILE);
55 uint8_t *image = malloc(info.size);
58 return err_push(err, SPAWN_ERR_LOAD);
61 size_t pos = 0, readlen;
63 err = vfs_read(fh, &image[pos], info.size - pos, &readlen);
64 if (err_is_fail(err)) {
67 return err_push(err, SPAWN_ERR_LOAD);
68 } else if (readlen == 0) {
71 return SPAWN_ERR_LOAD; // XXX
75 } while (err_is_ok(err) && readlen > 0 && pos < info.size);
78 if (err_is_fail(err)) {
79 DEBUG_ERR(err, "failed to close file %s", path);
82 // find short name (last part of path)
83 const char *name = strrchr(path, VFS_PATH_SEP);
92 err = spawn_load_image(&si, (lvaddr_t)image, info.size, CURRENT_CPU_TYPE,
93 name, disp_get_core_id(), argv, envp, inheritcn_cap,
95 if (err_is_fail(err)) {
102 /* request connection from monitor */
103 struct monitor_blocking_rpc_client *mrpc = get_monitor_blocking_rpc_client();
105 err = mrpc->vtbl.alloc_monitor_ep(mrpc, &msgerr, &monep);
106 if (err_is_fail(err)) {
107 return err_push(err, SPAWN_ERR_MONITOR_CLIENT);
108 } else if (err_is_fail(msgerr)) {
112 /* copy connection into the new domain */
113 struct capref destep = {
115 .slot = TASKCN_SLOT_MONITOREP,
117 err = cap_copy(destep, monep);
118 if (err_is_fail(err)) {
121 return err_push(err, SPAWN_ERR_MONITOR_CLIENT);
124 err = cap_destroy(monep);
125 if (err_is_fail(err)) {
126 return err_push(err, SPAWN_ERR_MONITOR_CLIENT);
129 debug_printf("spawning %s on core %u\n", path, disp_get_core_id());
131 /* give the perfmon capability */
132 struct capref dest, src;
133 dest.cnode = si.taskcn;
134 dest.slot = TASKCN_SLOT_PERF_MON;
135 src.cnode = cnode_task;
136 src.slot = TASKCN_SLOT_PERF_MON;
137 err = cap_copy(dest, src);
138 if (err_is_fail(err)) {
139 return err_push(err, INIT_ERR_COPY_PERF_MON);
142 // Create a new guest control structure
143 struct guest *g = guest_create();
147 spawn_guest_domain(g, &si);
149 err = guest_make_runnable(g, true);
150 assert_err(err, "guest_make_runnable");
152 // Allocate domain id
153 struct ps_entry *pe = malloc(sizeof(struct ps_entry));
155 memset(pe, 0, sizeof(struct ps_entry));
156 memcpy(pe->argv, (CONST_CAST)argv, MAX_CMDLINE_ARGS*sizeof(*argv));
158 pe->argbytes = argbytes;
160 * NB: It's important to keep a copy of the DCB *and* the root
161 * CNode around. We need to revoke both (in the right order, see
162 * kill_domain() below), so that we ensure no one else is
163 * referring to the domain's CSpace anymore. Especially the loop
164 * created by placing rootcn into its own address space becomes a
167 err = slot_alloc(&pe->rootcn_cap);
168 assert(err_is_ok(err));
169 err = cap_copy(pe->rootcn_cap, si.rootcn_cap);
170 pe->rootcn = si.rootcn;
171 assert(err_is_ok(err));
172 err = slot_alloc(&pe->dcb);
173 assert(err_is_ok(err));
174 err = cap_copy(pe->dcb, si.dcb);
175 assert(err_is_ok(err));
176 pe->status = PS_STATUS_RUNNING;
177 err = ps_allocate(pe, domainid);
178 if(err_is_fail(err)) {
182 // Store in target dispatcher frame
183 struct dispatcher_generic *dg = get_dispatcher_generic(si.handle);
184 dg->domain_id = *domainid;
187 err = spawn_free(&si);
188 if (err_is_fail(err)) {
189 return err_push(err, SPAWN_ERR_FREE);
195 struct pending_spawn_response {
196 struct arrakis_binding *b;
201 static void retry_spawn_domain_response(void *a)
205 struct pending_spawn_response *r = (struct pending_spawn_response*)a;
206 struct arrakis_binding *b = r->b;
208 err = b->tx_vtbl.spawn_arrakis_domain_response(b, NOP_CONT, r->err, r->domainid);
210 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
212 err = b->register_send(b, get_default_waitset(),
213 MKCONT(retry_spawn_domain_response,a));
215 if (err_is_fail(err)) {
216 DEBUG_ERR(err, "error sending spawn_domain reply\n");
223 static errval_t spawn_reply(struct arrakis_binding *b, errval_t rerr,
228 err = b->tx_vtbl.spawn_arrakis_domain_response(b, NOP_CONT, rerr, domainid);
230 if (err_is_fail(err)) {
231 DEBUG_ERR(err, "error sending spawn_domain reply\n");
233 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
234 // this will be freed in the retry handler
235 struct pending_spawn_response *sr =
236 malloc(sizeof(struct pending_spawn_response));
238 return LIB_ERR_MALLOC_FAIL;
242 sr->domainid = domainid;
243 err = b->register_send(b, get_default_waitset(),
244 MKCONT(retry_spawn_domain_response, sr));
245 if (err_is_fail(err)) {
246 // note that only one continuation may be registered at a time
248 DEBUG_ERR(err, "register_send failed!");
258 static void spawn_with_caps_handler(struct arrakis_binding *b, const char *path,
259 const char *argbuf, size_t argbytes,
260 const char *envbuf, size_t envbytes,
261 struct capref inheritcn_cap,
262 struct capref argcn_cap)
265 domainid_t domainid = 0;
267 /* printf("arrakismon: spawning '%s'\n", path); */
269 /* extract arguments from buffer */
270 char * argv[MAX_CMDLINE_ARGS + 1];
273 while (pos < argbytes && i < MAX_CMDLINE_ARGS) {
274 argv[i++] = (CONST_CAST)argbuf + pos;
275 char *end = memchr(&argbuf[pos], '\0', argbytes - pos);
277 err = SPAWN_ERR_GET_CMDLINE_ARGS;
280 pos = end - argbuf + 1;
282 assert(i <= MAX_CMDLINE_ARGS);
285 /* extract environment from buffer */
286 char *envp[MAX_CMDLINE_ARGS + 1];
289 while (pos < envbytes && i < MAX_CMDLINE_ARGS) {
290 envp[i++] = (CONST_CAST)envbuf + pos;
291 char *end = memchr(&envbuf[pos], '\0', envbytes - pos);
293 err = SPAWN_ERR_GET_CMDLINE_ARGS;
296 pos = end - envbuf + 1;
298 assert(i <= MAX_CMDLINE_ARGS);
301 char *npath = alloca(strlen(path));
303 vfs_path_normalise(npath);
305 err = spawn_arrakis(npath, argv, argbuf, argbytes, envp, inheritcn_cap,
306 argcn_cap, &domainid);
307 if (!capref_is_null(inheritcn_cap)) {
309 err2 = cap_delete(inheritcn_cap);
310 assert(err_is_ok(err2));
312 if (!capref_is_null(argcn_cap)) {
314 err2 = cap_delete(argcn_cap);
315 assert(err_is_ok(err2));
319 if(err_is_fail(err)) {
320 DEBUG_ERR(err, "spawn");
323 err = spawn_reply(b, err, domainid);
325 if (err_is_fail(err)) {
326 // not much we can do about this
327 DEBUG_ERR(err, "while sending reply in spawn_handler");
332 static void spawn_handler(struct arrakis_binding *b, const char *path, const char *argbuf,
333 size_t argbytes, const char *envbuf, size_t envbytes)
335 spawn_with_caps_handler(b, path, argbuf, argbytes, envbuf, envbytes,
339 static struct arrakis_rx_vtbl rx_vtbl = {
340 .spawn_arrakis_domain_call = spawn_handler,
343 static void export_cb(void *st, errval_t err, iref_t iref)
345 if (err_is_fail(err)) {
346 USER_PANIC_ERR(err, "export failed");
351 size_t len = snprintf(namebuf, sizeof(namebuf), "%s.%d", SERVICE_BASENAME,
353 assert(len < sizeof(namebuf));
354 namebuf[sizeof(namebuf) - 1] = '\0';
356 // register this iref with the name service
357 err = nameservice_register(namebuf, iref);
358 if (err_is_fail(err)) {
359 USER_PANIC_ERR(err, "nameservice_register failed");
363 static errval_t connect_cb(void *st, struct arrakis_binding *b)
365 // copy my message receive handler vtable to the binding
366 b->rx_vtbl = rx_vtbl;
370 static errval_t start_service(void)
372 return arrakis_export(NULL, export_cb, connect_cb, get_default_waitset(),
373 IDC_EXPORT_FLAGS_DEFAULT);
376 int main (int argc, char *argv[])
380 /* err = timer_init(); */
381 /* if (err_is_fail(err)) { */
382 /* USER_PANIC_ERR(err, "error initialising timer client library\n"); */
387 err = realmode_init();
388 assert_err(err, "realmode_init");
390 // aquire the standard input
391 err = terminal_want_stdin(TERMINAL_SOURCE_SERIAL);
392 assert_err(err, "terminal_want_stdin");
395 // Start arrakis service
398 // Spawn test arrakis application
399 /* err = spawn_arrakis("/x86_64/sbin/hellotest", ); */
400 /* assert_err(err, "spawn_arrakis"); */
403 guest = guest_create ();
404 assert(guest != NULL);
405 err = guest_make_runnable(guest, true);
406 assert_err(err, "guest_make_runnable");
408 printf("arrakismon: main loop\n");
411 messages_handler_loop();