From 1ff62e22bfa678427964a2fa931be5490dd64625 Mon Sep 17 00:00:00 2001 From: EnderIce2 Date: Fri, 7 Mar 2025 01:31:50 +0000 Subject: [PATCH] feat(kernel/syscalls): implement sys_fork() Signed-off-by: EnderIce2 --- Kernel/syscalls/native.cpp | 122 ++--------------- Kernel/syscalls/process.cpp | 256 ++++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 114 deletions(-) create mode 100644 Kernel/syscalls/process.cpp diff --git a/Kernel/syscalls/native.cpp b/Kernel/syscalls/native.cpp index bdfebd2f..bea35162 100644 --- a/Kernel/syscalls/native.cpp +++ b/Kernel/syscalls/native.cpp @@ -175,120 +175,14 @@ static off_t sys_seek(SysFrm *Frame, int fd, off_t offset, int whence) return fdt->usr_lseek(fd, offset, whence); } -static __noreturn void sys_exit(SysFrm *Frame, int status) -{ - TCB *t = thisThread; - { - CriticalSection cs; - trace("Userspace thread %s(%d) exited with code %d (%#x)", - t->Name, - t->ID, status, - status < 0 ? -status : status); - - t->SetState(Tasking::Zombie); - t->SetExitCode(status); - } - while (true) - t->GetContext()->Yield(); - __builtin_unreachable(); -} - -static pid_t sys_fork(SysFrm *Frame) { return -ENOSYS; } -static int sys_execve(SysFrm *Frame, const char *pathname, char *const argv[], char *const envp[]) { return -ENOSYS; } -static pid_t sys_getpid(SysFrm *Frame) { return -ENOSYS; } -static pid_t sys_getppid(SysFrm *Frame) { return -ENOSYS; } -static pid_t sys_waitpid(pid_t pid, int *wstatus, int options) { return -ENOSYS; } - -static int sys_kill(SysFrm *Frame, pid_t pid, int sig) -{ - PCB *pcb = thisProcess->GetContext()->GetProcessByID(pid); - if (!pcb) - return -ESRCH; - - /* TODO: Check permissions */ - - if (sig == 0) - return 0; - - if (pid == 0) - { - bool found = false; - foreach (auto proc in pcb->GetContext()->GetProcessList()) - { - if (proc->Security.ProcessGroupID == thisProcess->Security.ProcessGroupID) - { - debug("Sending signal %d to %s(%d)", sig, proc->Name, proc->ID); - proc->SendSignal(sig); - found = true; - } - } - if (!found) - return -ESRCH; - return 0; - } - - if (pid == -1) - { - fixme("Sending signal %d to all processes except init", sig); - return -ENOSYS; - } - - if (pid < -1) - { - fixme("Sending signal %d to process group %d", sig, pid); - return -ENOSYS; - } - - return pcb->SendSignal(sig); -} - -static int sys_prctl(SysFrm *Frame, prctl_options_t option, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) -{ - PCB *pcb = thisProcess; - Memory::VirtualMemoryArea *vma = pcb->vma; - - switch (option) - { - case __SYS_GET_GS: - { - auto arg = vma->UserCheckAndGetAddress((void *)arg1); - if (arg == nullptr) - return -EFAULT; - -#if defined(__amd64__) || defined(__i386__) - *r_cst(uintptr_t *, arg) = CPU::x86::rdmsr(CPU::x86::MSRID::MSR_GS_BASE); -#endif - return 0; - } - case __SYS_SET_GS: - { -#if defined(__amd64__) || defined(__i386__) - CPU::x86::wrmsr(CPU::x86::MSRID::MSR_GS_BASE, arg1); -#endif - return 0; - } - case __SYS_GET_FS: - { - auto arg = vma->UserCheckAndGetAddress((void *)arg1); - if (arg == nullptr) - return -EFAULT; - -#if defined(__amd64__) || defined(__i386__) - *r_cst(uintptr_t *, arg) = CPU::x86::rdmsr(CPU::x86::MSRID::MSR_FS_BASE); -#endif - return 0; - } - case __SYS_SET_FS: - { -#if defined(__amd64__) || defined(__i386__) - CPU::x86::wrmsr(CPU::x86::MSRID::MSR_FS_BASE, arg1); -#endif - return 0; - } - default: - return -EINVAL; - } -} +__noreturn void sys_exit(SysFrm *Frame, int status); +pid_t sys_fork(SysFrm *Frame); +int sys_execve(SysFrm *Frame, const char *pathname, char *const argv[], char *const envp[]); +pid_t sys_getpid(SysFrm *Frame); +pid_t sys_getppid(SysFrm *Frame); +pid_t sys_waitpid(pid_t pid, int *wstatus, int options); +int sys_kill(SysFrm *Frame, pid_t pid, int sig); +int sys_prctl(SysFrm *Frame, prctl_options_t option, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4); int sys_brk(SysFrm *Frame, void *end_data); void *sys_mmap(SysFrm *Frame, void *addr, size_t length, int prot, int flags, int fd, off_t offset); diff --git a/Kernel/syscalls/process.cpp b/Kernel/syscalls/process.cpp new file mode 100644 index 00000000..7fe3239b --- /dev/null +++ b/Kernel/syscalls/process.cpp @@ -0,0 +1,256 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../kernel.h" + +using Tasking::PCB; +using Tasking::TCB; + +__no_stack_protector void __ForkReturn(void *tableAddr) +{ +#if defined(__amd64__) + asmv("movq %0, %%cr3" ::"r"(tableAddr)); /* Load process page table */ + asmv("movq $0, %rax\n"); /* Return 0 */ + asmv("movq %r8, %rsp\n"); /* Restore stack pointer */ + asmv("movq %r8, %rbp\n"); /* Restore base pointer */ + asmv("swapgs\n"); /* Swap GS back to the user GS */ + asmv("sti\n"); /* Enable interrupts */ + asmv("sysretq\n"); /* Return to rcx address in user mode */ +#elif defined(__i386__) +#warning "__ForkReturn not implemented for i386" +#endif + __builtin_unreachable(); +} + +__noreturn void sys_exit(SysFrm *Frame, int status) +{ + TCB *t = thisThread; + { + CriticalSection cs; + trace("Userspace thread %s(%d) exited with code %d (%#x)", + t->Name, + t->ID, status, + status < 0 ? -status : status); + + t->SetState(Tasking::Zombie); + t->SetExitCode(status); + } + while (true) + t->GetContext()->Yield(); + __builtin_unreachable(); +} + +pid_t sys_fork(SysFrm *Frame) +{ + TCB *Thread = thisThread; + PCB *Parent = Thread->Parent; + + PCB *NewProcess = + TaskManager->CreateProcess(Parent, Parent->Name, + Parent->Security.ExecutionMode, + true); + if (unlikely(!NewProcess)) + { + error("Failed to create process for fork"); + return -EAGAIN; + } + + NewProcess->Security.ProcessGroupID = Parent->Security.ProcessGroupID; + NewProcess->Security.SessionID = Parent->Security.SessionID; + + NewProcess->PageTable = Parent->PageTable->Fork(); + NewProcess->vma->Table = NewProcess->PageTable; + NewProcess->vma->Fork(Parent->vma); + NewProcess->ProgramBreak->SetTable(NewProcess->PageTable); + NewProcess->FileDescriptors->Fork(Parent->FileDescriptors); + NewProcess->Executable = Parent->Executable; + NewProcess->CWD = Parent->CWD; + NewProcess->FileCreationMask = Parent->FileCreationMask; + + TCB *NewThread = + TaskManager->CreateThread(NewProcess, + 0, + nullptr, + nullptr, + std::vector(), + Thread->Info.Architecture, + Thread->Info.Compatibility, + true); + if (!NewThread) + { + error("Failed to create thread for fork"); + delete NewProcess; + return -EAGAIN; + } + NewThread->Rename(Thread->Name); + + TaskManager->UpdateFrame(); + +#if defined(__amd64__) || defined(__i386__) + NewThread->FPU = Thread->FPU; +#endif + NewThread->Stack->Fork(Thread->Stack); + NewThread->Info.Architecture = Thread->Info.Architecture; + NewThread->Info.Compatibility = Thread->Info.Compatibility; + NewThread->Security.IsCritical = Thread->Security.IsCritical; + NewThread->Registers = Thread->Registers; +#if defined(__amd64__) + NewThread->Registers.rip = (uintptr_t)__ForkReturn; + /* For sysretq */ + NewThread->Registers.rdi = (uintptr_t)NewProcess->PageTable; + NewThread->Registers.rcx = Frame->ReturnAddress; + NewThread->Registers.r8 = Frame->StackPointer; +#else +#warning "sys_fork not implemented for other platforms" +#endif + +#if defined(__amd64__) || defined(__i386__) + NewThread->GSBase = NewThread->ShadowGSBase; + NewThread->ShadowGSBase = Thread->ShadowGSBase; + NewThread->FSBase = Thread->FSBase; +#endif + + debug("ret addr: %#lx, stack: %#lx ip: %#lx", Frame->ReturnAddress, + Frame->StackPointer, (uintptr_t)__ForkReturn); + debug("Forked thread \"%s\"(%d) to \"%s\"(%d)", + Thread->Name, Thread->ID, + NewThread->Name, NewThread->ID); + NewThread->SetState(Tasking::Ready); + + // Parent->GetContext()->Yield(); + return (int)NewProcess->ID; +} + +int sys_execve(SysFrm *Frame, const char *pathname, char *const argv[], char *const envp[]) +{ + return -ENOSYS; +} + +pid_t sys_getpid(SysFrm *Frame) +{ + return -ENOSYS; +} + +pid_t sys_getppid(SysFrm *Frame) +{ + return -ENOSYS; +} + +pid_t sys_waitpid(pid_t pid, int *wstatus, int options) +{ + return -ENOSYS; +} + +int sys_kill(SysFrm *Frame, pid_t pid, int sig) +{ + PCB *pcb = thisProcess->GetContext()->GetProcessByID(pid); + if (!pcb) + return -ESRCH; + + /* TODO: Check permissions */ + + if (sig == 0) + return 0; + + if (pid == 0) + { + bool found = false; + foreach (auto proc in pcb->GetContext()->GetProcessList()) + { + if (proc->Security.ProcessGroupID == thisProcess->Security.ProcessGroupID) + { + debug("Sending signal %d to %s(%d)", sig, proc->Name, proc->ID); + proc->SendSignal(sig); + found = true; + } + } + if (!found) + return -ESRCH; + return 0; + } + + if (pid == -1) + { + fixme("Sending signal %d to all processes except init", sig); + return -ENOSYS; + } + + if (pid < -1) + { + fixme("Sending signal %d to process group %d", sig, pid); + return -ENOSYS; + } + + return pcb->SendSignal(sig); +} + +int sys_prctl(SysFrm *Frame, prctl_options_t option, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) +{ + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + switch (option) + { + case __SYS_GET_GS: + { + auto arg = vma->UserCheckAndGetAddress((void *)arg1); + if (arg == nullptr) + return -EFAULT; + +#if defined(__amd64__) || defined(__i386__) + *r_cst(uintptr_t *, arg) = CPU::x86::rdmsr(CPU::x86::MSRID::MSR_GS_BASE); +#endif + return 0; + } + case __SYS_SET_GS: + { +#if defined(__amd64__) || defined(__i386__) + CPU::x86::wrmsr(CPU::x86::MSRID::MSR_GS_BASE, arg1); +#endif + return 0; + } + case __SYS_GET_FS: + { + auto arg = vma->UserCheckAndGetAddress((void *)arg1); + if (arg == nullptr) + return -EFAULT; + +#if defined(__amd64__) || defined(__i386__) + *r_cst(uintptr_t *, arg) = CPU::x86::rdmsr(CPU::x86::MSRID::MSR_FS_BASE); +#endif + return 0; + } + case __SYS_SET_FS: + { +#if defined(__amd64__) || defined(__i386__) + CPU::x86::wrmsr(CPU::x86::MSRID::MSR_FS_BASE, arg1); +#endif + return 0; + } + default: + return -EINVAL; + } +}