Code-base clean-up and refactoring (#47)
[lunaix-os.git] / lunaix-os / kernel / exe / exec.c
index 0f6e4ecbfad7390ef7816540601d98939bbf4130..0dace13e9352ec6d2e2009968972846c01bcb8b5 100644 (file)
 #include <lunaix/syscall.h>
 #include <lunaix/syscall_utils.h>
 
-#include <sys/abi.h>
-#include <sys/mm/mm_defs.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_init_container(struct exec_container* param,
+exec_init_container(struct exec_host* param,
                struct thread* thread,
                ptr_t vms,
                const char** argv,
@@ -25,90 +89,89 @@ exec_init_container(struct exec_container* param,
 {
     assert(thread->ustack);
     ptr_t ustack_top = align_stack(thread->ustack->end - 1);
-    *param = (struct exec_container){ .proc = thread->process,
-                                      .vms_mnt = vms,
-                                      .exe = { .container = param },
-                                      .argv_pp = { 0, 0 },
-                                      .argv = argv,
-                                      .envp = envp,
-                                      .stack_top = ustack_top };
-}
-
-size_t
-args_ptr_size(const char** paramv)
-{
-    size_t sz = 0;
-    while (*paramv) {
-        sz++;
-        paramv++;
-    }
-
-    return (sz + 1) * sizeof(ptr_t);
+    *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 
+    };
 }
 
-static ptr_t
-copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
+int
+count_length(struct exec_arrptr* param)
 {
-    ptr_t ptr;
-    size_t sz = 0;
-
-    while ((ptr = *paramv)) {
-        sz = strlen((const char*)ptr) + 1;
+    int i = 0;
+    ptr_t* arr = (ptr_t*)param->raw;
 
-        stack_top -= sz;
-        memcpy((void*)stack_top, (const void*)ptr, sz);
-        *paramv = stack_top;
-
-        paramv++;
+    if (!arr) {
+        param->len = 0;
+        return 0;
     }
 
-    return stack_top;
+    for (; i < MAX_PARAM_LEN && arr[i]; i++);
+    
+    param->len = i;
+    return i > 0 && arr[i] ? E2BIG : 0;
 }
 
 static void
-save_process_cmd(struct proc_info* proc, ptr_t* argv)
+save_process_cmd(struct proc_info* proc, struct exec_arrptr* argv)
 {
-    ptr_t ptr, *_argv = argv;
-    size_t total_sz = 0;
-    while ((ptr = *_argv)) {
-        total_sz += strlen((const char*)ptr) + 1;
-        _argv++;
-    }
+    ptr_t ptr, *argv_ptrs;
+    char* cmd_;
 
     if (proc->cmd) {
         vfree(proc->cmd);
     }
 
-    char* cmd_ = (char*)valloc(total_sz);
-    proc->cmd = cmd_;
-    proc->cmd_len = total_sz;
+    argv_ptrs = (ptr_t*)argv->copied;
+    cmd_  = (char*)valloc(argv->size);
 
-    while ((ptr = *argv)) {
+    proc->cmd = cmd_;
+    while ((ptr = *argv_ptrs)) {
         cmd_ = strcpy(cmd_, (const char*)ptr);
         cmd_[-1] = ' ';
-        argv++;
+        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;
-    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;
     }
 
+    errno = __place_arrayptrs(container, &container->argv);
+
+done:
+    return errno;
+}
+
+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;
+
     struct proc_info* proc = container->proc;
     struct proc_mm* pvms = vmspace(proc);
 
@@ -117,77 +180,40 @@ exec_load(struct exec_container* container, struct v_file* executable)
         pvms->heap = NULL;
     }
 
-    if (!argv_extra[1]) {
-        // If loading a statically linked file, then heap remapping we can do,
-        // otherwise delayed.
-        create_heap(vmspace(proc), page_aligned(container->exe.end));
-    }
-
-    if (container->vms_mnt == VMS_SELF) {
-        // we are loading executable into current addr space
-
-        ptr_t ustack = container->stack_top;
-        size_t argv_len = 0, envp_len = 0;
-        ptr_t argv_ptr = 0, envp_ptr = 0;
-
-        if (envp) {
-            argv_len = args_ptr_size(envp);
-            ustack -= envp_len;
-            envp_ptr = ustack;
-
-            memcpy((void*)ustack, (const void*)envp, envp_len);
-            ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
-        } else {
-            ustack -= sizeof(ptr_t);
-            *((ptr_t*)ustack) = 0;
-        }
-
-        if (argv) {            
-            argv_len = args_ptr_size(argv);
-            ustack -= argv_len;
-
-            memcpy((void*)ustack, (const void**)argv, argv_len);
-        } else {
-            ustack -= sizeof(ptr_t);
-            *((ptr_t*)ustack) = 0;
-        }
-
-        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);
-
-        save_process_cmd(proc, (ptr_t*)argv_ptr);
-
-        // 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 - 1) / sizeof(ptr_t),
-                                .argv = (char**)argv_ptr,
-                                .envc = (envp_len - 1) / sizeof(ptr_t),
-                                .envp = (char**)envp_ptr };
-    } else {
+    if (!active_vms(container->vms_mnt)) {
         /*
-            TODO Inject to remote user stack with our procvm_remote toolsets
-                 Need a better way to factorise the argv/envp length calculating
+            TODO Setup remote mapping of user stack for later use
         */
         fail("not implemented");
 
     }
 
+    if ((errno = count_length(argv))) {
+        goto done;
+    }
+
+    if ((errno = count_length(envp))) {
+        goto done;
+    }
+
+    errno = __place_params(container);
+    if (errno) {
+        goto done;
+    }
+
+    save_process_cmd(proc, argv);
+    
+    errno = load_executable(&container->exe, executable);
+    if (errno) {
+        goto done;
+    }
+
 done:
     return errno;
 }
 
 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;
@@ -222,7 +248,9 @@ 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_init_container(&container, current_thread, VMS_SELF, argv, envp);
 
@@ -252,7 +280,12 @@ __DEFINE_LXSYSCALL3(int,
                     envp[])
 {
     int errno = 0;
-    struct exec_container container;
+    struct exec_host container;
+
+    if (!argv || !envp) {
+        errno = EINVAL;
+        goto done;
+    }
 
     exec_init_container(
       &container, current_thread, VMS_SELF, argv, envp);
@@ -263,8 +296,7 @@ __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
-    hart_flow_redirect(current_thread->hstate, 
-                          container.exe.entry, container.stack_top);
+    exec_arch_prepare_entry(current_thread, &container);
 
     // these become meaningless once execved!
     current_thread->ustack_top = 0;