X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/946c3fdd31300074cc78841795bd47af908ddddb..34f6af4f61e0eec9c96113e07f140b609b4113c8:/lunaix-os/kernel/exe/exec.c diff --git a/lunaix-os/kernel/exe/exec.c b/lunaix-os/kernel/exe/exec.c index a846126..0dace13 100644 --- a/lunaix-os/kernel/exe/exec.c +++ b/lunaix-os/kernel/exe/exec.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -6,147 +5,207 @@ #include #include #include +#include #include #include #include #include +#include +#include + #include +#define _push(ptr, type, val) \ + do { \ + ptr = __ptr(&((type*)ptr)[-1]); \ + *((type*)ptr) = (val); \ + } while(0) + +static int +__place_arrayptrs(struct exec_host* container, struct exec_arrptr* param) +{ + int len; + ptr_t usp, usp_top; + ptr_t* ptrs; + unsigned int* reloc_off; + + usp_top = container->stack_top; + usp = usp_top; + ptrs = (ptr_t*)param->raw; + + if (!param->len) { + _push(usp, unsigned int, 0); + + goto done; + } + + len = param->len; + reloc_off = valloc(len * sizeof(unsigned int)); + + char* el; + size_t el_sz, sz_acc = 0; + for (int i = 0; i < len; i++) + { + el= (char*)ptrs[i]; + el_sz = strnlen(el, MAX_PARAM_SIZE) + 1; + + usp -= el_sz; + sz_acc += el_sz; + strncpy((char*)usp, el, el_sz); + + reloc_off[i] = sz_acc; + } + + param->size = sz_acc; + + ptr_t* toc = (ptr_t*)(usp) - 1; + toc[0] = 0; + + toc = &toc[-1]; + for (int i = 0, j = len - 1; i < len; i++, j--) + { + toc[-i] = usp_top - (ptr_t)reloc_off[j]; + } + + toc[-len] = (ptr_t)len; + + usp = __ptr(&toc[-len]); + param->copied = __ptr(&toc[-len + 1]); + + vfree(reloc_off); + +done: + container->stack_top = usp; + return 0; +} + void -exec_container(struct exec_container* param, - struct proc_info* proc, +exec_init_container(struct exec_host* param, + struct thread* thread, ptr_t vms, const char** argv, const char** envp) { - *param = (struct exec_container){ .proc = proc, - .vms_mnt = vms, - .exe = { .container = param }, - .argv_pp = { 0, 0 }, - .argv = argv, - .envp = envp }; + assert(thread->ustack); + ptr_t ustack_top = align_stack(thread->ustack->end - 1); + *param = (struct exec_host) + { + .proc = thread->process, + .vms_mnt = vms, + .exe = { + .container = param + }, + .argv = { + .raw = __ptr(argv) + }, + .envp = { + .raw = __ptr(envp) + }, + .stack_top = ustack_top + }; } -size_t -args_ptr_size(const char** paramv) +int +count_length(struct exec_arrptr* param) { - size_t sz = 0; - while (*paramv) { - sz++; - paramv++; + int i = 0; + ptr_t* arr = (ptr_t*)param->raw; + + if (!arr) { + param->len = 0; + return 0; } - return (sz + 1) * sizeof(ptr_t); + for (; i < MAX_PARAM_LEN && arr[i]; i++); + + param->len = i; + return i > 0 && arr[i] ? E2BIG : 0; } -ptr_t -copy_to_ustack(ptr_t stack_top, ptr_t* paramv) +static void +save_process_cmd(struct proc_info* proc, struct exec_arrptr* argv) { - ptr_t ptr; - size_t sz = 0; + ptr_t ptr, *argv_ptrs; + char* cmd_; - while ((ptr = *paramv)) { - sz = strlen((const char*)ptr) + 1; + if (proc->cmd) { + vfree(proc->cmd); + } - stack_top -= sz; - memcpy((void*)stack_top, (const void*)ptr, sz); - *paramv = stack_top; + argv_ptrs = (ptr_t*)argv->copied; + cmd_ = (char*)valloc(argv->size); - paramv++; + proc->cmd = cmd_; + while ((ptr = *argv_ptrs)) { + cmd_ = strcpy(cmd_, (const char*)ptr); + cmd_[-1] = ' '; + argv_ptrs++; } - - return stack_top; + cmd_[-1] = '\0'; + + proc->cmd_len = argv->size; } -// externed from mm/dmm.c -extern int -create_heap(struct proc_mm* pvms, ptr_t addr); -int -exec_load(struct exec_container* container, struct v_file* executable) +static int +__place_params(struct exec_host* container) { int errno = 0; - const char **argv = container->argv, **envp = container->envp; - const char** argv_extra = container->argv_pp; - - argv_extra[0] = executable->dnode->name.value; - - if ((errno = load_executable(&container->exe, executable))) { + errno = __place_arrayptrs(container, &container->envp); + if (errno) { goto done; } - struct proc_mm* pvms = &container->proc->mm; + errno = __place_arrayptrs(container, &container->argv); - if (pvms->heap) { - mem_unmap_region(container->vms_mnt, pvms->heap); - pvms->heap = NULL; - } - - if (!argv_extra[1]) { - // If loading a statically linked file, then heap remapping we can do, - // otherwise delayed. - create_heap(&container->proc->mm, PG_ALIGN(container->exe.end)); - } +done: + return errno; +} - if (container->vms_mnt == VMS_SELF) { - // we are loading executable into current addr space +int +exec_load(struct exec_host* container, struct v_file* executable) +{ + int errno = 0; - ptr_t ustack = USTACK_TOP; - size_t argv_len = 0, envp_len = 0; - ptr_t argv_ptr = 0, envp_ptr = 0; + struct exec_arrptr* argv = &container->argv; + struct exec_arrptr* envp = &container->envp; - if (envp) { - argv_len = args_ptr_size(envp); - ustack -= envp_len; - envp_ptr = ustack; + struct proc_info* proc = container->proc; + struct proc_mm* pvms = vmspace(proc); - memcpy((void*)ustack, (const void*)envp, envp_len); - ustack = copy_to_ustack(ustack, (ptr_t*)ustack); - } + if (pvms->heap) { + mem_unmap_region(container->vms_mnt, pvms->heap); + pvms->heap = NULL; + } - if (argv) { - argv_len = args_ptr_size(argv); - ustack -= argv_len; + if (!active_vms(container->vms_mnt)) { + /* + TODO Setup remote mapping of user stack for later use + */ + fail("not implemented"); - memcpy((void*)ustack, (const void**)argv, argv_len); - for (size_t i = 0; i < 2 && argv_extra[i]; i++) { - ustack -= sizeof(ptr_t); - *((ptr_t*)ustack) = (ptr_t)argv_extra[i]; - argv_len += sizeof(ptr_t); - } + } - argv_ptr = ustack; - ustack = copy_to_ustack(ustack, (ptr_t*)ustack); - } + if ((errno = count_length(argv))) { + goto done; + } - // four args (arg{c|v}, env{c|p}) for main - struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1]; + if ((errno = count_length(envp))) { + goto done; + } - container->stack_top = (ptr_t)exec_param; + errno = __place_params(container); + if (errno) { + goto done; + } - *exec_param = - (struct uexec_param){ .argc = (argv_len - 1) / sizeof(ptr_t), - .argv = (char**)argv_ptr, - .envc = (envp_len - 1) / sizeof(ptr_t), - .envp = (char**)envp_ptr }; - } else { - /* - TODO need to find a way to inject argv and envp remotely - this is for the support of kernel level implementation of - posix_spawn - - IDEA - 1. Allocate a orphaned physical page (i.e., do not belong to any - VMA) - 2. Mounted to a temporary mount point in current VMA, (i.e., - PG_MOUNT_*) - 3. Do setup there. - 4. Unmount then mounted to the foreign VMA as the first stack - page. - */ - fail("not implemented"); + save_process_cmd(proc, argv); + + errno = load_executable(&container->exe, executable); + if (errno) { + goto done; } done: @@ -154,7 +213,7 @@ done: } int -exec_load_byname(struct exec_container* container, const char* filename) +exec_load_byname(struct exec_host* container, const char* filename) { int errno = 0; struct v_dnode* dnode; @@ -168,8 +227,19 @@ exec_load_byname(struct exec_container* container, const char* filename) goto done; } + if (!check_itype_any(dnode->inode, F_FILE)) { + errno = EISDIR; + goto done; + } + errno = exec_load(container, file); + // It shouldn't matter which pid we passed. As the only reader is + // in current context and we must finish read at this point, + // therefore the dead-lock condition will not exist and the pid + // for arbitration has no use. + vfs_pclose(file, container->proc->pid); + done: return errno; } @@ -178,10 +248,11 @@ int exec_kexecve(const char* filename, const char* argv[], const char* envp[]) { int errno = 0; - struct exec_container container; + struct exec_host container; + + assert(argv && envp); - exec_container( - &container, (struct proc_info*)__current, VMS_SELF, argv, envp); + exec_init_container(&container, current_thread, VMS_SELF, argv, envp); errno = exec_load_byname(&container, filename); @@ -209,10 +280,15 @@ __DEFINE_LXSYSCALL3(int, envp[]) { int errno = 0; - struct exec_container container; + struct exec_host container; - exec_container( - &container, (struct proc_info*)__current, VMS_SELF, argv, envp); + if (!argv || !envp) { + errno = EINVAL; + goto done; + } + + exec_init_container( + &container, current_thread, VMS_SELF, argv, envp); if ((errno = exec_load_byname(&container, filename))) { goto done; @@ -220,9 +296,12 @@ __DEFINE_LXSYSCALL3(int, // we will jump to new entry point (_u_start) upon syscall's // return so execve 'will not return' from the perspective of it's invoker - volatile struct exec_param* execp = __current->intr_ctx->execp; - execp->esp = container.stack_top; - execp->eip = container.exe.entry; + exec_arch_prepare_entry(current_thread, &container); + + // these become meaningless once execved! + current_thread->ustack_top = 0; + signal_reset_context(¤t_thread->sigctx); + signal_reset_registry(__current->sigreg); done: // set return value