diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index e92a795f..5653c67a 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -18,6 +18,7 @@ #define SYS_fcntl 13 #define SYS_mprotect 14 #define SYS_clock 15 +#define SYS_fork 16 namespace Syscall { @@ -41,4 +42,5 @@ void sys_seek(Context* context, int fd, long offset, int whence); void sys_exec(Context* context, const char* pathname); void sys_fcntl(Context* context, int fd, int command, uintptr_t arg); void sys_mprotect(Context* context, void* address, size_t size, int prot); -void sys_clock(Context* context); \ No newline at end of file +void sys_clock(Context* context); +void sys_fork(Context* context); \ No newline at end of file diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 243756ed..a8e10126 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -27,6 +27,7 @@ void Syscall::entry(Context* context) case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break; case SYS_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break; case SYS_clock: sys_clock(context); break; + case SYS_fork: sys_fork(context); break; default: context->rax = -ENOSYS; break; } VMM::exit_syscall_context(); diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index 9e5df9f7..ce4b621a 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -11,12 +11,43 @@ #include "sys/Syscall.h" #include "sys/elf/ELFLoader.h" #include "thread/Scheduler.h" +#include "utils/Addresses.h" + +void sys_fork(Context* context) // FIXME: Even though both processes's address spaces are the same in content, writing + // to one should not affect the other. +{ + kinfoln("fork(): attempting fork"); + + Task* parent = Scheduler::current_task(); + + Task* child = Scheduler::create_user_task(); + + memcpy(&child->regs, &parent->regs, sizeof(Context)); + if (parent->floating_saved) + { + memcpy(child->floating_region, parent->floating_region, sizeof(parent->floating_region)); + child->floating_saved = true; + } + for (int i = 0; i < TASK_MAX_FDS; i++) { child->files[i] = parent->files[i]; } + + size_t stack_bytes = get_top_of_stack(parent->allocated_stack, TASK_PAGES_IN_STACK) - parent->regs.rsp; + + child->regs.rsp -= stack_bytes; + + memcpy((void*)child->regs.rsp, (void*)parent->regs.rsp, stack_bytes); + + child->address_space = parent->address_space.clone(); + + child->regs.rax = 0; + context->rax = child->id; + + kinfoln("fork(): forked parent %d into child %d", parent->id, child->id); + + return; +} void sys_exec(Context* context, const char* pathname) { - /*context->rax = -ENOSYS; // FIXME: Make exec() work under separate address spaces. - return;*/ - char* kpathname = Syscall::strdup_from_user(pathname); if (!kpathname) {