Code-base clean-up and refactoring (#47)
[lunaix-os.git] / lunaix-os / kernel / exe / exec.c
index 96559322ba485af625a60ad420e8ed12a440bd4f..0dace13e9352ec6d2e2009968972846c01bcb8b5 100644 (file)
@@ -1,4 +1,3 @@
-#include <arch/abi.h>
 #include <lunaix/exec.h>
 #include <lunaix/fs.h>
 #include <lunaix/load.h>
 #include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/process.h>
+#include <lunaix/sched.h>
 #include <lunaix/spike.h>
 #include <lunaix/status.h>
 #include <lunaix/syscall.h>
 #include <lunaix/syscall_utils.h>
 
+#include <asm/abi.h>
+#include <asm/mm_defs.h>
+
 #include <klibc/string.h>
 
+#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
-exec_str_size(const char** str_arr, size_t* length)
+int
+count_length(struct exec_arrptr* param)
 {
-    if (!str_arr) {
-        *length = 0;
+    int i = 0;
+    ptr_t* arr = (ptr_t*)param->raw;
+
+    if (!arr) {
+        param->len = 0;
         return 0;
     }
 
-    const char* chr = *str_arr;
-    size_t sz = 0, len = 0;
+    for (; i < MAX_PARAM_LEN && arr[i]; i++);
+    
+    param->len = i;
+    return i > 0 && arr[i] ? E2BIG : 0;
+}
 
-    while (chr) {
-        sz += strlen(chr);
-        len++;
+static void
+save_process_cmd(struct proc_info* proc, struct exec_arrptr* argv)
+{
+    ptr_t ptr, *argv_ptrs;
+    char* cmd_;
 
-        chr = *(str_arr++);
+    if (proc->cmd) {
+        vfree(proc->cmd);
     }
 
-    *length = len;
-    return sz + sizeof(char*);
+    argv_ptrs = (ptr_t*)argv->copied;
+    cmd_  = (char*)valloc(argv->size);
+
+    proc->cmd = cmd_;
+    while ((ptr = *argv_ptrs)) {
+        cmd_ = strcpy(cmd_, (const char*)ptr);
+        cmd_[-1] = ' ';
+        argv_ptrs++;
+    }
+    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;
-    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 var_sz = ROUNDUP(sz_envp, PG_SIZE);
-    const char** argv_extra = container->argv_pp;
-
-    argv_extra[0] = executable->dnode->name.value;
-
-    if (var_sz / PG_SIZE > MAX_VAR_PAGES) {
-        errno = E2BIG;
+    errno = __place_arrayptrs(container, &container->envp);
+    if (errno) {
         goto done;
     }
 
-    if ((errno = load_executable(&container->exe, executable))) {
-        goto done;
-    }
+    errno = __place_arrayptrs(container, &container->argv);
 
-    struct proc_mm* pvms = &container->proc->mm;
+done:
+    return errno;
+}
 
-    // A dedicated place for process variables (e.g. envp)
-    struct mmap_param map_vars = { .pvms = pvms,
-                                   .vms_mnt = container->vms_mnt,
-                                   .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED,
-                                   .type = REGION_TYPE_VARS,
-                                   .proct = PROT_READ,
-                                   .mlen = MAX_VAR_PAGES * PG_SIZE };
+int
+exec_load(struct exec_host* container, struct v_file* executable)
+{
+    int errno = 0;
+
+    struct exec_arrptr* argv = &container->argv;
+    struct exec_arrptr* envp = &container->envp;
 
-    void* mapped;
+    struct proc_info* proc = container->proc;
+    struct proc_mm* pvms = vmspace(proc);
 
     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));
+    if (!active_vms(container->vms_mnt)) {
+        /*
+            TODO Setup remote mapping of user stack for later use
+        */
+        fail("not implemented");
+
     }
 
-    if ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_vars))) {
+    if ((errno = count_length(argv))) {
         goto done;
     }
 
-    if (container->vms_mnt == VMS_SELF) {
-        // we are loading executable into current addr space
-
-        // make some handy infos available to user space
-        if (envp)
-            memcpy(mapped, (void*)envp, sz_envp);
-
-        void* ustack = (void*)USTACK_TOP;
-
-        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++) {
-            const char* extra_arg = argv_extra[i];
-            size_t str_len = strlen(extra_arg);
-
-            ustack = (void*)((ptr_t)ustack - str_len);
-            memcpy(ustack, (const 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;
+    if ((errno = count_length(envp))) {
+        goto done;
+    }
 
-        *exec_param = (struct uexec_param){
-            .argc = argv_len, .argv = ustack, .envc = envp_len, .envp = mapped
-        };
+    errno = __place_params(container);
+    if (errno) {
+        goto done;
+    }
 
-    } 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:
@@ -158,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;
@@ -172,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;
 }
@@ -182,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);
 
@@ -213,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;
@@ -224,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(&current_thread->sigctx);
+    signal_reset_registry(__current->sigreg);
 
 done:
     // set return value