A Total Overhaul on the Lunaix's Virtual Memory Model (#26)
[lunaix-os.git] / lunaix-os / kernel / exe / exec.c
index 535f65978af69ade767718c7abc8b3a2f4de9a51..6f2962e8048f947e3b6a056a963ba271fc060a37 100644 (file)
@@ -1,4 +1,3 @@
-#include <arch/abi.h>
 #include <lunaix/exec.h>
 #include <lunaix/fs.h>
 #include <lunaix/load.h>
@@ -6,48 +5,90 @@
 #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 <sys/abi.h>
+#include <sys/mm/mm_defs.h>
+
 #include <klibc/string.h>
 
 void
-exec_container(struct exec_container* param,
-               struct proc_info* proc,
+exec_init_container(struct exec_container* param,
+               struct thread* thread,
                ptr_t vms,
                const char** argv,
                const char** envp)
 {
-    *param = (struct exec_container){ .proc = proc,
+    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 };
+                                      .envp = envp,
+                                      .stack_top = ustack_top };
 }
 
 size_t
-exec_str_size(const char** str_arr, size_t* length)
+args_ptr_size(const char** paramv)
+{
+    size_t sz = 0;
+    while (*paramv) {
+        sz++;
+        paramv++;
+    }
+
+    return (sz + 1) * sizeof(ptr_t);
+}
+
+static ptr_t
+copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
 {
-    if (!str_arr) {
-        *length = 0;
-        return 0;
+    ptr_t ptr;
+    size_t sz = 0;
+
+    while ((ptr = *paramv)) {
+        sz = strlen((const char*)ptr) + 1;
+
+        stack_top -= sz;
+        memcpy((void*)stack_top, (const void*)ptr, sz);
+        *paramv = stack_top;
+
+        paramv++;
     }
 
-    const char* chr = *str_arr;
-    size_t sz = 0, len = 0;
+    return stack_top;
+}
 
-    while (chr) {
-        sz += strlen(chr);
-        len++;
+static void
+save_process_cmd(struct proc_info* proc, ptr_t* argv)
+{
+    ptr_t ptr, *_argv = argv;
+    size_t total_sz = 0;
+    while ((ptr = *_argv)) {
+        total_sz += strlen((const char*)ptr) + 1;
+        _argv++;
+    }
 
-        chr = *(str_arr++);
+    if (proc->cmd) {
+        vfree(proc->cmd);
     }
 
-    *length = len;
-    return sz + sizeof(char*);
+    char* cmd_ = (char*)valloc(total_sz);
+    proc->cmd = cmd_;
+    proc->cmd_len = total_sz;
+
+    while ((ptr = *argv)) {
+        cmd_ = strcpy(cmd_, (const char*)ptr);
+        cmd_[-1] = ' ';
+        argv++;
+    }
+    cmd_[-1] = '\0';
 }
 
 // externed from mm/dmm.c
@@ -60,34 +101,16 @@ exec_load(struct exec_container* container, struct v_file* executable)
     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);
-    char** argv_extra = container->argv_pp;
+    const char** argv_extra = container->argv_pp;
 
     argv_extra[0] = executable->dnode->name.value;
 
-    if (var_sz / PG_SIZE > MAX_VAR_PAGES) {
-        errno = E2BIG;
-        goto done;
-    }
-
     if ((errno = load_executable(&container->exe, executable))) {
         goto done;
     }
 
-    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 = container->vms_mnt,
-                                   .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED,
-                                   .type = REGION_TYPE_VARS,
-                                   .proct = PROT_READ,
-                                   .mlen = MAX_VAR_PAGES * PG_SIZE };
-
-    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);
@@ -97,60 +120,60 @@ exec_load(struct exec_container* container, struct v_file* executable)
     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 ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_vars))) {
-        goto done;
+        create_heap(vmspace(proc), va_align(container->exe.end));
     }
 
     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);
+        ptr_t ustack = container->stack_top;
+        size_t argv_len = 0, envp_len = 0;
+        ptr_t argv_ptr = 0, envp_ptr = 0;
 
-        void* ustack = (void*)USTACK_TOP;
+        if (envp) {
+            argv_len = args_ptr_size(envp);
+            ustack -= envp_len;
+            envp_ptr = ustack;
 
-        if (argv) {
-            ustack = (void*)((ptr_t)ustack - sz_argv);
-            memcpy(ustack, (void*)argv, sz_argv);
+            memcpy((void*)ustack, (const void*)envp, envp_len);
+            ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
         }
 
-        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);
+        if (argv) {            
+            argv_len = args_ptr_size(argv);
+            ustack -= argv_len;
+
+            memcpy((void*)ustack, (const void**)argv, argv_len);
+        }
 
-            ustack = (void*)((ptr_t)ustack - str_len);
-            memcpy(ustack, (void*)extra_arg, str_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);
+
+        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, .argv = ustack, .envc = envp_len, .envp = mapped
-        };
-
+        *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.
+            TODO Inject to remote user stack with our procvm_remote toolsets
+                 Need a better way to factorise the argv/envp length calculating
         */
         fail("not implemented");
+
     }
 
 done:
@@ -174,6 +197,12 @@ exec_load_byname(struct exec_container* container, const char* filename)
 
     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;
 }
@@ -183,7 +212,8 @@ exec_kexecve(const char* filename, const char* argv[], const char* envp[])
 {
     int errno = 0;
     struct exec_container container;
-    exec_container(&container, __current, VMS_SELF, argv, envp);
+
+    exec_init_container(&container, current_thread, VMS_SELF, argv, envp);
 
     errno = exec_load_byname(&container, filename);
 
@@ -212,7 +242,9 @@ __DEFINE_LXSYSCALL3(int,
 {
     int errno = 0;
     struct exec_container container;
-    exec_container(&container, __current, VMS_SELF, argv, envp);
+
+    exec_init_container(
+      &container, current_thread, VMS_SELF, argv, envp);
 
     if ((errno = exec_load_byname(&container, filename))) {
         goto done;
@@ -220,9 +252,13 @@ __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;
+    eret_target(current_thread) = container.exe.entry;
+    eret_stack(current_thread) = container.stack_top;
+
+    // these become meaningless once execved!
+    current_thread->ustack_top = 0;
+    signal_reset_context(&current_thread->sigctx);
+    signal_reset_register(__current->sigreg);
 
 done:
     // set return value