/** * \brief Spawn a domain with the given args */ errval_t spawn_load_with_args(struct spawninfo *si, struct mem_region *module, const char *name, coreid_t coreid, char *const argv[], char *const envp[]) { errval_t err; /* Lookup and map the elf image */ lvaddr_t binary; size_t binary_size; err = spawn_map_module(module, &binary_size, &binary, NULL); //err = spawn_map(name, bi, &binary, &binary_size); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_ELF_MAP); } /* Determine cpu type */ err = spawn_determine_cputype(si, binary); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_DETERMINE_CPUTYPE); } /* Initialize cspace */ err = spawn_setup_cspace(si); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SETUP_CSPACE); } /* Initialize vspace */ err = spawn_setup_vspace(si); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_VSPACE_INIT); } /* Load the image */ genvaddr_t entry; void* arch_info; si->name = name; err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_LOAD); } /* Setup dispatcher frame */ err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SETUP_DISPATCHER); } /* Setup cmdline args */ err = spawn_setup_env(si, argv, envp); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SETUP_ENV); } return SYS_ERR_OK; }
static errval_t getimage(struct mem_region *region, size_t *retlen, lvaddr_t *retdata) { // map in the real module (FIXME: leaking it afterwards) size_t len; errval_t err = spawn_map_module(region, &len, retdata, NULL); if (err_is_ok(err)) { assert(len >= region->mrmod_size); *retlen = region->mrmod_size; } return err; }
/** * \brief Spawn a domain and give it the bootinfo struct. * Just monitor and memserv should be spawned using this. */ errval_t spawn_load_with_bootinfo(struct spawninfo *si, struct bootinfo *bi, const char *name, coreid_t coreid) { errval_t err; /* Get the module from the multiboot */ struct mem_region *module = multiboot_find_module(bi, name); if (module == NULL) { return SPAWN_ERR_FIND_MODULE; } /* Lookup and map the elf image */ lvaddr_t binary; size_t binary_size; err = spawn_map_module(module, &binary_size, &binary, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_ELF_MAP); } /* Determine cpu type */ err = spawn_determine_cputype(si, binary); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_DETERMINE_CPUTYPE); } /* Initialize cspace */ err = spawn_setup_cspace(si); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SETUP_CSPACE); } /* Initialize vspace */ err = spawn_setup_vspace(si); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_VSPACE_INIT); } /* Load the image */ genvaddr_t entry; void* arch_info; si->name = name; err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_LOAD); } /* Setup dispatcher frame */ err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SETUP_DISPATCHER); } /* Map bootinfo */ // XXX: Confusion address translation about l/gen/addr in entry genvaddr_t vaddr; err = spawn_map_bootinfo(si, &vaddr); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_MAP_BOOTINFO); } /* Construct cmdline args, 0 is name, 1 is bootinfo address, remaining are from the multiboot */ // Name char args[1024]; strcpy(args, name); strcat(args, " "); // bootinfo addr char vaddr_char[32]; // NB format here should be PRIuGENVADDR, but our ARM compiler has // an out-by-4 bytes issue when rendering 64-bit numbers using // __builtin_va_start/__builtin_va_arg. // [ gcc version 4.4.1 (Sourcery G++ Lite 2009q3-67) ] snprintf(vaddr_char, sizeof(vaddr_char), "%" PRIuPTR, (uintptr_t)vaddr); strcat(args, vaddr_char); strcat(args, " "); #ifdef __scc__ if(si->codeword == 0xcafebabe) { strcat(args, si->append_args); strcat(args, " "); } if(!strcmp(name, "scc/sbin/monitor")) { printf("starting monitor as '%s'\n", args); } #endif // Multiboot args char *multiboot_args; err = spawn_get_cmdline_args(module, &multiboot_args); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_GET_CMDLINE_ARGS); } // Lop off the name char *multiboot_args_lop = strchr(multiboot_args, ' '); if (multiboot_args_lop) { multiboot_args_lop++; strcat(args, multiboot_args_lop); } // Tokenize char *argv[MAX_CMDLINE_ARGS + 1]; spawn_tokenize_cmdargs(args, argv, ARRAY_LENGTH(argv)); // Setup err = spawn_setup_env(si, argv, environ); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SETUP_ENV); } free(multiboot_args); // unmap bootinfo module pages spawn_unmap_module(binary); return SYS_ERR_OK; }
/** * \brief Setup an initial cspace * * Create an initial cspace layout */ static errval_t spawn_setup_cspace(struct spawninfo *si) { errval_t err; struct capref t1; /* Create root CNode */ err = cnode_create(&si->rootcn_cap, &si->rootcn, DEFAULT_CNODE_SLOTS, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_ROOTCN); } /* Create taskcn */ err = cnode_create(&si->taskcn_cap, &si->taskcn, DEFAULT_CNODE_SLOTS, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_TASKCN); } // Mint into rootcn setting the guard t1.cnode = si->rootcn; t1.slot = ROOTCN_SLOT_TASKCN; err = cap_mint(t1, si->taskcn_cap, 0, GUARD_REMAINDER(2 * DEFAULT_CNODE_BITS)); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_MINT_TASKCN); } /* Create slot_alloc_cnode */ t1.cnode = si->rootcn; t1.slot = ROOTCN_SLOT_SLOT_ALLOC0; err = cnode_create_raw(t1, NULL, (1<<SLOT_ALLOC_CNODE_BITS), NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); } t1.cnode = si->rootcn; t1.slot = ROOTCN_SLOT_SLOT_ALLOC1; err = cnode_create_raw(t1, NULL, (1<<SLOT_ALLOC_CNODE_BITS), NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); } t1.cnode = si->rootcn; t1.slot = ROOTCN_SLOT_SLOT_ALLOC2; err = cnode_create_raw(t1, NULL, (1<<SLOT_ALLOC_CNODE_BITS), NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); } // Create DCB si->dcb.cnode = si->taskcn; si->dcb.slot = TASKCN_SLOT_DISPATCHER; err = dispatcher_create(si->dcb); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_DISPATCHER); } // Give domain endpoint to itself (in taskcn) struct capref selfep = { .cnode = si->taskcn, .slot = TASKCN_SLOT_SELFEP, }; err = cap_retype(selfep, si->dcb, ObjType_EndPoint, 0); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_SELFEP); } // Map root CNode (in taskcn) t1.cnode = si->taskcn; t1.slot = TASKCN_SLOT_ROOTCN; err = cap_mint(t1, si->rootcn_cap, 0, 0); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_MINT_ROOTCN); } #ifdef TRACING_EXISTS // Set up tracing for the child err = trace_setup_child(si->taskcn, si->handle); if (err_is_fail(err)) { printf("Warning: error setting up tracing for child domain\n"); // SYS_DEBUG(err, ...); } #endif // XXX: copy over argspg? memset(&si->argspg, 0, sizeof(si->argspg)); /* Fill up basecn */ struct capref basecn_cap; struct cnoderef basecn; // Create basecn in rootcn basecn_cap.cnode = si->rootcn; basecn_cap.slot = ROOTCN_SLOT_BASE_PAGE_CN; err = cnode_create_raw(basecn_cap, &basecn, DEFAULT_CNODE_SLOTS, NULL); if (err_is_fail(err)) { return err_push(err, LIB_ERR_CNODE_CREATE); } // Place the ram caps for (uint8_t i = 0; i < DEFAULT_CNODE_SLOTS; i++) { struct capref base = { .cnode = basecn, .slot = i }; struct capref ram; err = ram_alloc(&ram, BASE_PAGE_BITS); if (err_is_fail(err)) { return err_push(err, LIB_ERR_RAM_ALLOC); } err = cap_copy(base, ram); if (err_is_fail(err)) { return err_push(err, LIB_ERR_CAP_COPY); } err = cap_destroy(ram); if (err_is_fail(err)) { return err_push(err, LIB_ERR_CAP_DESTROY); } } return SYS_ERR_OK; } static errval_t spawn_setup_vspace(struct spawninfo *si) { errval_t err; /* Create pagecn */ si->pagecn_cap = (struct capref){.cnode = si->rootcn, .slot = ROOTCN_SLOT_PAGECN}; err = cnode_create_raw(si->pagecn_cap, &si->pagecn, PAGE_CNODE_SLOTS, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_PAGECN); } /* Init pagecn's slot allocator */ // XXX: satisfy a peculiarity of the single_slot_alloc_init_raw API size_t bufsize = SINGLE_SLOT_ALLOC_BUFLEN(PAGE_CNODE_SLOTS); void *buf = malloc(bufsize); assert(buf != NULL); err = single_slot_alloc_init_raw(&si->pagecn_slot_alloc, si->pagecn_cap, si->pagecn, PAGE_CNODE_SLOTS, buf, bufsize); if (err_is_fail(err)) { return err_push(err, LIB_ERR_SINGLE_SLOT_ALLOC_INIT_RAW); } // Create root of pagetable err = si->pagecn_slot_alloc.a.alloc(&si->pagecn_slot_alloc.a, &si->vtree); if (err_is_fail(err)) { return err_push(err, LIB_ERR_SLOT_ALLOC); } // top-level table should always live in slot 0 of pagecn assert(si->vtree.slot == 0); switch(si->cpu_type) { case CPU_X86_64: case CPU_K1OM: err = vnode_create(si->vtree, ObjType_VNode_x86_64_pml4); break; case CPU_X86_32: case CPU_SCC: #ifdef CONFIG_PAE err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdpt); #else err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdir); #endif break; case CPU_ARM5: case CPU_ARM7: err = vnode_create(si->vtree, ObjType_VNode_ARM_l1); break; default: assert(!"Other architecture"); return err_push(err, SPAWN_ERR_UNKNOWN_TARGET_ARCH); } if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_VNODE); } err = spawn_vspace_init(si, si->vtree, si->cpu_type); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_VSPACE_INIT); } return SYS_ERR_OK; } #if 0 /** * \brief Lookup and map an image */ static errval_t spawn_map(const char *name, struct bootinfo *bi, lvaddr_t *binary, size_t *binary_size) { errval_t err; /* Get the module from the multiboot */ struct mem_region *module = multiboot_find_module(bi, name); if (module == NULL) { return SPAWN_ERR_FIND_MODULE; } /* Map the image */ err = spawn_map_module(module, binary_size, binary, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_MAP_MODULE); } return SYS_ERR_OK; }
static void populate_multiboot(struct dirent *root, struct bootinfo *bi) { lvaddr_t data; size_t len; errval_t err; assert(root != NULL); // create bootscript file struct dirent *bootscript_f; err = ramfs_create(root, BOOTSCRIPT_FILE_NAME, &bootscript_f); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error creating bootscript file"); } debug_printf("pre-populating from boot image...\n"); for (int i = 0; i < bi->regions_length; i++) { struct mem_region *region = &bi->regions[i]; if (region->mr_type != RegionType_Module) { /* Not of module type */ continue; } const char *name = remove_prefix(multiboot_module_name(region)); // is this a ramfs image we should unpack? if (strstr(name, "_ramfs.cpio.gz") != NULL) { debug_printf("unpacking Gzipped CPIO %s\n", name); err = spawn_map_module(region, &len, &data, NULL); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error in spawn_map_module"); } err = unpack_cpiogz(root, (void *)data, len); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error unpacking ramfs image"); } // TODO: unmap } else if (strstr(name, "_ramfs.cpio") != NULL) { debug_printf("unpacking CPIO %s\n", name); err = spawn_map_module(region, &len, &data, NULL); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error in spawn_map_module"); } err = unpack_cpio(root, (void *)data, len); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error unpacking ramfs image"); } // TODO: unmap } else { // map the image err = getimage(region, &len, &data); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error in getimage"); } // copy to ramfs err = write_file(root, name, (void *)data, len); if (err_is_fail(err)) { if (err_no(err) == FS_ERR_EXISTS) { debug_printf("%s already exists, skipping it\n", name); } else { USER_PANIC_ERR(err, "error in write_file"); } } // TODO: unmap // append line to bootscript const char *args = remove_prefix(multiboot_module_rawstring(region)); err = append_to_file(bootscript_f, args); if (err_is_fail(err)) { USER_PANIC_ERR(err, "error appending to bootscript"); } } } debug_printf("ready\n"); }