X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/0cf90cca0c924622f3fee8d2a3fafa8238363dc6..b8d37199feb1369c445e3b0fe1fb9171218a0e14:/lunaix-os/kernel/loader/exec.c diff --git a/lunaix-os/kernel/loader/exec.c b/lunaix-os/kernel/loader/exec.c index cf0a422..5024a1d 100644 --- a/lunaix-os/kernel/loader/exec.c +++ b/lunaix-os/kernel/loader/exec.c @@ -1,15 +1,26 @@ +#include #include +#include #include -#include #include +#include #include #include #include #include #include +#include #include +void +exec_container(struct exec_container* param, struct proc_info* proc, ptr_t vms) +{ + *param = (struct exec_container){ .proc = proc, + .vms_mnt = vms, + .executable = { .container = param } }; +} + size_t exec_str_size(const char** str_arr, size_t* length) { @@ -25,70 +36,89 @@ exec_str_size(const char** str_arr, size_t* length) sz += strlen(chr); len++; - chr = *(str_arr + sz); + chr = *(str_arr++); } *length = len; - return sz + 1; + return sz + sizeof(char*); } -void -__heap_copied(struct mm_region* region) -{ - mm_index((void**)®ion->proc_vms->heap, region); -} - -int -__exec_remap_heap(struct ld_param* param, struct proc_mm* pvms) -{ - if (pvms->heap) { - mem_unmap_region(param->vms_mnt, pvms->heap); - } - - struct mmap_param map_param = { .pvms = pvms, - .vms_mnt = param->vms_mnt, - .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED, - .type = REGION_TYPE_HEAP, - .proct = PROT_READ | PROT_WRITE, - .mlen = DEFAULT_HEAP_PAGES * PG_SIZE }; - int status = 0; - struct mm_region* heap; - if ((status = mem_map(NULL, &heap, param->info.end, NULL, &map_param))) { - param->status |= LD_STAT_FKUP; - return status; - } - - heap->region_copied = __heap_copied; - mm_index((void**)&pvms->heap, heap); - - return status; -} +// externed from mm/dmm.c +extern int +create_heap(struct proc_mm* pvms, ptr_t addr); int -exec_load(struct ld_param* param, +exec_load(struct exec_container* container, struct v_file* executable, const char** argv, const char** envp) { int errno = 0; + char* ldpath = NULL; size_t argv_len, envp_len; size_t sz_argv = exec_str_size(argv, &argv_len); size_t sz_envp = exec_str_size(envp, &envp_len); - size_t total_sz = ROUNDUP(sz_argv + sz_envp, PG_SIZE); + size_t var_sz = ROUNDUP(sz_envp, PG_SIZE); - if (total_sz / PG_SIZE > MAX_VAR_PAGES) { + char* argv_extra[2] = { executable->dnode->name.value, 0 }; + + if (var_sz / PG_SIZE > MAX_VAR_PAGES) { errno = E2BIG; goto done; } - if ((errno = elf_load(param, executable))) { + struct elf32 elf; + + if ((errno = elf32_openat(&elf, executable))) { + goto done; + } + + if (!elf32_check_exec(&elf)) { + errno = ENOEXEC; + goto done; + } + + ldpath = valloc(512); + errno = elf32_find_loader(&elf, ldpath, 512); + + if (errno < 0) { + vfree(ldpath); goto done; } - struct proc_mm* pvms = ¶m->proc->mm; + if (errno != NO_LOADER) { + // TODO load loader + argv_extra[1] = ldpath; + + // close old elf + if ((errno = elf32_close(&elf))) { + goto done; + } + + // open the loader instead + if ((errno = elf32_open(&elf, ldpath))) { + goto done; + } + + // Is this the valid loader? + if (!elf32_static_linked(&elf) || !elf32_check_exec(&elf)) { + errno = ELIBBAD; + goto done_close_elf32; + } + + // TODO: relocate loader + } + + if ((errno = elf32_load(&container->executable, &elf))) { + goto done_close_elf32; + } + + struct proc_mm* pvms = &container->proc->mm; + + // A dedicated place for process variables (e.g. envp) struct mmap_param map_vars = { .pvms = pvms, - .vms_mnt = param->vms_mnt, + .vms_mnt = container->vms_mnt, .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED, .type = REGION_TYPE_VARS, .proct = PROT_READ, @@ -96,47 +126,79 @@ exec_load(struct ld_param* param, void* mapped; - if ((errno = __exec_remap_heap(param, pvms))) { - goto done; + 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->vms_mnt, PG_ALIGN(container->executable.end)); } if ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_vars))) { - goto done; + goto done_close_elf32; } - if (param->vms_mnt == VMS_SELF) { + if (container->vms_mnt == VMS_SELF) { // we are loading executable into current addr space // make some handy infos available to user space - ptr_t arg_start = mapped + sizeof(struct usr_exec_param); - if (argv) - memcpy(arg_start, (void*)argv, sz_argv); if (envp) - memcpy(arg_start + sz_argv, (void*)envp, sz_envp); + memcpy(mapped, (void*)envp, sz_envp); - ptr_t* ustack = (ptr_t*)USTACK_TOP; - struct usr_exec_param* exec_param = mapped; + void* ustack = (void*)USTACK_TOP; - ustack[-1] = (ptr_t)mapped; - param->info.stack_top = &ustack[-1]; + if (argv) { + ustack = (void*)((ptr_t)ustack - sz_argv); + memcpy(ustack, (void*)argv, sz_argv); + } + + for (size_t i = 0; i < 2 && argv_extra[i]; i++, argv_len++) { + char* extra_arg = argv_extra[i]; + size_t str_len = strlen(extra_arg); + + ustack = (void*)((ptr_t)ustack - str_len); + memcpy(ustack, (void*)extra_arg, str_len); + } + + // four args (arg{c|v}, env{c|p}) for main + struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1]; + + container->stack_top = (ptr_t)exec_param; + + *exec_param = (struct uexec_param){ + .argc = argv_len, .argv = ustack, .envc = envp_len, .envp = mapped + }; - *exec_param = (struct usr_exec_param){ .argc = argv_len, - .argv = arg_start, - .envc = envp_len, - .envp = arg_start + sz_argv, - .info = param->info }; } else { - // TODO need to find a way to inject argv and envp remotely + /* + 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"); } - param->info.entry = param->info.ehdr_out.e_entry; +done_close_elf32: + elf32_close(&elf); done: + vfree_safe(ldpath); return errno; } int -exec_load_byname(struct ld_param* param, +exec_load_byname(struct exec_container* container, const char* filename, const char** argv, const char** envp) @@ -153,14 +215,28 @@ exec_load_byname(struct ld_param* param, goto done; } - if ((errno = exec_load(param, file, argv, envp))) { - vfs_pclose(file, __current->pid); - } + errno = exec_load(container, file, argv, envp); done: return errno; } +int +exec_kexecve(const char* filename, const char* argv[], const char* envp) +{ + int errno = 0; + struct exec_container container; + exec_container(&container, __current, VMS_SELF); + + errno = exec_load_byname(&container, filename, argv, envp); + + if (errno) { + return errno; + } + + j_usr(container.stack_top, container.entry); +} + __DEFINE_LXSYSCALL3(int, execve, const char*, @@ -171,25 +247,26 @@ __DEFINE_LXSYSCALL3(int, envp[]) { int errno = 0; - struct ld_param ldparam; - ld_create_param(&ldparam, __current, VMS_SELF); - - if ((errno = exec_load_byname(&ldparam, filename, argv, envp))) { - if ((ldparam.status & LD_STAT_FKUP)) { - // we fucked up our address space. - terminate_proc(11451); - schedule(); - fail("should not reach"); - } - } + struct exec_container container; + exec_container(&container, __current, VMS_SELF); - isr_param* intr_ctx = &__current->intr_ctx; - intr_ctx->esp = ldparam.info.stack_top; - intr_ctx->eip = ldparam.info.entry; + if (!(errno = exec_load_byname(&container, filename, argv, envp))) { + goto done; + } // 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.entry; done: - return errno; + // set return value + store_retval(DO_STATUS(errno)); + + // Always yield the process that want execve! + schedule(); + + // this will never get executed! + return -1; } \ No newline at end of file