diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index fd69a690..41c30157 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -11,6 +11,7 @@ extern syscall_getpid extern syscall_fstat extern syscall_fstatat extern syscall_fork +extern syscall_execve syscalltab: dq syscall_print dq syscall_mmap @@ -24,7 +25,8 @@ dq syscall_getpid dq syscall_fstat dq syscall_fstatat dq syscall_fork -syscallcount equ 12 +dq syscall_execve +syscallcount equ 13 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/sys/syscalls/execve.c b/kernel-src/sys/syscalls/execve.c new file mode 100644 index 00000000..020deb3a --- /dev/null +++ b/kernel-src/sys/syscalls/execve.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void freevec(char **v) { + char **it = v; + while (*it) + free(*it++); + + free(v); +} + +syscallret_t syscall_execve(context_t *context, char *upath, char *uargv[], char *uenvp[]) { + syscallret_t ret = { + .ret = -1 + }; + + // TODO user str ops + char *path = alloc(strlen(upath) + 1); + if (path == NULL) { + ret.errno = ENOMEM; + return ret; + } + strcpy(path, upath); + + size_t argsize = 0; + size_t envsize = 0; + char **argv = NULL; + char **envp = NULL; + vmmcontext_t *vmmctx = NULL; + vmmcontext_t *oldctx = _cpu()->vmmctx; + vnode_t *node = NULL; + vnode_t *refnode = NULL; + char *interp = NULL; + + while (uargv[argsize++]); + while (uenvp[envsize++]); + + argv = alloc((argsize + 1) * sizeof(char *)); + envp = alloc((envsize + 1) * sizeof(char *)); + + if (argv == NULL || envp == NULL) { + ret.errno = ENOMEM; + goto error; + } + + for (int i = 0; i < argsize - 1; ++i) { + argv[i] = alloc(strlen(uargv[i]) + 1); + if (argv[i] == NULL) { + ret.errno = ENOMEM; + goto error; + } + strcpy(argv[i], uargv[i]); + } + + for (int i = 0; i < envsize - 1; ++i) { + envp[i] = alloc(strlen(uenvp[i]) + 1); + if (envp[i] == NULL) { + ret.errno = ENOMEM; + goto error; + } + strcpy(envp[i], uenvp[i]); + } + + vmmctx = vmm_newcontext(); + if (vmmctx == NULL) { + ret.errno = ENOMEM; + goto error; + } + + refnode = *path == '/' ? sched_getroot() : sched_getcwd(); + + ret.errno = vfs_lookup(&node, vfsroot, "/usr/bin/bash", NULL, 0); + if (ret.errno) + goto error; + + // TODO permission and type checks and all + + vmm_switchcontext(vmmctx); + + auxv64list_t auxv64; + void *entry; + ret.errno = elf_load(node, NULL, &entry, &interp, &auxv64); + if (ret.errno) + goto error; + + if (interp) { + vnode_t *interpnode; + ret.errno = vfs_open(vfsroot, interp, 0, &interpnode); + if (ret.errno) + goto error; + + auxv64list_t interpauxv; + char *interpinterp = NULL; + ret.errno = elf_load(interpnode, INTERP_BASE, &entry, &interpinterp, &interpauxv); + if (ret.errno) + goto error; + + __assert(interpinterp == NULL); + } + + void *stack = elf_preparestack(STACK_TOP, &auxv64, argv, envp); + if (stack == NULL) { + ret.errno = ENOMEM; + goto error; + } + + // TODO kill other threads and close CLOEXEC fds + + error: + free(path); + if (argv) + freevec(argv); + + if (envp) + freevec(envp); + + if (vmmctx && ret.errno) { + vmm_switchcontext(oldctx); + vmm_destroycontext(vmmctx, 0); + } + + if (refnode) + VOP_RELEASE(refnode); + + if (node) + VOP_RELEASE(node); + + if (interp) + free(interp); + + if (ret.errno == 0) { + // TODO sync mmap files (unmap all lower memory first before destroying context?) + vmm_destroycontext(oldctx, 0); + CTX_SP(context) = (uint64_t)stack; + CTX_IP(context) = (uint64_t)entry; + } + + printf("exec ret: %lu %lu\n", ret.ret, ret.errno); + + return ret; +} diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index d9b6a1e2..a843d0fc 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -133,10 +133,10 @@ index 0000000..e5b087a + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 -index 0000000..3961e7f +index 0000000..e108341 --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp -@@ -0,0 +1,185 @@ +@@ -0,0 +1,190 @@ +#include +#include +#include @@ -200,6 +200,11 @@ index 0000000..3961e7f + return 0; + } + ++ int sys_execve(const char *path, char *const argv[], char *const envp[]) { ++ long ret = 0; ++ return syscall(SYSCALL_EXECVE, &ret, (uint64_t)path, (uint64_t)argv, (uint64_t)envp); ++ } ++ + int sys_fork(pid_t *pid) { + long ret = 0; + long error = syscall(SYSCALL_FORK, &ret); @@ -341,10 +346,10 @@ index 0000000..990eca0 +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 -index 0000000..16c462d +index 0000000..e23be0d --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -0,0 +1,35 @@ +@@ -0,0 +1,36 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + @@ -360,6 +365,7 @@ index 0000000..16c462d +#define SYSCALL_FSTAT 9 +#define SYSCALL_FSTATAT 10 +#define SYSCALL_FORK 11 ++#define SYSCALL_EXECVE 12 + +#include +#include