3 * \brief functionality to spawn domains
7 * Copyright (c) 2007-2012, ETH Zurich.
8 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
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.
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>
29 extern char **environ;
32 * \brief Setup an initial cspace
34 * Create an initial cspace layout
36 static errval_t spawn_setup_cspace(struct spawninfo *si)
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);
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);
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);
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);
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);
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);
72 err = dispatcher_create(si->dcb);
73 if (err_is_fail(err)) {
74 return err_push(err, SPAWN_ERR_CREATE_DISPATCHER);
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);
85 // Give domain endpoint to itself (in taskcn)
86 struct capref selfep = {
88 .slot = TASKCN_SLOT_SELFEP,
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);
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);
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, ...);
113 // XXX: copy over argspg?
114 memset(&si->argspg, 0, sizeof(si->argspg));
117 struct cnoderef basecn;
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);
125 // get big RAM cap for L2_CNODE_SLOTS BASE_PAGE_SIZEd caps
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);
132 // retype big RAM cap into small caps in new basecn
133 struct capref base = {
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);
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);
151 static errval_t spawn_setup_vspace(struct spawninfo *si)
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);
161 /* Init pagecn's slot allocator */
162 si->pagecn_cap.cnode = si->rootcn;
163 si->pagecn_cap.slot = ROOTCN_SLOT_PAGECN;
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);
170 err = single_slot_alloc_init_raw(&si->pagecn_slot_alloc, si->pagecn_cap,
171 si->pagecn, PAGE_CNODE_SLOTS,
173 if (err_is_fail(err)) {
174 return err_push(err, LIB_ERR_SINGLE_SLOT_ALLOC_INIT_RAW);
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);
183 // top-level table should always live in slot 0 of pagecn
184 assert(si->vtree.slot == 0);
186 switch(si->cpu_type) {
189 err = vnode_create(si->vtree, ObjType_VNode_x86_64_pml4);
194 err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdpt);
196 err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdir);
201 err = vnode_create(si->vtree, ObjType_VNode_ARM_l1);
205 err = vnode_create(si->vtree, ObjType_VNode_AARCH64_l0);
209 assert(!"Other architecture");
210 return err_push(err, SPAWN_ERR_UNKNOWN_TARGET_ARCH);
213 if (err_is_fail(err)) {
214 return err_push(err, SPAWN_ERR_CREATE_VNODE);
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);
227 * \brief Lookup and map an image
229 static errval_t spawn_map(const char *name, struct bootinfo *bi,
230 lvaddr_t *binary, size_t *binary_size)
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;
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);
252 * \brief Determine cpu type of the image
254 static errval_t spawn_determine_cputype(struct spawninfo *si, lvaddr_t binary)
256 struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)binary;
258 switch(head->e_machine) {
260 si->cpu_type = CPU_K1OM;
263 si->cpu_type = CPU_X86_64;
267 si->cpu_type = CPU_X86_32;
271 si->cpu_type = CPU_ARM7;
275 si->cpu_type = CPU_ARM8;
279 assert(!"Unsupported architecture type");
280 return SPAWN_ERR_UNKNOWN_TARGET_ARCH;
287 * \brief Setup the dispatcher frame
289 static errval_t spawn_setup_dispatcher(struct spawninfo *si,
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);
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);
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);
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);
330 disp_gen->core_id = core_id;
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;
338 /* Setup dispatcher and make it runnable */
339 disp->udisp = spawn_dispatcher_base;
343 disp->xeon_phi_id = disp_xeon_phi_id();
346 // Copy the name for debugging
347 const char *copy_name = strrchr(name, '/');
348 if (copy_name == NULL) {
353 strncpy(disp->name, copy_name, DISP_NAME_LEN);
355 spawn_arch_set_registers(arch_info, handle, enabled_area, disabled_area);
356 registers_set_entry(disabled_area, entry);
363 errval_t spawn_map_bootinfo(struct spawninfo *si, genvaddr_t *retvaddr)
367 struct capref src = {
369 .slot = TASKCN_SLOT_BOOTINFO
371 struct capref dest = {
373 .slot = TASKCN_SLOT_BOOTINFO
375 err = cap_copy(dest, src);
376 if (err_is_fail(err)) {
377 return err_push(err, LIB_ERR_CAP_COPY);
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);
389 * \brief Retrive the commandline args of #name
391 * The arguments are malloced into a new space so need to be freed after use
393 errval_t spawn_get_cmdline_args(struct mem_region *module,
396 assert(module != NULL && retargs != NULL);
398 /* Get the cmdline args */
399 const char *args = getopt_module(module);
402 *retargs = malloc(sizeof(char) * strlen(args));
404 return LIB_ERR_MALLOC_FAIL;
408 strcpy(*retargs, args);
413 * \brief Returns tokenized cmdline args
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
419 * The arguments are placed in #argv, which is NULL-terminated
421 * \returns Number of arguments, not including terminator
423 * \bug Very limited handling of quoting etc.
425 int spawn_tokenize_cmdargs(char *s, char *argv[], size_t argv_len)
427 bool inquote = false;
429 assert(argv_len > 1);
432 // consume leading whitespace, and mark first argument
433 while (*s == ' ' || *s == '\t') s++;
438 while (argc + 1 < argv_len && *s != '\0') {
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
445 while (*s == ' ' || *s == '\t') s++; // Consume trailing whitespace
446 if (*s != '\0') { // New arg started
459 * \brief Setup arguments and environment
461 * \param argv Command-line arguments, NULL-terminated
462 * \param envp Environment, NULL-terminated
464 static errval_t spawn_setup_env(struct spawninfo *si,
465 char *const argv[], char *const envp[])
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);
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);
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);
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
495 struct spawn_domain_params *params = argspg;
496 char *buf = (char *)(params + 1);
497 size_t buflen = ARGS_SIZE - (buf - (char *)argspg);
499 /* Copy command-line arguments */
502 for (i = 0; argv[i] != NULL; i++) {
503 len = strlen(argv[i]) + 1;
505 return SPAWN_ERR_ARGSPG_OVERFLOW;
507 strcpy(buf, argv[i]);
508 params->argv[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base;
512 assert(i <= MAX_CMDLINE_ARGS);
514 params->argv[i] = NULL;
516 /* Copy environment strings */
517 for (i = 0; envp[i] != NULL; i++) {
518 len = strlen(envp[i]) + 1;
520 return SPAWN_ERR_ARGSPG_OVERFLOW;
522 strcpy(buf, envp[i]);
523 params->envp[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base;
528 assert(i <= MAX_ENVIRON_VARS);
529 params->envp[i] = NULL;
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;
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);
542 /* Setup environment pointer and vspace pointer */
544 params->vspace_buf = (char *)vspace_buf - (char *)argspg
545 + (char *)(lvaddr_t)spawn_args_base;
546 params->vspace_buf_len = buflen;
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;
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);
561 * Copies caps from inheritcnode into destination cnode,
562 * ignores caps that to not exist.
564 * \param inheritcn Source cnode
565 * \param inherit_slot Source cnode slot
566 * \param destcn Target cnode
567 * \param destcn_slot Target cnode slot
569 * \retval SYS_ERR_OK Copy to target was successful or source cap
571 * \retval SPAWN_ERR_COPY_INHERITCN_CAP Error in cap_copy
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)
581 src.cnode = inheritcn;
582 src.slot = inherit_slot;
584 // Create frame (actually multiple pages) for fds
587 dest.slot = destcn_slot;
589 err = cap_copy(dest, src);
590 if (err_no(err) == SYS_ERR_SOURCE_CAP_LOOKUP) {
591 // there was no fdcap to inherit, continue
593 } else if (err_is_fail(err)) {
594 return err_push(err, SPAWN_ERR_COPY_INHERITCN_CAP);
601 * Copies caps in inherited cnode into targets cspace.
603 * \param si Target spawninfo
604 * \param inheritcn_cap Cnode of caps to inherit
605 * \retval SYS_ERR_OK Caps have been copied.
607 static errval_t spawn_setup_inherited_caps(struct spawninfo *si,
608 struct capref inheritcn_cap)
611 struct cnoderef inheritcn;
613 if (capref_is_null(inheritcn_cap)) {
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);
624 err = cap_copy(inheritcn_cncap, inheritcn_cap);
625 if (err_is_fail(err)) {
626 return err_push(err, SPAWN_ERR_MINT_INHERITCN);
629 err = cnode_build_cnoderef(&inheritcn, inheritcn_cncap);
630 if (err_is_fail(err)) {
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);
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);
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);
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);
660 err = slot_free(inheritcn_cncap);
661 if (err_is_fail(err)) {
662 return err_push(err, LIB_ERR_SLOT_FREE);
668 static errval_t spawn_setup_argcn(struct spawninfo *si,
669 struct capref argumentcn_cap)
673 if (capref_is_null(argumentcn_cap)) {
677 struct capref dest = {
679 .slot = ROOTCN_SLOT_ARGCN
682 err = cap_copy(dest, argumentcn_cap);
683 if (err_is_fail(err)) {
684 return err_push(err, SPAWN_ERR_COPY_ARGCN);
692 * \brief Load an image
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
699 * \param coreid Coreid to load for, required only to place it in disp
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
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)
717 /* Initialize cspace */
718 err = spawn_setup_cspace(si);
719 if (err_is_fail(err)) {
720 return err_push(err, SPAWN_ERR_SETUP_CSPACE);
723 /* Initialize vspace */
724 err = spawn_setup_vspace(si);
725 if (err_is_fail(err)) {
726 return err_push(err, SPAWN_ERR_VSPACE_INIT);
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);
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);
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);
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);
756 // Add vspace-pspace mapping to environment
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) {
765 struct frame_identity id;
766 err = invoke_frame_identify(f->frame, &id);
767 assert(err_is_ok(err));
772 snprintf(str, 128, "%" PRIxGENVADDR ":%" PRIxGENPADDR ":%zx ",
773 si->base[i] + f->offset, f->pa + f->foffset, f->size);
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");
786 if(myenv[i] == NULL) {
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);
803 * \brief Spawn a domain with the given args
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[])
811 /* Lookup and map the elf image */
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);
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);
826 /* Initialize cspace */
827 err = spawn_setup_cspace(si);
828 if (err_is_fail(err)) {
829 return err_push(err, SPAWN_ERR_SETUP_CSPACE);
832 /* Initialize vspace */
833 err = spawn_setup_vspace(si);
834 if (err_is_fail(err)) {
835 return err_push(err, SPAWN_ERR_VSPACE_INIT);
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);
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);
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);
863 * \brief Spawn a domain and give it the bootinfo struct.
864 * Just monitor and memserv should be spawned using this.
866 errval_t spawn_load_with_bootinfo(struct spawninfo *si, struct bootinfo *bi,
867 const char *name, coreid_t coreid)
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;
877 /* Lookup and map the elf image */
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);
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);
892 /* Initialize cspace */
893 err = spawn_setup_cspace(si);
894 if (err_is_fail(err)) {
895 return err_push(err, SPAWN_ERR_SETUP_CSPACE);
898 /* Initialize vspace */
899 err = spawn_setup_vspace(si);
900 if (err_is_fail(err)) {
901 return err_push(err, SPAWN_ERR_VSPACE_INIT);
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);
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);
920 // XXX: Confusion address translation about l/gen/addr in entry
922 err = spawn_map_bootinfo(si, &vaddr);
923 if (err_is_fail(err)) {
924 return err_push(err, SPAWN_ERR_MAP_BOOTINFO);
927 /* Construct cmdline args, 0 is name, 1 is bootinfo address,
928 remaining are from the multiboot */
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);
943 strcat(args, vaddr_char);
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);
953 char *multiboot_args_lop = strchr(multiboot_args, ' ');
954 if (multiboot_args_lop) {
955 multiboot_args_lop++;
956 strcat(args, multiboot_args_lop);
960 char *argv[MAX_CMDLINE_ARGS + 1];
961 spawn_tokenize_cmdargs(args, argv, ARRAY_LENGTH(argv));
964 err = spawn_setup_env(si, argv, environ);
965 if (err_is_fail(err)) {
966 return err_push(err, SPAWN_ERR_SETUP_ENV);
968 free(multiboot_args);
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);
979 errval_t spawn_run(struct spawninfo *si)
981 return invoke_dispatcher(si->dcb, cap_dispatcher, si->rootcn_cap,
982 si->vtree, si->dispframe, true);
985 errval_t spawn_free(struct spawninfo *si)
987 cap_destroy(si->rootcn_cap);
988 cap_destroy(si->dispframe);
989 cap_destroy(si->dcb);
990 cap_destroy(si->argspg);
996 * \brief Span a domain with the given vroot and disp_frame
998 * Operation similar to spawning a domain but the vroot and disp_frame
999 * are already provided
1001 errval_t spawn_span_domain(struct spawninfo *si, struct capref vroot,
1002 struct capref disp_frame)
1006 struct cnoderef cnode;
1009 err = spawn_setup_cspace(si);
1010 if (err_is_fail(err)) {
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);
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;
1026 // Copy root of pagetable
1027 si->vtree.cnode = cnode;
1029 err = cap_copy(si->vtree, vroot);
1030 if (err_is_fail(err)) {
1031 return err_push(err, SPAWN_ERR_COPY_VNODE);
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);