/** * \brief Setup arguments and environment * * \param argv Command-line arguments, NULL-terminated * \param envp Environment, NULL-terminated */ static errval_t spawn_setup_env(struct spawninfo *si, char *const argv[], char *const envp[]) { errval_t err; // Create frame (actually multiple pages) for arguments si->argspg.cnode = si->taskcn; si->argspg.slot = TASKCN_SLOT_ARGSPAGE; struct capref spawn_argspg = { .cnode = si->taskcn, .slot = TASKCN_SLOT_ARGSPAGE2, }; err = frame_create(si->argspg, ARGS_SIZE, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_ARGSPG); } err = cap_copy(spawn_argspg, si->argspg); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_CREATE_ARGSPG); } /* Map in args frame */ genvaddr_t spawn_args_base; err = spawn_vspace_map_one_frame(si, &spawn_args_base, spawn_argspg, ARGS_SIZE); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_MAP_ARGSPG_TO_NEW); } void *argspg; err = vspace_map_one_frame(&argspg, ARGS_SIZE, si->argspg, NULL, NULL); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_MAP_ARGSPG_TO_SELF); } /* Layout of arguments page: * struct spawn_domain_params; // contains pointers to other fields * char buf[]; // NUL-terminated strings for arguments and environment * vspace layout data follows the string data */ struct spawn_domain_params *params = argspg; char *buf = (char *)(params + 1); size_t buflen = ARGS_SIZE - (buf - (char *)argspg); /* Copy command-line arguments */ int i; size_t len; for (i = 0; argv[i] != NULL; i++) { len = strlen(argv[i]) + 1; if (len > buflen) { return SPAWN_ERR_ARGSPG_OVERFLOW; } strcpy(buf, argv[i]); params->argv[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base; buf += len; buflen -= len; } assert(i <= MAX_CMDLINE_ARGS); int argc = i; params->argv[i] = NULL; /* Copy environment strings */ for (i = 0; envp[i] != NULL; i++) { len = strlen(envp[i]) + 1; if (len > buflen) { return SPAWN_ERR_ARGSPG_OVERFLOW; } strcpy(buf, envp[i]); params->envp[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base; buf += len; buflen -= len; } assert(i <= MAX_ENVIRON_VARS); params->envp[i] = NULL; /* Serialise vspace data */ // XXX: align buf to next word char *vspace_buf = (char *)ROUND_UP((lvaddr_t)buf, sizeof(uintptr_t)); buflen -= vspace_buf - buf; // FIXME: currently just the pmap is serialised err = si->vspace->pmap->f.serialise(si->vspace->pmap, vspace_buf, buflen); if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_SERIALISE_VSPACE); } /* Setup environment pointer and vspace pointer */ params->argc = argc; params->vspace_buf = (char *)vspace_buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base; params->vspace_buf_len = buflen; // Setup TLS data params->tls_init_base = (void *)vspace_genvaddr_to_lvaddr(si->tls_init_base); params->tls_init_len = si->tls_init_len; params->tls_total_len = si->tls_total_len; arch_registers_state_t *enabled_area = dispatcher_get_enabled_save_area(si->handle); registers_set_param(enabled_area, (uintptr_t)spawn_args_base); return SYS_ERR_OK; } /** * Copies caps from inheritcnode into destination cnode, * ignores caps that to not exist. * * \param inheritcn Source cnode * \param inherit_slot Source cnode slot * \param destcn Target cnode * \param destcn_slot Target cnode slot * * \retval SYS_ERR_OK Copy to target was successful or source cap * did not exist. * \retval SPAWN_ERR_COPY_INHERITCN_CAP Error in cap_copy */ static errval_t spawn_setup_inherited_cap(struct cnoderef inheritcn, capaddr_t inherit_slot, struct cnoderef destcn, capaddr_t destcn_slot) { errval_t err; struct capref src; src.cnode = inheritcn; src.slot = inherit_slot;; // Create frame (actually multiple pages) for fds struct capref dest; dest.cnode = destcn; dest.slot = destcn_slot; err = cap_copy(dest, src); if (err_no(err) == SYS_ERR_SOURCE_CAP_LOOKUP) { // there was no fdcap to inherit, continue return SYS_ERR_OK; } else if (err_is_fail(err)) { return err_push(err, SPAWN_ERR_COPY_INHERITCN_CAP); } return SYS_ERR_OK; }
static struct dcb *spawn_init_common(struct spawn_state *st, const char *name, int argc, const char *argv[], lpaddr_t bootinfo_phys, alloc_phys_func alloc_phys) { errval_t err; /* Perform arch-independent spawn */ lvaddr_t paramaddr; struct dcb *init_dcb = spawn_module(st, name, argc, argv, bootinfo_phys, ARGS_BASE, alloc_phys, ¶maddr); /* Init page tables */ init_page_tables(st, alloc_phys); /* Map dispatcher R/W into VSpace starting at vaddr 0x204000 * (Starting after Bootinfo pages)*/ #ifdef CONFIG_PAE paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(DISPATCHER_BASE)], mem_to_local_phys((lvaddr_t)init_pdir)); #endif paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(DISPATCHER_BASE)], mem_to_local_phys((lvaddr_t)init_ptable)); for (int i = 0; i < DISPATCHER_SIZE / BASE_PAGE_SIZE; i++) { paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(DISPATCHER_BASE) + i], mem_to_local_phys(init_dcb->disp) + i * BASE_PAGE_SIZE, INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W)); } struct dispatcher_shared_generic *init_disp = get_dispatcher_shared_generic(init_dcb->disp); struct dispatcher_shared_x86_32 *init_disp_x86_32 = get_dispatcher_shared_x86_32(init_dcb->disp); registers_set_param(&init_disp_x86_32->enabled_save_area, paramaddr); // Map IO cap in task cnode struct cte *iocap = caps_locate_slot(CNODE(st->taskcn), TASKCN_SLOT_IO); err = caps_create_new(ObjType_IO, 0, 0, 0, my_core_id, iocap); assert(err_is_ok(err)); /* Set fields in DCB */ // Set Vspace #ifdef CONFIG_PAE init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pdpte); #else init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pdir); #endif /* Initialize dispatcher */ init_disp->disabled = true; strncpy(init_disp->name, argv[0], DISP_NAME_LEN); /* tell init the vspace addr of its dispatcher */ init_disp->udisp = DISPATCHER_BASE; init_disp_x86_32->disabled_save_area.edi = DISPATCHER_BASE; init_disp_x86_32->disabled_save_area.fs = 0; init_disp_x86_32->disabled_save_area.gs = 0; init_disp_x86_32->disabled_save_area.cs = USER_CS; init_disp_x86_32->disabled_save_area.ss = USER_SS; init_disp_x86_32->disabled_save_area.eflags = USER_EFLAGS; return init_dcb; }