From: Matthias Kruk Date: Sat, 23 Nov 2019 06:30:35 +0000 (+0900) Subject: Add execfve() syscall X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=3784a4ef30a03afb1c60bbcaa39521d14414dba1;p=corax Add execfve() syscall --- diff --git a/kernel/core/posixcall.c b/kernel/core/posixcall.c index 34b2926..76a8fcc 100644 --- a/kernel/core/posixcall.c +++ b/kernel/core/posixcall.c @@ -8,6 +8,7 @@ #include #include #include +#include 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; diff --git a/kernel/core/syscall.S b/kernel/core/syscall.S index 8226ea6..075f9d7 100644 --- a/kernel/core/syscall.S +++ b/kernel/core/syscall.S @@ -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