T258: refactor creation of new cspaces to make it cleaner
[barrelfish] / lib / spawndomain / spawn.c
1 /**
2  * \file
3  * \brief functionality to spawn domains
4  */
5
6 /*
7  * Copyright (c) 2007-2012, ETH Zurich.
8  * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
14  */
15
16 #include <string.h>
17 #include <stdio.h>
18 #include <inttypes.h>
19 #include <barrelfish/barrelfish.h>
20 #include <spawndomain/spawndomain.h>
21 #include <barrelfish/dispatcher_arch.h>
22 #include <barrelfish/spawn_client.h>
23 #include <barrelfish_kpi/domain_params.h>
24 #include <trace/trace.h>
25 #include "spawn.h"
26 #include "arch.h"
27 #include <elf/elf.h>
28
29 extern char **environ;
30
31 /**
32  * \brief Setup an initial cspace
33  *
34  * Create an initial cspace layout
35  */
36 static errval_t spawn_setup_cspace(struct spawninfo *si)
37 {
38     errval_t err;
39     struct capref t1;
40
41     /* Create root CNode */
42     err = cnode_create_l1(&si->rootcn_cap, &si->rootcn);
43     if (err_is_fail(err)) {
44         return err_push(err, SPAWN_ERR_CREATE_ROOTCN);
45     }
46
47     /* Create taskcn */
48     err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_TASKCN, &si->taskcn);
49     if (err_is_fail(err)) {
50         return err_push(err, SPAWN_ERR_CREATE_TASKCN);
51     }
52
53     /* Create slot_alloc_cnode */
54     err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_SLOT_ALLOC0, NULL);
55     if (err_is_fail(err)) {
56         return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE);
57     }
58     err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_SLOT_ALLOC1, NULL);
59     if (err_is_fail(err)) {
60         return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE);
61     }
62     err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_SLOT_ALLOC2, NULL);
63     if (err_is_fail(err)) {
64         return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE);
65     }
66
67     // Create DCB: make si->dcb invokable
68     err = slot_alloc(&si->dcb);
69     if (err_is_fail(err)) {
70         return err_push(err, LIB_ERR_SLOT_ALLOC);
71     }
72     err = dispatcher_create(si->dcb);
73     if (err_is_fail(err)) {
74         return err_push(err, SPAWN_ERR_CREATE_DISPATCHER);
75     }
76
77     // Copy DCB to new taskcn
78     t1.cnode = si->taskcn;
79     t1.slot  = TASKCN_SLOT_DISPATCHER;
80     err = cap_copy(t1, si->dcb);
81     if (err_is_fail(err)) {
82         return err_push(err, LIB_ERR_CAP_COPY);
83     }
84
85     // Give domain endpoint to itself (in taskcn)
86     struct capref selfep = {
87         .cnode = si->taskcn,
88         .slot = TASKCN_SLOT_SELFEP,
89     };
90     // XXX: could redo retyping of EPs now, and actually give offset and stuff
91     err = cap_retype(selfep, si->dcb, 0, ObjType_EndPoint, 0, 1);
92     if (err_is_fail(err)) {
93         return err_push(err, SPAWN_ERR_CREATE_SELFEP);
94     }
95
96     // Map root CNode (in taskcn)
97     t1.cnode = si->taskcn;
98     t1.slot  = TASKCN_SLOT_ROOTCN;
99     err = cap_copy(t1, si->rootcn_cap);
100     if (err_is_fail(err)) {
101         return err_push(err, SPAWN_ERR_MINT_ROOTCN);
102     }
103
104 #ifdef TRACING_EXISTS
105     // Set up tracing for the child
106     err = trace_setup_child(si->taskcn, si->handle);
107     if (err_is_fail(err)) {
108         printf("Warning: error setting up tracing for child domain\n");
109         // SYS_DEBUG(err, ...);
110     }
111 #endif
112
113     // XXX: copy over argspg?
114     memset(&si->argspg, 0, sizeof(si->argspg));
115
116     /* Fill up basecn */
117     struct cnoderef basecn;
118
119     // Create basecn in our rootcn so we can copy stuff in there
120     err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_BASE_PAGE_CN, &basecn);
121     if (err_is_fail(err)) {
122         return err_push(err, LIB_ERR_CNODE_CREATE);
123     }
124
125     // get big RAM cap for L2_CNODE_SLOTS BASE_PAGE_SIZEd caps
126     struct capref ram;
127     err = ram_alloc(&ram, L2_CNODE_BITS + BASE_PAGE_BITS);
128     if (err_is_fail(err)) {
129         return err_push(err, LIB_ERR_RAM_ALLOC);
130     }
131
132     // retype big RAM cap into small caps in new basecn
133     struct capref base = {
134         .cnode = basecn,
135         .slot = 0,
136     };
137     err = cap_retype(base, ram, 0, ObjType_RAM, BASE_PAGE_SIZE, L2_CNODE_SLOTS);
138     if (err_is_fail(err)) {
139         return err_push(err, LIB_ERR_CAP_RETYPE);
140     }
141
142     // delete big RAM cap
143     err = cap_destroy(ram);
144     if (err_is_fail(err)) {
145         return err_push(err, LIB_ERR_CAP_DESTROY);
146     }
147
148     return SYS_ERR_OK;
149 }
150
151 static errval_t spawn_setup_vspace(struct spawninfo *si)
152 {
153     errval_t err;
154
155     /* Create pagecn */
156     err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_PAGECN, &si->pagecn);
157     if (err_is_fail(err)) {
158         return err_push(err, SPAWN_ERR_CREATE_PAGECN);
159     }
160
161     /* Init pagecn's slot allocator */
162     si->pagecn_cap.cnode = si->rootcn;
163     si->pagecn_cap.slot = ROOTCN_SLOT_PAGECN;
164
165     // XXX: satisfy a peculiarity of the single_slot_alloc_init_raw API
166     size_t bufsize = SINGLE_SLOT_ALLOC_BUFLEN(PAGE_CNODE_SLOTS);
167     void *buf = malloc(bufsize);
168     assert(buf != NULL);
169
170     err = single_slot_alloc_init_raw(&si->pagecn_slot_alloc, si->pagecn_cap,
171                                      si->pagecn, PAGE_CNODE_SLOTS,
172                                      buf, bufsize);
173     if (err_is_fail(err)) {
174         return err_push(err, LIB_ERR_SINGLE_SLOT_ALLOC_INIT_RAW);
175     }
176
177     // Create root of pagetable
178     err = si->pagecn_slot_alloc.a.alloc(&si->pagecn_slot_alloc.a, &si->vtree);
179     if (err_is_fail(err)) {
180         return err_push(err, LIB_ERR_SLOT_ALLOC);
181     }
182
183     // top-level table should always live in slot 0 of pagecn
184     assert(si->vtree.slot == 0);
185
186     switch(si->cpu_type) {
187     case CPU_X86_64:
188     case CPU_K1OM:
189         err = vnode_create(si->vtree, ObjType_VNode_x86_64_pml4);
190         break;
191
192     case CPU_X86_32:
193 #ifdef CONFIG_PAE
194         err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdpt);
195 #else
196         err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdir);
197 #endif
198         break;
199
200     case CPU_ARM7:
201         err = vnode_create(si->vtree, ObjType_VNode_ARM_l1);
202         break;
203
204     case CPU_ARM8:
205         err = vnode_create(si->vtree, ObjType_VNode_AARCH64_l0);
206         break;
207
208     default:
209         assert(!"Other architecture");
210         return err_push(err, SPAWN_ERR_UNKNOWN_TARGET_ARCH);
211     }
212
213     if (err_is_fail(err)) {
214         return err_push(err, SPAWN_ERR_CREATE_VNODE);
215     }
216
217     err = spawn_vspace_init(si, si->vtree, si->cpu_type);
218     if (err_is_fail(err)) {
219         return err_push(err, SPAWN_ERR_VSPACE_INIT);
220     }
221
222     return SYS_ERR_OK;
223 }
224
225 #if 0
226 /**
227  * \brief Lookup and map an image
228  */
229 static errval_t spawn_map(const char *name, struct bootinfo *bi,
230                           lvaddr_t *binary, size_t *binary_size)
231 {
232     errval_t err;
233
234     /* Get the module from the multiboot */
235     struct mem_region *module = multiboot_find_module(bi, name);
236     if (module == NULL) {
237         return SPAWN_ERR_FIND_MODULE;
238     }
239
240     /* Map the image */
241     err = spawn_map_module(module, binary_size, binary, NULL);
242     if (err_is_fail(err)) {
243         return err_push(err, SPAWN_ERR_MAP_MODULE);
244     }
245
246     return SYS_ERR_OK;
247 }
248 #endif // 0
249
250
251 /**
252  * \brief Determine cpu type of the image
253  */
254 static errval_t spawn_determine_cputype(struct spawninfo *si, lvaddr_t binary)
255 {
256     struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)binary;
257
258     switch(head->e_machine) {
259     case EM_K1OM:
260         si->cpu_type = CPU_K1OM;
261         break;
262     case EM_X86_64:
263         si->cpu_type = CPU_X86_64;
264         break;
265
266     case EM_386:
267         si->cpu_type = CPU_X86_32;
268         break;
269
270     case EM_ARM:
271         si->cpu_type = CPU_ARM7;
272         break;
273
274     case EM_AARCH64:
275         si->cpu_type = CPU_ARM8;
276         break;
277
278     default:
279         assert(!"Unsupported architecture type");
280         return SPAWN_ERR_UNKNOWN_TARGET_ARCH;
281     }
282
283     return SYS_ERR_OK;
284 }
285
286 /**
287  * \brief Setup the dispatcher frame
288  */
289 static errval_t spawn_setup_dispatcher(struct spawninfo *si,
290                                        coreid_t core_id,
291                                        const char *name,
292                                        genvaddr_t entry,
293                                        void* arch_info)
294 {
295     errval_t err;
296
297     /* Create dispatcher frame (in taskcn) */
298     si->dispframe.cnode = si->taskcn;
299     si->dispframe.slot  = TASKCN_SLOT_DISPFRAME;
300     err = frame_create(si->dispframe, (1 << DISPATCHER_FRAME_BITS), NULL);
301     if (err_is_fail(err)) {
302         return err_push(err, SPAWN_ERR_CREATE_DISPATCHER_FRAME);
303     }
304
305     /* Map in dispatcher frame */
306     dispatcher_handle_t handle;
307     err = vspace_map_one_frame((void**)&handle, 1ul << DISPATCHER_FRAME_BITS,
308                                si->dispframe, NULL, NULL);
309     if (err_is_fail(err)) {
310         return err_push(err, SPAWN_ERR_MAP_DISPATCHER_TO_SELF);
311     }
312     genvaddr_t spawn_dispatcher_base;
313     err = spawn_vspace_map_one_frame(si, &spawn_dispatcher_base, si->dispframe,
314                                      1UL << DISPATCHER_FRAME_BITS);
315     if (err_is_fail(err)) {
316         return err_push(err, SPAWN_ERR_MAP_DISPATCHER_TO_NEW);
317     }
318
319     /* Set initial state */
320     // XXX: Confusion address translation about l/gen/addr in entry
321     struct dispatcher_shared_generic *disp =
322         get_dispatcher_shared_generic(handle);
323     struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
324     arch_registers_state_t *enabled_area =
325         dispatcher_get_enabled_save_area(handle);
326     arch_registers_state_t *disabled_area =
327         dispatcher_get_disabled_save_area(handle);
328
329     /* Place core_id */
330     disp_gen->core_id = core_id;
331
332     /* place eh information */
333     disp_gen->eh_frame = si->eh_frame;
334     disp_gen->eh_frame_size = si->eh_frame_size;
335     disp_gen->eh_frame_hdr = si->eh_frame_hdr;
336     disp_gen->eh_frame_hdr_size = si->eh_frame_hdr_size;
337
338     /* Setup dispatcher and make it runnable */
339     disp->udisp = spawn_dispatcher_base;
340     disp->disabled = 1;
341     disp->fpu_trap = 1;
342 #ifdef __k1om__
343     disp->xeon_phi_id = disp_xeon_phi_id();
344 #endif
345
346     // Copy the name for debugging
347     const char *copy_name = strrchr(name, '/');
348     if (copy_name == NULL) {
349         copy_name = name;
350     } else {
351         copy_name++;
352     }
353     strncpy(disp->name, copy_name, DISP_NAME_LEN);
354
355     spawn_arch_set_registers(arch_info, handle, enabled_area, disabled_area);
356     registers_set_entry(disabled_area, entry);
357
358     si->handle = handle;
359     return SYS_ERR_OK;
360
361 }
362
363 errval_t spawn_map_bootinfo(struct spawninfo *si, genvaddr_t *retvaddr)
364 {
365     errval_t err;
366
367     struct capref src = {
368         .cnode = cnode_task,
369         .slot  = TASKCN_SLOT_BOOTINFO
370     };
371     struct capref dest = {
372         .cnode = si->taskcn,
373         .slot  = TASKCN_SLOT_BOOTINFO
374     };
375     err = cap_copy(dest, src);
376     if (err_is_fail(err)) {
377         return err_push(err, LIB_ERR_CAP_COPY);
378     }
379
380     err = spawn_vspace_map_one_frame(si, retvaddr, dest, BOOTINFO_SIZE);
381     if (err_is_fail(err)) {
382         return err_push(err, SPAWN_ERR_MAP_BOOTINFO);
383     }
384
385     return SYS_ERR_OK;
386 }
387
388 /**
389  * \brief Retrive the commandline args of #name
390  *
391  * The arguments are malloced into a new space so need to be freed after use
392  */
393 errval_t spawn_get_cmdline_args(struct mem_region *module,
394                                 char **retargs)
395 {
396     assert(module != NULL && retargs != NULL);
397
398     /* Get the cmdline args */
399     const char *args = getopt_module(module);
400
401     /* Allocate space */
402     *retargs = malloc(sizeof(char) * strlen(args));
403     if (!retargs) {
404         return LIB_ERR_MALLOC_FAIL;
405     }
406
407     /* Copy args */
408     strcpy(*retargs, args);
409     return SYS_ERR_OK;
410 }
411
412 /**
413  * \brief Returns tokenized cmdline args
414  *
415  * \param s Argument string, which is modified in place
416  * \param argv Array to be filled-in with arguments
417  * \param argv_len Length of array available in argv, including terminator
418  *
419  * The arguments are placed in #argv, which is NULL-terminated
420  *
421  * \returns Number of arguments, not including terminator
422  *
423  * \bug Very limited handling of quoting etc.
424  */
425 int spawn_tokenize_cmdargs(char *s, char *argv[], size_t argv_len)
426 {
427     bool inquote = false;
428     int argc = 0;
429     assert(argv_len > 1);
430     assert(s != NULL);
431
432     // consume leading whitespace, and mark first argument
433     while (*s == ' ' || *s == '\t') s++;
434     if (*s != '\0') {
435         argv[argc++] = s;
436     }
437
438     while (argc + 1 < argv_len && *s != '\0') {
439         if (*s == '"') {
440             inquote = !inquote;
441             // consume quote mark, by moving remainder of string over it
442             memmove(s, s + 1, strlen(s));
443         } else if ((*s == ' ' || *s == '\t') && !inquote) { // First whitespace, arg finished
444             *s++ = '\0';
445             while (*s == ' ' || *s == '\t') s++; // Consume trailing whitespace
446             if (*s != '\0') { // New arg started
447                 argv[argc++] = s;
448             }
449         } else {
450             s++;
451         }
452     }
453
454     argv[argc] = NULL;
455     return argc;
456 }
457
458 /**
459  * \brief Setup arguments and environment
460  *
461  * \param argv   Command-line arguments, NULL-terminated
462  * \param envp   Environment, NULL-terminated
463  */
464 static errval_t spawn_setup_env(struct spawninfo *si,
465                                 char *const argv[], char *const envp[])
466 {
467     errval_t err;
468
469     // Create frame (actually multiple pages) for arguments
470     si->argspg.cnode = si->taskcn;
471     si->argspg.slot  = TASKCN_SLOT_ARGSPAGE;
472     err = frame_create(si->argspg, ARGS_SIZE, NULL);
473     if (err_is_fail(err)) {
474         return err_push(err, SPAWN_ERR_CREATE_ARGSPG);
475     }
476
477     /* Map in args frame */
478     genvaddr_t spawn_args_base;
479     err = spawn_vspace_map_one_frame(si, &spawn_args_base, si->argspg, ARGS_SIZE);
480     if (err_is_fail(err)) {
481         return err_push(err, SPAWN_ERR_MAP_ARGSPG_TO_NEW);
482     }
483
484     void *argspg;
485     err = vspace_map_one_frame(&argspg, ARGS_SIZE, si->argspg, NULL, NULL);
486     if (err_is_fail(err)) {
487         return err_push(err, SPAWN_ERR_MAP_ARGSPG_TO_SELF);
488     }
489
490     /* Layout of arguments page:
491      *   struct spawn_domain_params; // contains pointers to other fields
492      *   char buf[]; // NUL-terminated strings for arguments and environment
493      *   vspace layout data follows the string data
494      */
495     struct spawn_domain_params *params = argspg;
496     char *buf = (char *)(params + 1);
497     size_t buflen = ARGS_SIZE - (buf - (char *)argspg);
498
499     /* Copy command-line arguments */
500     int i;
501     size_t len;
502     for (i = 0; argv[i] != NULL; i++) {
503         len = strlen(argv[i]) + 1;
504         if (len > buflen) {
505             return SPAWN_ERR_ARGSPG_OVERFLOW;
506         }
507         strcpy(buf, argv[i]);
508         params->argv[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base;
509         buf += len;
510         buflen -= len;
511     }
512     assert(i <= MAX_CMDLINE_ARGS);
513     int argc = i;
514     params->argv[i] = NULL;
515
516     /* Copy environment strings */
517     for (i = 0; envp[i] != NULL; i++) {
518         len = strlen(envp[i]) + 1;
519         if (len > buflen) {
520             return SPAWN_ERR_ARGSPG_OVERFLOW;
521         }
522         strcpy(buf, envp[i]);
523         params->envp[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base;
524         buf += len;
525         buflen -= len;
526     }
527
528     assert(i <= MAX_ENVIRON_VARS);
529     params->envp[i] = NULL;
530
531     /* Serialise vspace data */
532     // XXX: align buf to next word
533     char *vspace_buf = (char *)ROUND_UP((lvaddr_t)buf, sizeof(uintptr_t));
534     buflen -= vspace_buf - buf;
535
536     // FIXME: currently just the pmap is serialised
537     err = si->vspace->pmap->f.serialise(si->vspace->pmap, vspace_buf, buflen);
538     if (err_is_fail(err)) {
539         return err_push(err, SPAWN_ERR_SERIALISE_VSPACE);
540     }
541
542     /* Setup environment pointer and vspace pointer */
543     params->argc = argc;
544     params->vspace_buf = (char *)vspace_buf - (char *)argspg
545                     + (char *)(lvaddr_t)spawn_args_base;
546     params->vspace_buf_len = buflen;
547
548     // Setup TLS data
549     params->tls_init_base = (void *)vspace_genvaddr_to_lvaddr(si->tls_init_base);
550     params->tls_init_len = si->tls_init_len;
551     params->tls_total_len = si->tls_total_len;
552
553     arch_registers_state_t *enabled_area =
554         dispatcher_get_enabled_save_area(si->handle);
555     registers_set_param(enabled_area, (uintptr_t)spawn_args_base);
556
557     return SYS_ERR_OK;
558 }
559
560 /**
561  * Copies caps from inheritcnode into destination cnode,
562  * ignores caps that to not exist.
563  *
564  * \param  inheritcn    Source cnode
565  * \param  inherit_slot Source cnode slot
566  * \param  destcn       Target cnode
567  * \param  destcn_slot  Target cnode slot
568  *
569  * \retval SYS_ERR_OK Copy to target was successful or source cap
570  * did not exist.
571  * \retval SPAWN_ERR_COPY_INHERITCN_CAP Error in cap_copy
572  */
573 static errval_t spawn_setup_inherited_cap(struct cnoderef inheritcn,
574                                           capaddr_t inherit_slot,
575                                           struct cnoderef destcn,
576                                           capaddr_t destcn_slot)
577 {
578     errval_t err;
579
580     struct capref src;
581     src.cnode = inheritcn;
582     src.slot  = inherit_slot;
583
584     // Create frame (actually multiple pages) for fds
585     struct capref dest;
586     dest.cnode = destcn;
587     dest.slot  = destcn_slot;
588
589     err = cap_copy(dest, src);
590     if (err_no(err) == SYS_ERR_SOURCE_CAP_LOOKUP) {
591         // there was no fdcap to inherit, continue
592         return SYS_ERR_OK;
593     } else if (err_is_fail(err)) {
594         return err_push(err, SPAWN_ERR_COPY_INHERITCN_CAP);
595     }
596
597     return SYS_ERR_OK;
598 }
599
600 /**
601  * Copies caps in inherited cnode into targets cspace.
602  *
603  * \param  si Target spawninfo
604  * \param  inheritcn_cap Cnode of caps to inherit
605  * \retval SYS_ERR_OK Caps have been copied.
606  */
607 static errval_t spawn_setup_inherited_caps(struct spawninfo *si,
608                                            struct capref inheritcn_cap)
609 {
610     errval_t err;
611     struct cnoderef inheritcn;
612
613     if (capref_is_null(inheritcn_cap)) {
614         return SYS_ERR_OK;
615     }
616
617     // Put inheritcn cap into root cnode so we can grab caps out of it
618     struct capref inheritcn_cncap;
619     err = slot_alloc_root(&inheritcn_cncap);
620     if (err_is_fail(err)) {
621         return err_push(err, LIB_ERR_SLOT_ALLOC);
622     }
623
624     err = cap_copy(inheritcn_cncap, inheritcn_cap);
625     if (err_is_fail(err)) {
626         return err_push(err, SPAWN_ERR_MINT_INHERITCN);
627     }
628
629     err = cnode_build_cnoderef(&inheritcn, inheritcn_cncap);
630     if (err_is_fail(err)) {
631         return err;
632     }
633
634     /* Copy the file descriptor frame cap over */
635     err = spawn_setup_inherited_cap(inheritcn, INHERITCN_SLOT_FDSPAGE,
636                                     si->taskcn, TASKCN_SLOT_FDSPAGE);
637     if (err_is_fail(err)) {
638         return err_push(err, SPAWN_ERR_SETUP_FDCAP);
639     }
640
641     /* Copy the session capability over */
642     err = spawn_setup_inherited_cap(inheritcn, INHERITCN_SLOT_SESSIONID,
643                                     si->taskcn, TASKCN_SLOT_SESSIONID);
644     if (err_is_fail(err)) {
645         return err_push(err, SPAWN_ERR_SETUP_SIDCAP);
646     }
647
648     /* Copy the kernel capability over, scary */
649     err = spawn_setup_inherited_cap(inheritcn, INHERITCN_SLOT_KERNELCAP,
650                                     si->taskcn, TASKCN_SLOT_KERNELCAP);
651     if (err_is_fail(err)) {
652         return err_push(err, SPAWN_ERR_SETUP_KERNEL_CAP);
653     }
654
655     /* Cleanup our copy of inheritcn */
656     err = cap_delete(inheritcn_cncap);
657     if (err_is_fail(err)) {
658         return err_push(err, LIB_ERR_CAP_DELETE);
659     }
660     err = slot_free(inheritcn_cncap);
661     if (err_is_fail(err)) {
662         return err_push(err, LIB_ERR_SLOT_FREE);
663     }
664
665     return SYS_ERR_OK;
666 }
667
668 static errval_t spawn_setup_argcn(struct spawninfo *si,
669                                   struct capref argumentcn_cap)
670 {
671     errval_t err;
672
673     if (capref_is_null(argumentcn_cap)) {
674         return SYS_ERR_OK;
675     }
676
677     struct capref dest = {
678         .cnode = si->rootcn,
679         .slot  = ROOTCN_SLOT_ARGCN
680     };
681
682     err = cap_copy(dest, argumentcn_cap);
683     if (err_is_fail(err)) {
684         return err_push(err, SPAWN_ERR_COPY_ARGCN);
685     }
686
687     return SYS_ERR_OK;
688 }
689
690
691 /**
692  * \brief Load an image
693  *
694  * \param si            Struct used by the library
695  * \param binary        The image to load
696  * \param type          The type of arch to load for
697  * \param name          Name of the image required only to place it in disp
698  *                      struct
699  * \param coreid        Coreid to load for, required only to place it in disp
700  *                      struct
701  * \param argv          Command-line arguments, NULL-terminated
702  * \param envp          Environment, NULL-terminated
703  * \param inheritcn_cap Cap to a CNode containing capabilities to be inherited
704  * \param argcn_cap     Cap to a CNode containing capabilities passed as
705  *                      arguments
706  */
707 errval_t spawn_load_image(struct spawninfo *si, lvaddr_t binary,
708                           size_t binary_size, enum cpu_type type,
709                           const char *name, coreid_t coreid,
710                           char *const argv[], char *const envp[],
711                           struct capref inheritcn_cap, struct capref argcn_cap)
712 {
713     errval_t err;
714
715     si->cpu_type = type;
716
717     /* Initialize cspace */
718     err = spawn_setup_cspace(si);
719     if (err_is_fail(err)) {
720         return err_push(err, SPAWN_ERR_SETUP_CSPACE);
721     }
722
723     /* Initialize vspace */
724     err = spawn_setup_vspace(si);
725     if (err_is_fail(err)) {
726         return err_push(err, SPAWN_ERR_VSPACE_INIT);
727     }
728
729     si->name = name;
730     genvaddr_t entry;
731     void* arch_info;
732     /* Load the image */
733     err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info);
734     if (err_is_fail(err)) {
735         return err_push(err, SPAWN_ERR_LOAD);
736     }
737
738     /* Setup dispatcher frame */
739     err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info);
740     if (err_is_fail(err)) {
741         return err_push(err, SPAWN_ERR_SETUP_DISPATCHER);
742     }
743
744     /* Setup inherited caps */
745     err = spawn_setup_inherited_caps(si, inheritcn_cap);
746     if (err_is_fail(err)) {
747         return err_push(err, SPAWN_ERR_SETUP_INHERITED_CAPS);
748     }
749
750     /* Setup argument caps */
751     err = spawn_setup_argcn(si, argcn_cap);
752     if (err_is_fail(err)) {
753         return err_push(err, SPAWN_ERR_SETUP_ARGCN);
754     }
755
756     // Add vspace-pspace mapping to environment
757     char envstr[2048];
758 #ifdef __x86__  // SK: si->vregions only valid on x86
759     snprintf(envstr, 2048, "ARRAKIS_PMAP=");
760     for(int i = 0; i < si->vregions; i++) {
761         struct memobj_anon *m = (struct memobj_anon *)si->vregion[i]->memobj;
762         assert(m->m.type == ANONYMOUS);
763         for(struct memobj_frame_list *f = m->frame_list; f != NULL; f = f->next) {
764             if (f->pa == 0) {
765                 struct frame_identity id;
766                 err = invoke_frame_identify(f->frame, &id);
767                 assert(err_is_ok(err));
768                 f->pa = id.base;
769             }
770
771             char str[128];
772             snprintf(str, 128, "%" PRIxGENVADDR ":%" PRIxGENPADDR ":%zx ",
773                     si->base[i] + f->offset, f->pa + f->foffset, f->size);
774             strcat(envstr, str);
775         }
776     }
777 #endif /* __x86__ */
778
779     char **myenv = (char **)envp;
780     for(int i = 0; i < MAX_ENVIRON_VARS; i++) {
781         if(i + 1 == MAX_ENVIRON_VARS) {
782             printf("spawnd: Couldn't set environemnt. Out of variables!\n");
783             abort();
784         }
785
786         if(myenv[i] == NULL) {
787             myenv[i] = envstr;
788             myenv[i+1] = NULL;
789             break;
790         }
791     }
792
793     /* Setup cmdline args */
794     err = spawn_setup_env(si, argv, envp);
795     if (err_is_fail(err)) {
796         return err_push(err, SPAWN_ERR_SETUP_ENV);
797     }
798
799     return SYS_ERR_OK;
800 }
801
802 /**
803  * \brief Spawn a domain with the given args
804  */
805 errval_t spawn_load_with_args(struct spawninfo *si, struct mem_region *module,
806                               const char *name, coreid_t coreid,
807                               char *const argv[], char *const envp[])
808 {
809     errval_t err;
810
811     /* Lookup and map the elf image */
812     lvaddr_t binary;
813     size_t binary_size;
814     err = spawn_map_module(module, &binary_size, &binary, NULL);
815     //err = spawn_map(name, bi, &binary, &binary_size);
816     if (err_is_fail(err)) {
817         return err_push(err, SPAWN_ERR_ELF_MAP);
818     }
819
820     /* Determine cpu type */
821     err = spawn_determine_cputype(si, binary);
822     if (err_is_fail(err)) {
823         return err_push(err, SPAWN_ERR_DETERMINE_CPUTYPE);
824     }
825
826     /* Initialize cspace */
827     err = spawn_setup_cspace(si);
828     if (err_is_fail(err)) {
829         return err_push(err, SPAWN_ERR_SETUP_CSPACE);
830     }
831
832     /* Initialize vspace */
833     err = spawn_setup_vspace(si);
834     if (err_is_fail(err)) {
835         return err_push(err, SPAWN_ERR_VSPACE_INIT);
836     }
837
838     /* Load the image */
839     genvaddr_t entry;
840     void* arch_info;
841     si->name = name;
842     err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info);
843     if (err_is_fail(err)) {
844         return err_push(err, SPAWN_ERR_LOAD);
845     }
846
847     /* Setup dispatcher frame */
848     err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info);
849     if (err_is_fail(err)) {
850         return err_push(err, SPAWN_ERR_SETUP_DISPATCHER);
851     }
852
853     /* Setup cmdline args */
854     err = spawn_setup_env(si, argv, envp);
855     if (err_is_fail(err)) {
856         return err_push(err, SPAWN_ERR_SETUP_ENV);
857     }
858
859     return SYS_ERR_OK;
860 }
861
862 /**
863  * \brief Spawn a domain and give it the bootinfo struct.
864  * Just monitor and memserv should be spawned using this.
865  */
866 errval_t spawn_load_with_bootinfo(struct spawninfo *si, struct bootinfo *bi,
867                                   const char *name, coreid_t coreid)
868 {
869     errval_t err;
870
871     /* Get the module from the multiboot */
872     struct mem_region *module = multiboot_find_module(bi, name);
873     if (module == NULL) {
874         return SPAWN_ERR_FIND_MODULE;
875     }
876
877     /* Lookup and map the elf image */
878     lvaddr_t binary;
879     size_t binary_size;
880     err = spawn_map_module(module, &binary_size, &binary, NULL);
881     if (err_is_fail(err)) {
882         return err_push(err, SPAWN_ERR_ELF_MAP);
883     }
884
885
886     /* Determine cpu type */
887     err = spawn_determine_cputype(si, binary);
888     if (err_is_fail(err)) {
889         return err_push(err, SPAWN_ERR_DETERMINE_CPUTYPE);
890     }
891
892     /* Initialize cspace */
893     err = spawn_setup_cspace(si);
894     if (err_is_fail(err)) {
895         return err_push(err, SPAWN_ERR_SETUP_CSPACE);
896     }
897
898     /* Initialize vspace */
899     err = spawn_setup_vspace(si);
900     if (err_is_fail(err)) {
901         return err_push(err, SPAWN_ERR_VSPACE_INIT);
902     }
903
904     /* Load the image */
905     genvaddr_t entry;
906     void* arch_info;
907     si->name = name;
908     err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info);
909     if (err_is_fail(err)) {
910         return err_push(err, SPAWN_ERR_LOAD);
911     }
912
913     /* Setup dispatcher frame */
914     err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info);
915     if (err_is_fail(err)) {
916         return err_push(err, SPAWN_ERR_SETUP_DISPATCHER);
917     }
918
919     /* Map bootinfo */
920     // XXX: Confusion address translation about l/gen/addr in entry
921     genvaddr_t vaddr;
922     err = spawn_map_bootinfo(si, &vaddr);
923     if (err_is_fail(err)) {
924         return err_push(err, SPAWN_ERR_MAP_BOOTINFO);
925     }
926
927     /* Construct cmdline args, 0 is name, 1 is bootinfo address,
928        remaining are from the multiboot */
929     // Name
930     char args[1024];
931     strcpy(args, name);
932     strcat(args, " ");
933
934     // bootinfo addr
935     char vaddr_char[32];
936
937     // NB format here should be PRIuGENVADDR, but our ARM compiler has
938     // an out-by-4 bytes issue when rendering 64-bit numbers using
939     // __builtin_va_start/__builtin_va_arg.
940     // [ gcc version 4.4.1 (Sourcery G++ Lite 2009q3-67) ]
941     snprintf(vaddr_char, sizeof(vaddr_char), "%" PRIuPTR, (uintptr_t)vaddr);
942
943     strcat(args, vaddr_char);
944     strcat(args, " ");
945
946     // Multiboot args
947     char *multiboot_args;
948     err = spawn_get_cmdline_args(module, &multiboot_args);
949     if (err_is_fail(err)) {
950         return err_push(err, SPAWN_ERR_GET_CMDLINE_ARGS);
951     }
952     // Lop off the name
953     char *multiboot_args_lop = strchr(multiboot_args, ' ');
954     if (multiboot_args_lop) {
955         multiboot_args_lop++;
956         strcat(args, multiboot_args_lop);
957     }
958
959     // Tokenize
960     char *argv[MAX_CMDLINE_ARGS + 1];
961     spawn_tokenize_cmdargs(args, argv, ARRAY_LENGTH(argv));
962
963     // Setup
964     err = spawn_setup_env(si, argv, environ);
965     if (err_is_fail(err)) {
966         return err_push(err, SPAWN_ERR_SETUP_ENV);
967     }
968     free(multiboot_args);
969
970     // unmap bootinfo module pages
971     err = spawn_unmap_module(binary);
972     if (err_is_fail(err)) {
973         return err_push(err, SPAWN_ERR_UNMAP_MODULE);
974     }
975
976     return SYS_ERR_OK;
977 }
978
979 errval_t spawn_run(struct spawninfo *si)
980 {
981     return invoke_dispatcher(si->dcb, cap_dispatcher, si->rootcn_cap,
982                              si->vtree, si->dispframe, true);
983 }
984
985 errval_t spawn_free(struct spawninfo *si)
986 {
987     cap_destroy(si->rootcn_cap);
988     cap_destroy(si->dispframe);
989     cap_destroy(si->dcb);
990     cap_destroy(si->argspg);
991
992     return SYS_ERR_OK;
993 }
994
995 /**
996  * \brief Span a domain with the given vroot and disp_frame
997  *
998  * Operation similar to spawning a domain but the vroot and disp_frame
999  * are already provided
1000  */
1001 errval_t spawn_span_domain(struct spawninfo *si, struct capref vroot,
1002                            struct capref disp_frame)
1003 {
1004     errval_t err;
1005     struct capref t1;
1006     struct cnoderef cnode;
1007
1008     /* Spawn cspace */
1009     err = spawn_setup_cspace(si);
1010     if (err_is_fail(err)) {
1011         return err;
1012     }
1013
1014     /* Create pagecn: default L2 CNode size */
1015     t1.cnode = si->rootcn;
1016     t1.slot  = ROOTCN_SLOT_PAGECN;
1017     err = cnode_create_raw(t1, NULL, ObjType_L2CNode, L2_CNODE_SLOTS, NULL);
1018     if (err_is_fail(err)) {
1019         return err_push(err, SPAWN_ERR_CREATE_PAGECN);
1020     }
1021     // XXX: fix build_cnoderef()
1022     cnode.croot = get_cap_addr(si->rootcn_cap);
1023     cnode.cnode = ROOTCN_SLOT_ADDR(ROOTCN_SLOT_PAGECN);
1024     cnode.level = CNODE_TYPE_OTHER;
1025
1026     // Copy root of pagetable
1027     si->vtree.cnode = cnode;
1028     si->vtree.slot = 0;
1029     err = cap_copy(si->vtree, vroot);
1030     if (err_is_fail(err)) {
1031         return err_push(err, SPAWN_ERR_COPY_VNODE);
1032     }
1033
1034     /* Copy dispatcher frame (in taskcn) */
1035     si->dispframe.cnode = si->taskcn;
1036     si->dispframe.slot  = TASKCN_SLOT_DISPFRAME;
1037     err = cap_copy(si->dispframe, disp_frame);
1038     if (err_is_fail(err)) {
1039         return err_push(err, SPAWN_ERR_COPY_VNODE);
1040     }
1041
1042     return SYS_ERR_OK;
1043 }