]> git.corax.cc Git - corax/commitdiff
Add execfve() syscall
authorMatthias Kruk <m@m10k.eu>
Sat, 23 Nov 2019 06:30:35 +0000 (15:30 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 23 Nov 2019 06:30:35 +0000 (15:30 +0900)
kernel/core/posixcall.c
kernel/core/syscall.S

index 34b29264ed53046e212f4ff2956bc829ea4003cd..76a8fcc324682c6cc137f8953d1863ac0e54845e 100644 (file)
@@ -8,6 +8,7 @@
 #include <arch.h>
 #include <process.h>
 #include <debug.h>
+#include <string.h>
 
 int sys_exit(int status)
 {
@@ -43,6 +44,217 @@ int sys_fork(stack_frame_t *stk)
        ct = task_get_current();
 
        stk->cr3 = ct->t_pgdir;
+       dbg_printf("[0x%08x] sys_fork()\n", stk->cr3);
+
+       return(ret_val);
+}
+
+#if FEATURE(ELF)
+int sys_execelf(stack_frame_t *stk)
+{
+       int ret_val;
+       void *elfdata;
+       u32_t elfsize;
+       pg_dir_t *pd;
+       pg_dir_t *oldpd;
+       process_t *cproc;
+       void *ostack;
+       void *nstack;
+
+       /*
+        * sys_execelf() - Replace the process image with the provided ELF file
+        *
+        * This function will:
+        * [ 0. Validate the provided ELF file ]
+        *  1. Create a new address space (page directory)
+        *  2. Copy the ELF data into the new address space
+        *  3. Initialize the initial stack frame for the new image
+        *
+        * The new process will start execution in the ELF parser, preparing
+        * its own environment.
+        */
+
+       ret_val = -EINVAL;
+       elfdata = (void*)stk->ebx;
+       elfsize = (u32_t)stk->ecx;
+       cproc = process_get_current();
+
+       /* FIXME: Verify ELF file integrity before doing the heavy lifting */
+
+       /* FIXME: Destroy all but one task in the process */
+
+       ret_val = pg_dir_create(&pd);
+
+       if(ret_val < 0) {
+               goto cleanup;
+       }
+
+       /* FIXME: Copy the elf image into the new address space */
+
+
+       /* make the process and its tasks refer to the new page directory */
+       process_get_pagedir(cproc, &oldpd);
+       process_set_pagedir(cproc, pd);
+
+       /* update the stack frame of the executing task */
+       stk->cr3 = (u32_t)pg_dir_get_pdbr(pd);
+
+       /*
+        * The kernel is currently executing on the kernel stack inside the
+        * page directory that we're about to free. We have to copy the old
+        * stack to the new one and update ESP, EBP.
+        */
+       ostack = cproc->p_tasks->t_kstack;
+       nstack = pg_dir_get_kstack(pd);
+
+       /*
+        * task_move_stack() will move the current stack and update the
+        * stack pointers. When this function returns, we will be executing
+        * on the kernel-mode stack from the new page directory.
+        */
+       task_move_stack(nstack, ostack, CONFIG_KERNEL_STACK_SIZE);
+
+#if 0
+       /* values on the stack should also have been adjusted by task_move_stack() */
+       stk = (stack_frame_t*)((u32_t)stk - (u32_t)ostack + (u32_t)nstack);
+#endif /* 0 */
+
+       /* FIXME: destroy the previous address space, if not used anymore */
+
+
+       ret_val = 0;
+
+cleanup:
+       return(ret_val);
+}
+#endif /* FEATURE(ELF) */
+
+void* setstackvfe(void *ustack, char **argv, char **envp)
+{
+       int nstrs;
+       int i;
+
+       if(ustack) {
+               char **nargv;
+               char **nenvp;
+               int nargc;
+
+               nargv = NULL;
+               nenvp = NULL;
+               nargc = 0;
+
+               /* copy the environment string, if it was provided */
+               if(envp) {
+                       char *nextstr;
+
+                       /* count the strings in envp */
+                       for(nstrs = 0; envp[nstrs]; nstrs++);
+
+                       /* copy the environment variable to the destination stack */
+                       for(i = 0; i < nstrs; i++) {
+                               int idx;
+                               int len;
+
+                               idx = nstrs - i - 1;
+                               len = strlen(envp[idx]) + 1;
+
+                               ustack -= len;
+                               memcpy(ustack, envp[idx], len);
+                       }
+
+                       nextstr = (char*)ustack;
+                       /* make space for the new envp */
+                       ustack -= sizeof(char*) * (nstrs + 1);
+                       nenvp = (char**)ustack;
+
+                       for(i = 0; i < nstrs; i++) {
+                               nenvp[i] = nextstr;
+                               nextstr += strlen(nextstr);
+                       }
+                       nenvp[nstrs] = NULL;
+               }
+
+               /* copy arguments, if they were provided */
+               if(argv) {
+                       char *nextstr;
+
+                       /* count the arguments */
+                       for(nstrs = 0; argv[nstrs]; nstrs++);
+
+                       /* copy the arguments to the destination stack */
+                       for(i = 0; i < nstrs; i++) {
+                               int idx;
+                               int len;
+
+                               idx = nstrs - i - 1;
+                               len = strlen(argv[idx]) * 1;
+
+                               ustack -= len;
+                               memcpy(ustack, argv[idx], len);
+                       }
+
+                       nextstr = (char*)ustack;
+                       /* make space for the new argv */
+                       ustack -= sizeof(char*) * (nstrs + 1);
+                       nargv = (char**)ustack;
+
+                       for(i = 0; i < nstrs; i++) {
+                               nargv[i] = nextstr;
+                               nextstr += strlen(nextstr);
+                       }
+                       nargv[nstrs] = NULL;
+                       nargc = nstrs;
+               }
+
+               /* finally, prepare the stack frame for the function call */
+               ustack -= sizeof(char**);
+               *(char***)ustack = envp;
+               ustack -= sizeof(char**);
+               *(char***)ustack = argv;
+               ustack -= sizeof(int);
+               *(int*)ustack = nargc;
+       }
+
+       return(ustack);
+}
+
+int sys_execfve(stack_frame_t *stk)
+{
+       process_t *proc;
+       pg_dir_t *pgdir;
+       void *ustack;
+       void *entry;
+       char **argv;
+       char **envp;
+       int ret_val;
+
+       entry = (void*)stk->ebx;
+       argv = (char**)stk->ecx;
+       envp = (char**)stk->edx;
+       ret_val = 0;
+
+       proc = process_get_current();
+       process_get_pagedir(proc, &pgdir);
+
+       /* FIXME: Stack size may not be static */
+       ustack = (void*)((u32_t)pg_dir_get_ustack(pgdir) +
+                                        CONFIG_USER_STACK_SIZE);
+
+       /* FIXME: We also need to duplicate the .data and .bss sections */
+
+       /* prepare the stack frame for the function */
+       ustack = setstackvfe(ustack, argv, envp);
+
+       /* FIXME: This will not work on any architecture but IA-32 */
+
+       /* make the task execute the new function upon return from the interrupt */
+       stk->eip = (u32_t)entry;
+       stk->ebp = (u32_t)ustack;
+       stk->esp = (u32_t)ustack;
+       stk->prevesp = (u32_t)ustack;
+
+       /* TODO: Stop remaining tasks that may be executing in the process */
+       /* FIXME: Shouldn't we also wipe the heap? */
 
        return(ret_val);
 }
@@ -52,11 +264,28 @@ int sys_vfork(void)
        return(process_fork(1));
 }
 
-int sys_wait(int *status)
+int sys_sleep(unsigned int seconds)
 {
        return(-ENOSYS);
 }
 
+int sys_wait(int *status)
+{
+       pid_t self;
+       int ret_val;
+
+       self = process_get_id(process_get_current());
+
+       /* wait for a signal from any process */
+       dbg_printf("[%u] going to wait\n", self);
+
+       ret_val = process_wait(-1);
+
+       /* TODO: Handle the signal */
+
+       return(ret_val);
+}
+
 int sys_waitpid(pid_t pid, int *status, int options)
 {
        return(-ENOSYS);
@@ -78,9 +307,9 @@ int sys_setsid(void)
        if(cproc) {
                /*
                 * At this point there is nothing that needs to be done here. Maybe
-                * in the future there will be more that needs to be done.
+                * in the future there will be lists that the child needs to be removed
+                * from, or things like that.
                 */
-
 #if 0
                process_t *pproc;
 
@@ -133,6 +362,14 @@ int sys_posixcall(stack_frame_t *stk)
                ret_val = sys_setsid();
                break;
 
+       case SYS_SLEEP:
+               ret_val = sys_sleep((unsigned int)stk->ebx);
+               break;
+
+       case SYS_EXECFVE:
+               ret_val = sys_execfve(stk);
+               break;
+
        default:
                ret_val = -EOPNOTSUPP;
                break;
index 8226ea6e808b795d09a02e5e784bd730be7b184c..075f9d71cfcf20d7d6a0b4656621ed5dc19988f8 100644 (file)
@@ -225,3 +225,48 @@ cxsendrecv:
 
        popl    %ebx
        ret
+
+.global fork
+fork:
+       pushl   %ebx
+
+       movl    $SYS_FORK, %eax
+       int             $SYSCALL_POSIX
+
+       popl    %ebx
+       ret
+
+.global execfve
+execfve:
+       pushl   %ebx
+
+       movl    $SYS_EXECFVE, %eax
+       movl    8(%esp), %ebx
+       movl    12(%esp), %ecx
+       movl    16(%esp), %edx
+       int             $SYSCALL_POSIX
+
+       popl    %ebx
+       ret
+
+       .global sleep
+sleep:
+       pushl   %ebx
+
+       movl    $SYS_SLEEP, %eax
+       movl    8(%esp), %ebx
+       int             $SYSCALL_POSIX
+
+       popl    %ebx
+       ret
+
+       .global wait
+wait:
+       pushl   %ebx
+
+       movl    $SYS_WAIT, %eax
+       movl    8(%esp), %ebx
+       int             $SYSCALL_POSIX
+
+       popl    %ebx
+       ret