Update kernel

This commit is contained in:
EnderIce2
2024-01-19 06:47:42 +02:00
parent fd15592608
commit 96daa43d38
282 changed files with 25486 additions and 15700 deletions

View File

@ -1,277 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include <ipc.hpp>
#include <task.hpp>
#include "../kernel.h"
#include "../ipc.h"
namespace InterProcessCommunication
{
void IPC::Fork(IPC *Parent)
{
std::vector<IPCHandle *> ParentHandles = Parent->GetHandles();
foreach (auto Hnd in ParentHandles)
{
debug("Forking IPC with ID %d", Hnd->ID);
IPCHandle *NewHnd = (IPCHandle *)vma->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1));
memcpy(NewHnd, Hnd, sizeof(IPCHandle));
NewHnd->Node = fs->Create(Hnd->Node->Name, vfs::NodeType::FILE, IPCNode);
Handles.push_back(NewHnd);
}
}
IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16])
{
UNUSED(Type);
SmartLock(this->IPCLock);
IPCHandle *Hnd = (IPCHandle *)vma->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1));
Hnd->ID = NextID++;
Hnd->Node = fs->Create(UniqueToken, vfs::NodeType::FILE, IPCNode);
Hnd->Buffer = nullptr;
Hnd->Length = 0;
Hnd->Listening = false;
Handles.push_back(Hnd);
debug("Created IPC with ID %d", Hnd->ID);
return Hnd;
}
IPCErrorCode IPC::Destroy(IPCID ID)
{
SmartLock(this->IPCLock);
forItr(itr, Handles)
{
if ((*itr)->ID == ID)
{
fs->Delete((*itr)->Node);
vma->FreePages((*itr), TO_PAGES(sizeof(IPCHandle) + 1));
Handles.erase(itr);
debug("Destroyed IPC with ID %d", ID);
return IPCSuccess;
}
}
debug("Failed to destroy IPC with ID %d", ID);
return IPCIDNotFound;
}
IPCErrorCode IPC::Allocate(IPCID ID, long Size)
{
SmartLock(this->IPCLock);
if (Size < 0)
return IPCError;
foreach (auto Hnd in Handles)
{
if (Hnd->ID == ID)
{
if (Hnd->Buffer != nullptr || Hnd->Length != 0)
return IPCAlreadyAllocated;
Hnd->Buffer = (uint8_t *)vma->RequestPages(TO_PAGES(Size + 1));
Hnd->Length = Size;
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPCErrorCode IPC::Deallocate(IPCID ID)
{
SmartLock(this->IPCLock);
foreach (auto Hnd in Handles)
{
if (Hnd->ID == ID)
{
if (Hnd->Buffer == nullptr || Hnd->Length == 0)
return IPCNotAllocated;
vma->FreePages(Hnd->Buffer, TO_PAGES(Hnd->Length + 1));
Hnd->Buffer = nullptr;
Hnd->Length = 0;
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPCErrorCode IPC::Read(IPCID ID, void *Buffer, long Size)
{
SmartLock(this->IPCLock);
if (Size < 0)
return IPCError;
foreach (auto Hnd in Handles)
{
if (Hnd->ID == ID)
{
if (Hnd->Listening)
{
debug("IPC %d is listening", ID);
return IPCNotListening;
}
if (Hnd->Length < Size)
{
debug("IPC %d is too small", ID);
return IPCError;
}
debug("IPC %d reading %d bytes", ID, Size);
memcpy(Buffer, Hnd->Buffer, Size);
debug("IPC read %d bytes", Size);
return IPCSuccess;
}
}
debug("IPC %d not found", ID);
return IPCIDNotFound;
}
IPCErrorCode IPC::Write(IPCID ID, void *Buffer, long Size)
{
SmartLock(this->IPCLock);
if (Size < 0)
{
debug("IPC %d is too small", ID);
return IPCError;
}
foreach (auto Hnd in Handles)
{
if (Hnd->ID == ID)
{
if (!Hnd->Listening)
{
debug("IPC %d is NOT listening", ID);
return IPCNotListening;
}
if (Hnd->Length < Size)
{
debug("IPC %d is too small", ID);
return IPCError;
}
debug("IPC %d writing %d bytes", ID, Size);
memcpy(Hnd->Buffer, Buffer, Size);
Hnd->Listening = false;
debug("IPC %d wrote %d bytes and now is %s", ID, Size, Hnd->Listening ? "listening" : "ready");
return IPCSuccess;
}
}
debug("IPC %d not found", ID);
return IPCIDNotFound;
}
IPCErrorCode IPC::Listen(IPCID ID, bool Listen)
{
foreach (auto Hnd in Handles)
{
if (Hnd->ID == ID)
{
Hnd->Listening = Listen;
debug("IPC %d is now set to %s", ID, Listen ? "listening" : "ready");
return IPCSuccess;
}
}
debug("IPC %d not found", ID);
return IPCIDNotFound;
}
IPCErrorCode IPC::Wait(IPCID ID)
{
foreach (auto Hnd in Handles)
{
if (Hnd->ID == ID)
{
if (!CPU::Interrupts())
warn("Interrupts are disabled. This may cause a kernel hang.");
debug("Waiting for IPC %d (now %s)", ID, Hnd->Listening ? "listening" : "ready");
while (Hnd->Listening)
TaskManager->Yield();
debug("IPC %d is ready", ID);
return IPCSuccess;
}
}
debug("IPC %d not found", ID);
return IPCIDNotFound;
}
IPCHandle *IPC::SearchByToken(char UniqueToken[16])
{
foreach (auto Hnd in Handles)
{
if (strcmp(Hnd->Node->Name, UniqueToken) == 0)
{
debug("Found IPC with token %s", UniqueToken);
return Hnd;
}
}
debug("Failed to find IPC with token %s", UniqueToken);
return nullptr;
}
int IPC::HandleSyscall(long Command, long Type, int ID, int Flags, void *Buffer, size_t Size)
{
switch (Command)
{
case IPC_CREATE:
{
char UniqueToken[16];
if (Buffer != nullptr)
strcpy(UniqueToken, (char *)Buffer);
else
snprintf(UniqueToken, 16, "IPC_%d", ID);
IPCHandle *Hnd = this->Create((IPCType)Type, UniqueToken);
this->Allocate(Hnd->ID, Size ? Size : PAGE_SIZE);
return Hnd->ID;
}
case IPC_READ:
return this->Read(ID, Buffer, Size);
case IPC_WRITE:
return TaskManager->GetProcessByID(Flags)->IPC->Write(ID, Buffer, Size);
case IPC_DELETE:
{
this->Deallocate(ID);
return this->Destroy(ID);
}
case IPC_WAIT:
return this->Wait(ID);
case IPC_LISTEN:
return this->Listen(ID, Flags);
default:
return IPCInvalidCommand;
}
return IPCError;
}
IPC::IPC(void *Process)
{
Tasking::PCB *pcb = (Tasking::PCB *)Process;
this->Process = Process;
this->vma = new Memory::VirtualMemoryArea(pcb->PageTable);
IPCNode = fs->Create("ipc", vfs::NodeType::DIRECTORY,
pcb->ProcessDirectory);
}
IPC::~IPC()
{
fs->Delete(IPCNode, true);
delete this->vma, this->vma = nullptr;
}
}

View File

@ -44,12 +44,29 @@
#define tskdbg(m, ...)
#endif
using namespace InterProcessCommunication;
using namespace vfs;
using vfs::NodeType;
namespace Tasking
{
int PCB::SendSignal(int sig)
{
return this->Signals->SendSignal(sig);
}
void PCB::SetState(TaskState state)
{
this->State.store(state);
if (this->Threads.size() == 1)
this->Threads.front()->State.store(state);
}
void PCB::SetExitCode(int code)
{
this->ExitCode.store(code);
if (this->Threads.size() == 1)
this->Threads.front()->ExitCode.store(code);
}
void PCB::Rename(const char *name)
{
assert(name != nullptr);
@ -74,6 +91,25 @@ namespace Tasking
trace("Setting working directory of process %s to %#lx (%s)",
this->Name, node, node->Name);
CurrentWorkingDirectory = node;
Node *cwd = fs->GetNodeFromPath("cwd", this);
if (cwd)
delete cwd;
cwd = fs->CreateLink("cwd", node->FullPath, this);
if (cwd == nullptr)
error("Failed to create cwd link");
}
void PCB::SetExe(const char *path)
{
trace("Setting exe %s to %s",
this->Name, path);
Executable = fs->GetNodeFromPath(path);
Node *exe = fs->GetNodeFromPath("exe", this);
if (exe)
delete exe;
exe = fs->CreateLink("exe", Executable->FullPath, this);
if (exe == nullptr)
error("Failed to create exe link");
}
size_t PCB::GetSize()
@ -92,11 +128,12 @@ namespace Tasking
PCB::PCB(Task *ctx, PCB *Parent, const char *Name,
TaskExecutionMode ExecutionMode, void *Image,
bool DoNotCreatePageTable,
bool UseKernelPageTable,
uint16_t UserID, uint16_t GroupID)
: Node(ProcFS, std::to_string(ctx->NextPID), NodeType::DIRECTORY)
{
debug("+ %#lx", this);
assert(ctx != nullptr);
assert(Name != nullptr);
assert(strlen(Name) > 0);
@ -154,36 +191,25 @@ namespace Tasking
assert(false);
}
char ProcFSName[12];
sprintf(ProcFSName, "%d", this->ID);
this->ProcessDirectory = fs->Create(ProcFSName, DIRECTORY, ProcFS);
this->FileDescriptors = new FileDescriptorTable(this);
/* If create page table */
if (DoNotCreatePageTable == false)
if (UseKernelPageTable == false)
{
OwnPageTable = true;
size_t PTPgs = TO_PAGES(sizeof(Memory::PageTable) + 1);
this->PageTable = (Memory::PageTable *)KernelAllocator.RequestPages(PTPgs);
memcpy(this->PageTable, KernelPageTable, sizeof(Memory::PageTable));
this->PageTable = KernelPageTable->Fork();
debug("Process %s(%d) has page table at %#lx",
this->Name, this->ID, this->PageTable);
}
else
this->PageTable = KernelPageTable;
this->vma = new Memory::VirtualMemoryArea(this->PageTable);
this->ProgramBreak = new Memory::ProgramBreak(this->PageTable, this->vma);
this->IPC = new class IPC((void *)this);
this->Signals = new Signal(this);
if (Image)
{
this->ELFSymbolTable = new SymbolResolver::Symbols((uintptr_t)Image);
this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
}
if (Parent)
Parent->Children.push_back(this);
debug("Process page table: %#lx", this->PageTable);
debug("Created %s process \"%s\"(%d). Parent \"%s\"(%d)",
@ -198,9 +224,13 @@ namespace Tasking
this->AllocatedMemory += FROM_PAGES(TO_PAGES(sizeof(Memory::PageTable) + 1));
this->AllocatedMemory += sizeof(Memory::VirtualMemoryArea);
this->AllocatedMemory += sizeof(Memory::ProgramBreak);
this->AllocatedMemory += sizeof(class IPC);
this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
this->AllocatedMemory += sizeof(Signal);
this->Info.SpawnTime = TimeManager->GetCounter();
if (Parent)
Parent->Children.push_back(this);
ctx->ProcessList.push_back(this);
}
@ -221,8 +251,8 @@ namespace Tasking
if (this->ELFSymbolTable)
delete this->ELFSymbolTable;
debug("Freeing IPC");
delete this->IPC;
debug("Freeing signals");
delete this->Signals;
debug("Freeing allocated memory");
delete this->ProgramBreak;
@ -242,14 +272,31 @@ namespace Tasking
/* Exit all children processes */
foreach (auto pcb in this->Children)
{
if (pcb == nullptr)
{
warn("Process is null? Kernel bug");
continue;
}
debug("Destroying child process \"%s\"(%d)",
pcb->Name, pcb->ID);
delete pcb;
}
/* Exit all threads */
foreach (auto tcb in this->Threads)
delete tcb;
{
if (tcb == nullptr)
{
warn("Thread is null? Kernel bug");
continue;
}
debug("Removing /proc/%d", this->ID);
fs->Delete(this->ProcessDirectory, true);
debug("Destroying thread \"%s\"(%d)",
tcb->Name, tcb->ID);
delete tcb;
}
/* Free Name */
delete[] this->Name;
@ -257,11 +304,14 @@ namespace Tasking
debug("Removing from parent process");
if (this->Parent)
{
std::vector<Tasking::PCB *> &pChild = this->Parent->Children;
std::list<Tasking::PCB *> &pChild = this->Parent->Children;
pChild.erase(std::find(pChild.begin(),
pChild.end(),
this));
}
debug("Process \"%s\"(%d) destroyed",
this->Name, this->ID);
}
}

View File

@ -110,6 +110,12 @@ extern "C" SafeFunction NIF void TaskingScheduler_OneShot(int TimeSlice)
{
if (TimeSlice == 0)
TimeSlice = Tasking::TaskPriority::Normal;
#ifdef DEBUG
if (DebuggerIsAttached)
TimeSlice += 10;
#endif
#if defined(a86)
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x86::IRQ16, TimeSlice);
#elif defined(aa64)
@ -348,13 +354,16 @@ namespace Tasking
if (process->Threads.size() == 1)
{
process->State.exchange(process->Threads[0]->State.load());
process->State.exchange(process->Threads.front()->State.load());
continue;
}
bool AllThreadsSleeping = true;
foreach (auto thread in process->Threads)
{
if (thread->State.load() == TaskState::Terminated)
continue;
if (thread->State.load() != TaskState::Sleeping)
{
AllThreadsSleeping = false;
@ -409,6 +418,24 @@ namespace Tasking
}
}
SafeFunction NIF void Task::CleanupTerminated()
{
foreach (auto pcb in ProcessList)
{
if (pcb->State.load() == TaskState::Terminated)
{
delete pcb;
continue;
}
foreach (TCB *tcb in pcb->Threads)
{
if (tcb->State == Terminated)
delete tcb;
}
}
}
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
int SuccessSource = 0;
int sanity;
@ -434,6 +461,7 @@ namespace Tasking
"Block",
"Wait",
"Core",
"Zombie",
"Terminated",
};
@ -485,11 +513,7 @@ namespace Tasking
}
#endif
#ifdef a64
SafeFunction NIF void Task::Schedule(CPU::x64::TrapFrame *Frame)
#else
SafeFunction NIF void Task::Schedule(CPU::x32::TrapFrame *Frame)
#endif
SafeFunction NIF void Task::Schedule(CPU::TrapFrame *Frame)
{
if (unlikely(StopScheduler))
{
@ -497,43 +521,15 @@ namespace Tasking
return;
}
bool ProcessNotChanged = false;
/* Restore kernel page table for safety reasons. */
#ifdef a64
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable});
#else
CPU::x32::writecr3({.raw = (uint32_t)KernelPageTable});
#endif
/* Restore kernel page table for safety reasons. */
if (!SchedulerUpdateTrapFrame)
KernelPageTable->Update();
uint64_t SchedTmpTicks = TimeManager->GetCounter();
this->LastTaskTicks.store(size_t(SchedTmpTicks - this->SchedulerTicks.load()));
CPUData *CurrentCPU = GetCurrentCPU();
this->LastCore.store(CurrentCPU->ID);
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
#ifdef DEBUG_SCHEDULER
{
schedbg("================================================================");
schedbg("State: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
size_t ds;
asmv("mov %%ds, %0"
: "=r"(ds));
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
schedbg("================================================================");
}
#endif
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess.load()) ||
InvalidTCB(CurrentCPU->CurrentThread.load())))
{
@ -563,6 +559,9 @@ namespace Tasking
if (CurrentCPU->CurrentThread->State.load() == TaskState::Running)
CurrentCPU->CurrentThread->State.store(TaskState::Ready);
this->CleanupTerminated();
schedbg("Passed CleanupTerminated");
this->UpdateProcessState();
schedbg("Passed UpdateProcessState");
@ -571,8 +570,13 @@ namespace Tasking
if (this->SchedulerUpdateTrapFrame)
{
debug("Updating trap frame");
this->SchedulerUpdateTrapFrame = false;
goto Success;
CurrentCPU->CurrentProcess->State.store(TaskState::Running);
CurrentCPU->CurrentThread->State.store(TaskState::Running);
*Frame = CurrentCPU->CurrentThread->Registers;
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
return;
}
if (this->GetNextAvailableThread(CurrentCPU))
@ -637,20 +641,13 @@ namespace Tasking
*Frame = CurrentCPU->CurrentThread->Registers;
for (size_t i = 0; i < (sizeof(CurrentCPU->CurrentThread->IPHistory) / sizeof(CurrentCPU->CurrentThread->IPHistory[0])) - 1; i++)
CurrentCPU->CurrentThread->IPHistory[i + 1] = CurrentCPU->CurrentThread->IPHistory[i];
#ifdef a64
CurrentCPU->CurrentThread->IPHistory[0] = Frame->rip;
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
CPU::x64::fxrstor(&CurrentCPU->CurrentThread->FPU);
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase);
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
#else
CurrentCPU->CurrentThread->IPHistory[0] = Frame->eip;
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
CPU::x32::fxrstor(&CurrentCPU->CurrentThread->FPU);
CPU::x32::wrmsr(CPU::x32::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase);
@ -658,6 +655,8 @@ namespace Tasking
CPU::x32::wrmsr(CPU::x32::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
#endif
CurrentCPU->CurrentProcess->Signals->HandleSignal(Frame);
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
OnScreenTaskManagerUpdate();
#endif
@ -682,7 +681,8 @@ namespace Tasking
(&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter();
TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority);
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled &&
CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
{
#ifdef a64
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
@ -722,18 +722,10 @@ namespace Tasking
End:
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
#ifdef a64
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
#else
CPU::x32::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
#endif
CurrentCPU->CurrentProcess->PageTable->Update();
}
#ifdef a64
SafeFunction NIF void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
#else
SafeFunction NIF void Task::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
#endif
SafeFunction NIF void Task::OnInterruptReceived(CPU::TrapFrame *Frame)
{
SmartCriticalSection(SchedulerLock);
this->Schedule(Frame);
@ -759,11 +751,11 @@ namespace Tasking
fixme("unimplemented");
}
SafeFunction void Task::Schedule(CPU::aarch64::TrapFrame *Frame)
SafeFunction void Task::Schedule(CPU::TrapFrame *Frame)
{
fixme("unimplemented");
}
SafeFunction void Task::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame) { this->Schedule(Frame); }
SafeFunction void Task::OnInterruptReceived(CPU::TrapFrame *Frame) { this->Schedule(Frame); }
#endif
}

732
tasking/signal.cpp Normal file
View File

@ -0,0 +1,732 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include <signal.hpp>
#include <dumper.hpp>
#include <task.hpp>
#include <errno.h>
#if defined(a64)
#include "../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#include "../arch/i386/cpu/gdt.hpp"
#elif defined(aa64)
#endif
#include "../kernel.h"
#ifdef DEBUG
const char *lSigStr[] = {
"SIGHUP",
"SIGINT",
"SIGQUIT",
"SIGILL",
"SIGTRAP",
"SIGABRT",
"SIGBUS",
"SIGFPE",
"SIGKILL",
"SIGUSR1",
"SIGSEGV",
"SIGUSR2",
"SIGPIPE",
"SIGALRM",
"SIGTERM",
"SIGSTKFLT",
"SIGCHLD",
"SIGCONT",
"SIGSTOP",
"SIGTSTP",
"SIGTTIN",
"SIGTTOU",
"SIGURG",
"SIGXCPU",
"SIGXFSZ",
"SIGVTALRM",
"SIGPROF",
"SIGWINCH",
"SIGPOLL",
"SIGPWR",
"SIGSYS",
"SIGUNUSED",
};
const char *sigStr[] = {
"INVALID ",
"SIGABRT ",
"SIGALRM ",
"SIGBUS ",
"SIGCHLD ",
"SIGCONT ",
"SIGFPE ",
"SIGHUP ",
"SIGILL ",
"SIGINT ",
"SIGKILL ",
"SIGPIPE ",
"SIGQUIT ",
"SIGSEGV ",
"SIGSTOP ",
"SIGTERM ",
"SIGTSTP ",
"SIGTTIN ",
"SIGTTOU ",
"SIGUSR1 ",
"SIGUSR2 ",
"SIGPOLL ",
"SIGPROF ",
"SIGSYS ",
"SIGTRAP ",
"SIGURG ",
"SIGVTALRM",
"SIGXCPU ",
"SIGXFSZ ",
"SIGRSV1 ",
"SIGRSV2 ",
};
const char *dispStr[] = {
"SIG_TERM",
"SIG_IGN ",
"SIG_CORE",
"SIG_STOP",
"SIG_CONT",
};
#endif
extern "C" uintptr_t _sig_native_trampoline_start, _sig_native_trampoline_end;
extern "C" uintptr_t _sig_linux_trampoline_start, _sig_linux_trampoline_end;
static const struct
{
int linuxSignal;
int nativeSignal;
} signalMapping[] = {
{linux_SIGHUP, SIGHUP},
{linux_SIGINT, SIGINT},
{linux_SIGQUIT, SIGQUIT},
{linux_SIGILL, SIGILL},
{linux_SIGTRAP, SIGTRAP},
{linux_SIGABRT, SIGABRT},
{linux_SIGBUS, SIGBUS},
{linux_SIGFPE, SIGFPE},
{linux_SIGKILL, SIGKILL},
{linux_SIGUSR1, SIGUSR1},
{linux_SIGSEGV, SIGSEGV},
{linux_SIGUSR2, SIGUSR2},
{linux_SIGPIPE, SIGPIPE},
{linux_SIGALRM, SIGALRM},
{linux_SIGTERM, SIGTERM},
{linux_SIGSTKFLT, SIGRSV1},
{linux_SIGCHLD, SIGCHLD},
{linux_SIGCONT, SIGCONT},
{linux_SIGSTOP, SIGSTOP},
{linux_SIGTSTP, SIGTSTP},
{linux_SIGTTIN, SIGTTIN},
{linux_SIGTTOU, SIGTTOU},
{linux_SIGURG, SIGURG},
{linux_SIGXCPU, SIGXCPU},
{linux_SIGXFSZ, SIGXFSZ},
{linux_SIGVTALRM, SIGVTALRM},
{linux_SIGPROF, SIGPROF},
{linux_SIGPOLL, SIGPOLL},
{linux_SIGPWR, SIGRSV2},
{linux_SIGSYS, SIGSYS},
{linux_SIGUNUSED, SIGSYS},
};
static_assert(linux_SIGUNUSED == SIGNAL_MAX);
#define CTLif(x) ConvertToLinuxIfNecessary(x)
#define CTNif(x) ConvertToNativeIfNecessary(x)
#define CSigTLif(x) ConvertSigsetToLinuxIfNecessary(x)
#define CSigTNif(x) ConvertSigsetToNativeIfNecessary(x)
/* TODO: CTLif & CTNif may need optimization */
namespace Tasking
{
bool Signal::LinuxSig()
{
return ((PCB *)ctx)->Info.Compatibility == Linux;
}
int Signal::ConvertToLinuxIfNecessary(int sig)
{
if (!LinuxSig())
{
debug("Not linux sig: %d", sig);
return sig;
}
foreach (auto &mapping in signalMapping)
{
if (mapping.nativeSignal == sig)
{
// debug("Converted %d to %d", sig, mapping.linuxSignal);
return mapping.linuxSignal;
}
}
return -1;
}
int Signal::ConvertToNativeIfNecessary(int sig)
{
if (!LinuxSig())
{
debug("Not native sig: %d", sig);
return sig;
}
foreach (auto &mapping in signalMapping)
{
if (mapping.linuxSignal == sig)
{
// debug("Converted %d to %d", sig, mapping.nativeSignal);
return mapping.nativeSignal;
}
}
return -1;
}
sigset_t Signal::ConvertSigsetToLinuxIfNecessary(sigset_t sig)
{
if (!LinuxSig())
{
debug("Not linux sigset: %#lx", sig);
return 0;
}
sigset_t ret = 0;
for (int i = 0; i < SIGNAL_MAX; i++)
{
if (sig & ToFlag(i))
ret |= ToFlag(CTLif(i));
}
return ret;
}
sigset_t Signal::ConvertSigsetToNativeIfNecessary(sigset_t sig)
{
if (!LinuxSig())
{
debug("Not native sigset: %#lx", sig);
return 0;
}
sigset_t ret = 0;
for (int i = 0; i < linux_SIGUNUSED; i++)
{
if (sig & ToFlag(i))
ret |= ToFlag(CTNif(i));
}
return ret;
}
int Signal::MakeExitCode(int sig)
{
if (this->LinuxSig())
return 128 + sig;
else
return 100 + sig;
}
/* ------------------------------------------------------ */
int Signal::AddWatcher(Signal *who, int sig)
{
SmartLock(SignalLock);
SignalInfo info;
info.sig = sig;
info.val.sival_ptr = who;
Watchers.push_back(info);
return 0;
}
int Signal::RemoveWatcher(Signal *who, int sig)
{
SmartLock(SignalLock);
forItr(itr, Watchers)
{
if (itr->sig == sig &&
itr->val.sival_ptr == who)
{
Watchers.erase(itr);
return 0;
}
}
return -ENOENT;
}
int Signal::AddSignal(int sig, union sigval val)
{
SmartLock(SignalLock);
SignalInfo info{.sig = sig, .val = val};
SignalQueue.push_back(info);
return 0;
}
int Signal::RemoveSignal(int sig)
{
SmartLock(SignalLock);
forItr(itr, SignalQueue)
{
if (itr->sig == sig)
{
SignalQueue.erase(itr);
return 0;
}
}
return -ENOENT;
}
bool Signal::HandleSignal(CPU::TrapFrame *tf)
{
SmartLock(SignalLock);
if (SignalQueue.empty())
return false;
/* We don't want to do this in kernel mode */
if (unlikely(tf->cs != GDT_USER_CODE &&
tf->cs != GDT_USER_DATA))
{
// debug("Not user-mode");
return false;
}
debug("We have %d signals to handle", SignalQueue.size());
SignalInfo sigI = SignalQueue.front();
SignalQueue.erase(SignalQueue.begin());
uintptr_t _p_rsp = ((PCB *)ctx)->PageTable->Get(tf->rsp);
uint64_t paRsp = _p_rsp;
paRsp &= ~0xF; /* Align */
paRsp -= 128; /* Red zone */
/* Calculate the virtual rsp */
uintptr_t _v_rsp = tf->rsp;
_v_rsp &= ~0xF; /* Align */
_v_rsp -= 128; /* Red zone */
uint64_t *vRsp = (uint64_t *)(_v_rsp - sizeof(StackInfo));
vRsp--; /* Alignment */
vRsp--; /* Handler Address */
assert(!((uintptr_t)vRsp & 0xF));
/* Add the stack info */
StackInfo si{};
CPU::x64::fxsave(&si.fx);
si.tf = *tf;
si.GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
si.FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
si.ShadowGSBase = CPU::x64::rdmsr(CPU::x64::MSR_SHADOW_GS_BASE);
debug("gs: %#lx fs: %#lx shadow: %#lx",
si.GSBase, si.FSBase, si.ShadowGSBase);
si.SignalMask = SignalMask.load();
si.Compatibility = ((PCB *)ctx)->Info.Compatibility;
/* Copy the stack info */
uint64_t *pRsp = (uint64_t *)(paRsp - sizeof(StackInfo));
memcpy(pRsp, &si, sizeof(StackInfo));
/* Set the handler address */
pRsp--; /* Alignment */
pRsp--;
*pRsp = uint64_t(SignalAction[sigI.sig].__sa_handler.sa_handler);
assert(!((uintptr_t)pRsp & 0xF));
#ifdef DEBUG
DumpData("Stack Data", (void *)pRsp,
paRsp - uint64_t(pRsp));
debug("initial stack tf->rsp: %#lx after: %#lx",
tf->rsp, uint64_t(vRsp));
debug("sig: %d -> %d", sigI.sig, CTLif(sigI.sig));
#endif
tf->rsp = uint64_t(vRsp);
tf->rip = uint64_t(TrampAddr);
tf->rdi = CTLif(sigI.sig);
tf->rsi = uint64_t(sigI.val.sival_ptr);
return true;
}
void Signal::RestoreHandleSignal(SyscallsFrame *sf)
{
SmartLock(SignalLock);
debug("Restoring signal handler");
gsTCB *gs = (gsTCB *)CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
uint64_t *sp = (uint64_t *)((PCB *)ctx)->PageTable->Get(gs->TempStack);
sp++; /* Alignment */
sp++; /* Handler Address */
assert(!((uintptr_t)sp & 0xF));
StackInfo *si = (StackInfo *)sp;
assert(si != nullptr);
sf->r15 = si->tf.r15;
sf->r14 = si->tf.r14;
sf->r13 = si->tf.r13;
sf->r12 = si->tf.r12;
sf->r11 = si->tf.r11;
sf->r10 = si->tf.r10;
sf->r9 = si->tf.r9;
sf->r8 = si->tf.r8;
sf->rbp = si->tf.rbp;
sf->rdi = si->tf.rdi;
sf->rsi = si->tf.rsi;
sf->rdx = si->tf.rdx;
sf->rcx = si->tf.rcx;
sf->rbx = si->tf.rbx;
sf->rax = si->tf.rax;
sf->Flags = si->tf.rflags.raw;
sf->ReturnAddress = si->tf.rip;
gs->TempStack = si->tf.rsp;
SignalMask.store(si->SignalMask);
CPU::x64::fxrstor(&si->fx);
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, si->ShadowGSBase);
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, si->FSBase);
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, si->GSBase);
debug("gs: %#lx fs: %#lx shadow: %#lx",
si->GSBase, si->FSBase, si->ShadowGSBase);
// ((PCB *)ctx)->GetContext()->Yield();
// __builtin_unreachable();
/* Return because we will restore at sysretq */
}
sigset_t Signal::Block(sigset_t sig)
{
SmartLock(SignalLock);
sig = CSigTNif(sig);
sigset_t oldMask = SignalMask.fetch_or(sig);
debug("%#lx -> %#lx", oldMask, SignalMask);
return CSigTLif(oldMask);
}
sigset_t Signal::Unblock(sigset_t sig)
{
SmartLock(SignalLock);
sig = CSigTNif(sig);
sigset_t oldMask = SignalMask.fetch_and(~sig);
debug("%#lx -> %#lx", oldMask, SignalMask);
return CSigTLif(oldMask);
}
sigset_t Signal::SetMask(sigset_t sig)
{
SmartLock(SignalLock);
sig = CSigTNif(sig);
sigset_t oldMask = SignalMask.exchange(sig);
debug("%#lx -> %#lx", oldMask, SignalMask);
return CSigTLif(oldMask);
}
int Signal::SetAction(int sig, const sigaction act)
{
SmartLock(SignalLock);
if ((size_t)sig > sizeof(SignalAction) / sizeof(SignalAction[0]))
return -EINVAL;
sig = CTNif(sig);
SignalAction[sig].__sa_handler.sa_handler = act.__sa_handler.sa_handler;
SignalAction[sig].sa_mask = act.sa_mask;
SignalAction[sig].sa_flags = act.sa_flags;
debug("Set action for %s with handler %#lx, mask %#lx and flags %#lx",
LinuxSig() ? lSigStr[sig] : sigStr[sig],
SignalAction[sig].__sa_handler.sa_handler,
SignalAction[sig].sa_mask,
SignalAction[sig].sa_flags);
return 0;
}
int Signal::GetAction(int sig, sigaction *act)
{
SmartLock(SignalLock);
if ((size_t)sig > sizeof(SignalAction) / sizeof(SignalAction[0]))
return -EINVAL;
sig = CTNif(sig);
act->__sa_handler.sa_handler = SignalAction[sig].__sa_handler.sa_handler;
act->sa_mask = SignalAction[sig].sa_mask;
act->sa_flags = SignalAction[sig].sa_flags;
debug("Got action for %s with handler %#lx, mask %#lx and flags %#lx",
LinuxSig() ? lSigStr[sig] : sigStr[sig],
SignalAction[sig].__sa_handler.sa_handler,
SignalAction[sig].sa_mask,
SignalAction[sig].sa_flags);
return 0;
}
int Signal::SendSignal(int sig, union sigval val)
{
PCB *pcb = (PCB *)ctx;
sig = CTNif(sig);
LastSignal = (Signals)sig;
debug("Sending signal %s to %s(%d)",
sigStr[sig], pcb->Name, pcb->ID);
if (SignalAction[sig].__sa_handler.sa_handler)
{
if (pcb->Security.ExecutionMode == Kernel)
{
info("Kernel processes cannot have signal handlers");
return -EINVAL;
}
debug("sa_handler: %#lx",
SignalAction[sig].__sa_handler.sa_handler);
debug("Adding signal %s to queue", sigStr[sig]);
goto CompleteSignal;
}
debug("Signal disposition: %s", dispStr[sigDisp[sig]]);
switch (sigDisp[sig])
{
case SIG_TERM:
{
if (unlikely(pcb->Security.IsCritical))
{
debug("Critical process %s received signal %s(%d): Terminated",
pcb->Name, sigStr[sig], sig);
// int3;
}
pcb->SetExitCode(MakeExitCode(sig));
debug("We have %d watchers", this->Watchers.size());
if (this->Watchers.size() > 0)
pcb->SetState(Zombie);
else
pcb->SetState(Terminated);
break;
}
case SIG_IGN:
{
debug("Ignoring signal %d", sig);
return 0;
}
case SIG_CORE:
{
fixme("core dump");
if (unlikely(pcb->Security.IsCritical))
{
debug("Critical process %s received signal %s(%d): Core dumped",
pcb->Name, sigStr[sig], sig);
// int3;
}
pcb->SetExitCode(MakeExitCode(sig));
debug("We have %d watchers", this->Watchers.size());
if (this->Watchers.size() > 0)
pcb->SetState(CoreDump);
else
pcb->SetState(Terminated);
break;
}
case SIG_STOP:
{
pcb->SetState(Stopped);
break;
}
case SIG_CONT:
{
pcb->SetState(Ready);
break;
}
default:
assert(!"Invalid signal disposition");
return -EINVAL;
};
CompleteSignal:
if (pcb->Security.ExecutionMode == Kernel)
{
debug("Kernel process %s received signal %s(%d)! Ignoring... (with exceptions)",
pcb->Name, sigStr[sig], sig);
return 0;
}
if (unlikely(TrampAddr == nullptr))
{
debug("Trampoline not set up yet");
switch (thisThread->Info.Compatibility)
{
case Native:
{
debug("%#lx - %#lx",
&_sig_native_trampoline_end,
&_sig_native_trampoline_start);
TrampSz = (size_t)&_sig_native_trampoline_end -
(size_t)&_sig_native_trampoline_start;
TrampAddr = pcb->vma->RequestPages(TO_PAGES(TrampSz), true);
memcpy((void *)TrampAddr,
(void *)&_sig_native_trampoline_start,
TrampSz);
debug("Trampoline at %#lx with size %lld",
TrampAddr, TrampSz);
break;
}
case Linux:
{
debug("%#lx - %#lx",
&_sig_linux_trampoline_end,
&_sig_linux_trampoline_start);
TrampSz = (size_t)&_sig_linux_trampoline_end -
(size_t)&_sig_linux_trampoline_start;
TrampAddr = pcb->vma->RequestPages(TO_PAGES(TrampSz), true);
memcpy((void *)TrampAddr,
(void *)&_sig_linux_trampoline_start,
TrampSz);
debug("Trampoline at %#lx with size %lld",
TrampAddr, TrampSz);
break;
}
default:
{
assert(!"Not implemented");
break;
}
}
}
debug("Signal %s(%d) completed", sigStr[sig], sig);
if (sigDisp[sig] != SIG_IGN)
{
foreach (auto info in Watchers)
{
Signal *who = (Signal *)info.val.sival_ptr;
assert(who != nullptr);
debug("Sending SIGCHLD to %s(%d)",
((PCB *)who->GetContext())->Name,
((PCB *)who->GetContext())->ID);
who->SendSignal(SIGCHLD, val);
}
}
debug("Adding signal to queue");
SignalQueue.push_back({.sig = sig, .val = val});
return 0;
}
int Signal::WaitAnySignal()
{
/* Sleep until a signal that terminated or invokes
the signal catch function */
debug("Waiting for any signal");
size_t oldSize = SignalQueue.size();
Reset:
while (SignalQueue.size() == oldSize)
TaskManager->Yield();
if (SignalQueue.size() > oldSize)
{
debug("Added signal to queue %d > %d",
SignalQueue.size(), oldSize);
oldSize = SignalQueue.size();
goto Reset;
}
debug("Signal received");
return -EINTR;
}
int Signal::WaitSignal(int sig, union sigval *val)
{
return 0;
}
int Signal::WaitSignalTimeout(int sig, union sigval *val, uint64_t timeout)
{
return 0;
}
Signal::Signal(void *ctx)
{
assert(ctx != nullptr);
this->ctx = ctx;
sigDisp[SIG_NULL] = SIG_IGN;
sigDisp[SIGABRT] = SIG_CORE;
sigDisp[SIGALRM] = SIG_TERM;
sigDisp[SIGBUS] = SIG_CORE;
sigDisp[SIGCHLD] = SIG_IGN;
sigDisp[SIGCONT] = SIG_CONT;
sigDisp[SIGFPE] = SIG_CORE;
sigDisp[SIGHUP] = SIG_TERM;
sigDisp[SIGILL] = SIG_CORE;
sigDisp[SIGINT] = SIG_TERM;
sigDisp[SIGKILL] = SIG_TERM;
sigDisp[SIGPIPE] = SIG_TERM;
sigDisp[SIGQUIT] = SIG_TERM;
sigDisp[SIGSEGV] = SIG_CORE;
sigDisp[SIGSTOP] = SIG_STOP;
sigDisp[SIGTERM] = SIG_TERM;
sigDisp[SIGTSTP] = SIG_STOP;
sigDisp[SIGTTIN] = SIG_STOP;
sigDisp[SIGTTOU] = SIG_STOP;
sigDisp[SIGUSR1] = SIG_TERM;
sigDisp[SIGUSR2] = SIG_TERM;
sigDisp[SIGPOLL] = SIG_TERM;
sigDisp[SIGPROF] = SIG_TERM;
sigDisp[SIGSYS] = SIG_CORE;
sigDisp[SIGTRAP] = SIG_CORE;
sigDisp[SIGURG] = SIG_IGN;
sigDisp[SIGVTALRM] = SIG_TERM;
sigDisp[SIGXCPU] = SIG_CORE;
sigDisp[SIGXFSZ] = SIG_CORE;
#ifdef DEBUG
static int once = 0;
if (!once++)
{
if (LinuxSig())
{
for (int i = 0; i <= linux_SIGUNUSED; i++)
debug("%s: %s",
lSigStr[i],
dispStr[sigDisp[i]]);
}
else
{
for (int i = 0; i < SIGNAL_MAX; i++)
debug("%s: %s",
sigStr[i],
dispStr[sigDisp[i]]);
}
}
#endif
}
Signal::~Signal() {}
}

View File

@ -103,11 +103,6 @@ namespace Tasking
SafeFunction bool Task::RemoveThread(TCB *Thread)
{
if (Thread->KeepInMemory.load() == true)
return false;
if (Thread->KeepTime > TimeManager->GetCounter())
return false;
debug("Thread \"%s\"(%d) removed from process \"%s\"(%d)",
Thread->Name, Thread->ID, Thread->Parent->Name,
Thread->Parent->ID);
@ -123,11 +118,6 @@ namespace Tasking
if (Process->State == Terminated)
{
if (Process->KeepInMemory.load() == true)
return false;
if (Process->KeepTime > TimeManager->GetCounter())
return false;
delete Process;
return true;
}
@ -201,7 +191,8 @@ namespace Tasking
pcb->Name, pcb->ID);
while (pcb->State != TaskState::Terminated &&
pcb->State != TaskState::Zombie)
pcb->State != TaskState::Zombie &&
pcb->State != TaskState::CoreDump)
this->Yield();
}
@ -217,7 +208,8 @@ namespace Tasking
tcb->Name, tcb->ID);
while (tcb->State != TaskState::Terminated &&
tcb->State != TaskState::Zombie)
tcb->State != TaskState::Zombie &&
tcb->State != TaskState::CoreDump)
this->Yield();
}
@ -254,14 +246,14 @@ namespace Tasking
void Task::Sleep(uint64_t Milliseconds, bool NoSwitch)
{
TCB *thread = this->GetCurrentThread();
PCB *process = this->GetCurrentProcess();
PCB *process = thread->Parent;
thread->State = TaskState::Sleeping;
thread->SetState(TaskState::Sleeping);
{
SmartLock(TaskingLock);
if (process->Threads.size() == 1)
process->State = TaskState::Sleeping;
process->SetState(TaskState::Sleeping);
thread->Info.SleepUntil =
TimeManager->CalculateTarget(Milliseconds,
@ -281,28 +273,25 @@ namespace Tasking
void Task::SignalShutdown()
{
fixme("SignalShutdown()");
// TODO: Implement this
// This should hang until all processes are terminated
}
debug("Current process is %s(%d) and thread is %s(%d)",
GetCurrentProcess()->Name, GetCurrentProcess()->ID,
GetCurrentThread()->Name, GetCurrentThread()->ID);
void Task::CleanupProcessesThread()
{
thisThread->Rename("Tasking Cleanup");
while (true)
foreach (auto pcb in ProcessList)
{
this->Sleep(2000);
{
SmartLock(TaskingLock);
foreach (auto Process in ProcessList)
{
if (unlikely(InvalidPCB(Process)))
continue;
if (pcb->State == TaskState::Terminated ||
pcb->State == TaskState::Zombie)
continue;
RemoveProcess(Process);
}
}
if (pcb == GetCurrentProcess())
continue;
debug("Sending SIGTERM to process \"%s\"(%d)",
pcb->Name, pcb->ID);
pcb->SendSignal(SIGTERM);
}
// TODO: wait for processes to terminate with timeout.
}
__no_sanitize("undefined")
@ -325,16 +314,55 @@ namespace Tasking
const char *Name,
TaskExecutionMode ExecutionMode,
void *Image,
bool DoNotCreatePageTable,
bool UseKernelPageTable,
uint16_t UserID,
uint16_t GroupID)
{
SmartLock(TaskingLock);
return new PCB(this, Parent, Name, ExecutionMode,
Image, DoNotCreatePageTable,
Image, UseKernelPageTable,
UserID, GroupID);
}
void Task::StartScheduler()
{
#if defined(a86)
if (Interrupts::apicTimer[0])
{
((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100);
/* FIXME: The kernel is not ready for multi-core tasking. */
return;
APIC::InterruptCommandRegister icr{};
bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC;
if (likely(x2APIC))
{
icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
icr.x2.MT = APIC::Fixed;
icr.x2.L = APIC::Assert;
icr.x2.DES = 0xFFFFFFFF; /* Broadcast IPI to all local APICs. */
((APIC::APIC *)Interrupts::apic[0])->ICR(icr);
}
else
{
icr.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
icr.MT = APIC::Fixed;
icr.L = APIC::Assert;
for (int i = 0; i < SMP::CPUCores; i++)
{
icr.DES = uint8_t(i);
((APIC::APIC *)Interrupts::apic[i])->ICR(icr);
}
}
}
#elif defined(aa64)
#endif
debug("Tasking Started");
}
Task::Task(const IP EntryPoint) : Interrupts::Handler(16) /* IRQ16 */
{
#if defined(a64)
@ -343,8 +371,8 @@ namespace Tasking
#elif defined(a32)
#elif defined(aa64)
#endif
KPrint("Starting Tasking With Instruction Pointer: %p (\e666666%s\eCCCCCC)",
EntryPoint, KernelSymbolTable->GetSymbolFromAddress(EntryPoint));
KPrint("Starting tasking instance %#lx with ip: %p (\e666666%s\eCCCCCC)",
this, EntryPoint, KernelSymbolTable->GetSymbol(EntryPoint));
#if defined(a64)
TaskArchitecture Arch = TaskArchitecture::x64;
@ -354,14 +382,17 @@ namespace Tasking
TaskArchitecture Arch = TaskArchitecture::ARM64;
#endif
PCB *kproc = CreateProcess(nullptr, "Kernel", TaskExecutionMode::Kernel);
kproc->ELFSymbolTable = KernelSymbolTable;
TCB *kthrd = CreateThread(kproc, EntryPoint,
KernelProcess = CreateProcess(nullptr, "Kernel",
TaskExecutionMode::Kernel,
nullptr, true);
KernelProcess->PageTable = KernelPageTable;
KernelProcess->ELFSymbolTable = KernelSymbolTable;
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
nullptr, nullptr,
std::vector<AuxiliaryVector>(), Arch);
kthrd->Rename("Main Thread");
debug("Created Kernel Process: %s and Thread: %s",
kproc->Name, kthrd->Name);
KernelProcess->Name, kthrd->Name);
bool MONITORSupported = false;
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
@ -388,37 +419,25 @@ namespace Tasking
CPU::Interrupts(CPU::Enable);
}
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskExecutionMode::Kernel);
IdleProcess = CreateProcess(nullptr, (char *)"Idle",
TaskExecutionMode::Kernel,
nullptr, true);
IdleProcess->ELFSymbolTable = KernelSymbolTable;
for (int i = 0; i < SMP::CPUCores; i++)
{
IdleThread = CreateThread(IdleProcess, IP(IdleProcessLoop));
TCB *thd = CreateThread(IdleProcess, IP(IdleProcessLoop));
char IdleName[16];
sprintf(IdleName, "Idle Thread %d", i);
IdleThread->Rename(IdleName);
IdleThread->SetPriority(Idle);
thd->Rename(IdleName);
thd->SetPriority(Idle);
for (int j = 0; j < MAX_CPU; j++)
IdleThread->Info.Affinity[j] = false;
IdleThread->Info.Affinity[i] = true;
}
debug("Tasking Started");
#if defined(a86)
if (Interrupts::apicTimer[0])
{
((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100);
thd->Info.Affinity[j] = false;
thd->Info.Affinity[i] = true;
/* FIXME: The kernel is not ready for multi-core tasking. */
// for (int i = 1; i < SMP::CPUCores; i++)
// {
// ((APIC::Timer *)Interrupts::apicTimer[i])->OneShot(CPU::x86::IRQ16, 100);
// APIC::InterruptCommandRegisterLow icr;
// icr.Vector = CPU::x86::IRQ16;
// icr.Level = APIC::APICLevel::Assert;
// ((APIC::APIC *)Interrupts::apic[0])->IPI(i, icr);
// }
if (unlikely(i == 0))
IdleThread = thd;
}
#elif defined(aa64)
#endif
debug("Tasking is ready");
}
Task::~Task()
@ -430,8 +449,7 @@ namespace Tasking
{
foreach (TCB *Thread in Process->Threads)
{
if (Thread == GetCurrentCPU()->CurrentThread.load() ||
Thread == CleanupThread)
if (Thread == GetCurrentCPU()->CurrentThread.load())
continue;
this->KillThread(Thread, KILL_SCHEDULER_DESTRUCTION);
}
@ -442,20 +460,38 @@ namespace Tasking
}
}
debug("Waiting for processes to terminate");
uint64_t timeout = TimeManager->CalculateTarget(20, Time::Units::Seconds);
while (ProcessList.size() > 0)
{
trace("Waiting for %d processes to terminate", ProcessList.size());
int NotTerminated = 0;
foreach (PCB *Process in ProcessList)
{
debug("Process %s(%d) is still running (or waiting to be removed status %#lx)",
trace("Process %s(%d) is still running (or waiting to be removed state %#lx)",
Process->Name, Process->ID, Process->State);
if (Process->State == TaskState::Terminated)
{
debug("Process %s(%d) terminated", Process->Name, Process->ID);
continue;
}
NotTerminated++;
}
if (NotTerminated == 1)
break;
this->Sleep(1000);
debug("Current working process is %s(%d)",
GetCurrentProcess()->Name, GetCurrentProcess()->ID);
if (TimeManager->GetCounter() > timeout)
{
error("Timeout waiting for processes to terminate");
break;
}
TaskingScheduler_OneShot(100);
}

View File

@ -51,7 +51,7 @@ void ThreadDoExit()
{
CPUData *CPUData = GetCurrentCPU();
Tasking::TCB *CurrentThread = CPUData->CurrentThread.load();
CurrentThread->State = Tasking::TaskState::Terminated;
CurrentThread->SetState(Tasking::Terminated);
debug("\"%s\"(%d) exited with code: %#lx",
CurrentThread->Name,
@ -62,6 +62,25 @@ void ThreadDoExit()
namespace Tasking
{
int TCB::SendSignal(int sig)
{
return this->Parent->Signals->SendSignal(sig);
}
void TCB::SetState(TaskState state)
{
this->State.store(state);
if (this->Parent->Threads.size() == 1)
this->Parent->State.store(state);
}
void TCB::SetExitCode(int code)
{
this->ExitCode.store(code);
if (this->Parent->Threads.size() == 1)
this->Parent->ExitCode.store(code);
}
void TCB::Rename(const char *name)
{
assert(name != nullptr);
@ -98,6 +117,9 @@ namespace Tasking
this->Name, Critical ? "true" : "false");
Security.IsCritical = Critical;
if (this->Parent->Threads.size() == 1)
this->Parent->Security.IsCritical = Critical;
}
void TCB::SetDebugMode(bool Enable)
@ -106,6 +128,9 @@ namespace Tasking
this->Name, Enable ? "true" : "false");
Security.IsDebugEnabled = Enable;
if (this->Parent->Threads.size() == 1)
this->Parent->Security.IsDebugEnabled = Enable;
}
void TCB::SetKernelDebugMode(bool Enable)
@ -114,6 +139,9 @@ namespace Tasking
this->Name, Enable ? "true" : "false");
Security.IsKernelDebugEnabled = Enable;
if (this->Parent->Threads.size() == 1)
this->Parent->Security.IsKernelDebugEnabled = Enable;
}
size_t TCB::GetSize()
@ -171,13 +199,13 @@ namespace Tasking
/* https://articles.manugarg.com/aboutelfauxiliaryvectors.html */
/* https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf#figure.3.9 */
// rsp is the top of the stack
/* rsp is the top of the stack */
char *Stack = (char *)this->Stack->GetStackPhysicalTop();
// Temporary stack pointer for strings
/* Temporary stack pointer for strings */
char *StackStrings = (char *)Stack;
char *StackStringsVirtual = (char *)this->Stack->GetStackTop();
// Store string pointers for later
/* Store string pointers for later */
uintptr_t *ArgvStrings = nullptr;
uintptr_t *EnvpStrings = nullptr;
if (ArgvSize > 0)
@ -187,63 +215,66 @@ namespace Tasking
for (size_t i = 0; i < ArgvSize; i++)
{
// Subtract the length of the string and the null terminator
/* Subtract the length of the string and the null terminator */
StackStrings -= strlen(argv[i]) + 1;
StackStringsVirtual -= strlen(argv[i]) + 1;
// Store the pointer to the string
/* Store the pointer to the string */
ArgvStrings[i] = (uintptr_t)StackStringsVirtual;
// Copy the string to the stack
/* Copy the string to the stack */
strcpy(StackStrings, argv[i]);
debug("argv[%d]: %s", i, argv[i]);
}
for (size_t i = 0; i < EnvpSize; i++)
{
// Subtract the length of the string and the null terminator
/* Subtract the length of the string and the null terminator */
StackStrings -= strlen(envp[i]) + 1;
StackStringsVirtual -= strlen(envp[i]) + 1;
// Store the pointer to the string
/* Store the pointer to the string */
EnvpStrings[i] = (uintptr_t)StackStringsVirtual;
// Copy the string to the stack
/* Copy the string to the stack */
strcpy(StackStrings, envp[i]);
debug("envp[%d]: %s", i, envp[i]);
}
// Align the stack to 16 bytes
/* Align the stack to 16 bytes */
StackStrings -= (uintptr_t)StackStrings & 0xF;
// Set "Stack" to the new stack pointer
/* Set "Stack" to the new stack pointer */
Stack = (char *)StackStrings;
// If argv and envp sizes are odd then we need to align the stack
/* If argv and envp sizes are odd then we need to align the stack */
Stack -= (ArgvSize + EnvpSize) % 2;
debug("odd align: %#lx | %#lx -> %#lx",
(ArgvSize + EnvpSize) % 2,
StackStrings, Stack);
// We need 8 bit pointers for the stack from here
/* We need 8 bit pointers for the stack from here */
uintptr_t *Stack64 = (uintptr_t *)Stack;
assert(Stack64 != nullptr);
// Store the null terminator
Stack64--;
*Stack64 = AT_NULL;
/* Store the null terminator */
StackPush(Stack64, uintptr_t, AT_NULL);
// auxv_array is initialized with auxv elements. If the array is empty then we add a null terminator
/* auxv_array is initialized with auxv elements.
If the array is empty then we add a null terminator */
std::vector<AuxiliaryVector> auxv_array = auxv;
if (auxv_array.size() == 0)
auxv_array.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
// Store auxillary vector
/* Store auxillary vector */
foreach (AuxiliaryVector av in auxv_array)
{
// Subtract the size of the auxillary vector
/* Subtract the size of the auxillary vector */
Stack64 -= sizeof(Elf_auxv_t) / sizeof(uintptr_t);
// Store the auxillary vector
/* Store the auxillary vector */
POKE(Elf_auxv_t, Stack64) = av.archaux;
// TODO: Store strings to the stack
/* TODO: Store strings to the stack */
}
// Store the null terminator
Stack64--;
*Stack64 = AT_NULL;
/* Store the null terminator */
StackPush(Stack64, uintptr_t, AT_NULL);
// Store EnvpStrings[] to the stack
Stack64 -= EnvpSize; // (1 Stack64 = 8 bits; Stack64 = 8 * EnvpSize)
/* Store EnvpStrings[] to the stack */
Stack64 -= EnvpSize; /* (1 Stack64 = 8 bits; Stack64 = 8 * EnvpSize) */
for (size_t i = 0; i < EnvpSize; i++)
{
*(Stack64 + i) = (uintptr_t)EnvpStrings[i];
@ -251,12 +282,11 @@ namespace Tasking
i, EnvpStrings[i]);
}
// Store the null terminator
Stack64--;
*Stack64 = AT_NULL;
/* Store the null terminator */
StackPush(Stack64, uintptr_t, AT_NULL);
// Store ArgvStrings[] to the stack
Stack64 -= ArgvSize; // (1 Stack64 = 8 bits; Stack64 = 8 * ArgvSize)
/* Store ArgvStrings[] to the stack */
Stack64 -= ArgvSize; /* (1 Stack64 = 8 bits; Stack64 = 8 * ArgvSize) */
for (size_t i = 0; i < ArgvSize; i++)
{
*(Stack64 + i) = (uintptr_t)ArgvStrings[i];
@ -264,11 +294,10 @@ namespace Tasking
i, ArgvStrings[i]);
}
// Store the argc
Stack64--;
*Stack64 = ArgvSize;
/* Store the argc */
StackPush(Stack64, uintptr_t, ArgvSize);
// Set "Stack" to the new stack pointer
/* Set "Stack" to the new stack pointer */
Stack = (char *)Stack64;
/* We need the virtual address but because we are in the kernel we can't use the process page table.
@ -276,8 +305,10 @@ namespace Tasking
uintptr_t SubtractStack = (uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)Stack;
debug("SubtractStack: %#lx", SubtractStack);
// Set the stack pointer to the new stack
/* Set the stack pointer to the new stack */
uintptr_t StackPointerReg = ((uintptr_t)this->Stack->GetStackTop() - SubtractStack);
// assert(!(StackPointerReg & 0xF));
#if defined(a64)
this->Registers.rsp = StackPointerReg;
#elif defined(a32)
@ -292,7 +323,9 @@ namespace Tasking
delete[] EnvpStrings;
#ifdef DEBUG
DumpData("Stack Data", (void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack), SubtractStack);
DumpData("Stack Data",
(void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack),
SubtractStack);
#endif
#if defined(a64)
@ -327,6 +360,48 @@ namespace Tasking
fixme("Not implemented");
}
void TCB::SetupThreadLocalStorage()
{
if (Parent->TLS.pBase == 0x0)
return;
this->TLS = Parent->TLS;
debug("msz: %ld fsz: %ld",
this->TLS.Size, this->TLS.fSize);
// size_t pOffset = this->TLS.vBase - std::tolower(this->TLS.vBase);
size_t tlsFullSize = sizeof(uintptr_t) + this->TLS.Size;
/* 2 guard pages */
size_t tlsPages = 1 + TO_PAGES(tlsFullSize) + 1;
void *opTLS = this->vma->RequestPages(tlsPages);
void *pTLS = (void *)(PAGE_SIZE + uintptr_t(opTLS));
this->TLS.pBase = uintptr_t(pTLS);
memcpy(pTLS, (void *)this->TLS.pBase,
this->TLS.Size);
size_t restBytes = this->TLS.Size - this->TLS.fSize;
if (restBytes)
{
memset((void *)(uintptr_t(pTLS) + this->TLS.Size),
0, restBytes);
}
Memory::Virtual vmm(this->Parent->PageTable);
/* Map guard pages */
vmm.Remap((void *)(uintptr_t(pTLS) - PAGE_SIZE), opTLS, Memory::P);
vmm.Remap((void *)(uintptr_t(pTLS) + this->TLS.Size), opTLS, Memory::P);
/* Map TLS */
vmm.Map(pTLS, pTLS, this->TLS.Size, Memory::RW | Memory::US);
uintptr_t *pTLSPointer = (uintptr_t *)this->TLS.pBase + this->TLS.Size;
*pTLSPointer = this->TLS.pBase + this->TLS.Size;
this->GSBase = r_cst(uintptr_t, pTLSPointer);
this->FSBase = r_cst(uintptr_t, pTLSPointer);
}
TCB::TCB(Task *ctx, PCB *Parent, IP EntryPoint,
const char **argv, const char **envp,
const std::vector<AuxiliaryVector> &auxv,
@ -363,9 +438,9 @@ namespace Tasking
this->ExitCode = KILL_CRASH;
if (ThreadNotReady)
this->State = TaskState::Waiting;
this->SetState(Waiting);
else
this->State = TaskState::Ready;
this->SetState(Ready);
this->vma = new Memory::VirtualMemoryArea(this->Parent->PageTable);
@ -467,11 +542,19 @@ namespace Tasking
assert(false);
}
SetupThreadLocalStorage();
this->Info.Architecture = Architecture;
this->Info.Compatibility = Compatibility;
this->Security.ExecutionMode =
this->Parent->Security.ExecutionMode;
if (this->Parent->Threads.size() == 0)
{
this->Parent->Info.Architecture = this->Info.Architecture;
this->Parent->Info.Compatibility = this->Info.Compatibility;
}
// TODO: Is really a good idea to use the FPU in kernel mode?
this->FPU.mxcsr = 0b0001111110000000;
this->FPU.mxcsrmask = 0b1111111110111111;
@ -519,7 +602,7 @@ namespace Tasking
this->Parent->State == Waiting &&
ThreadNotReady == false)
{
this->Parent->State = Ready;
this->Parent->SetState(Ready);
debug("Setting process \"%s\"(%d) to ready",
this->Parent->Name, this->Parent->ID);
}
@ -531,7 +614,7 @@ namespace Tasking
/* Remove us from the process list so we
don't get scheduled anymore */
std::vector<Tasking::TCB *> &Threads = this->Parent->Threads;
std::list<Tasking::TCB *> &Threads = this->Parent->Threads;
Threads.erase(std::find(Threads.begin(),
Threads.end(),
this));
@ -544,5 +627,8 @@ namespace Tasking
/* Free Name */
delete[] this->Name;
debug("Thread \"%s\"(%d) destroyed",
this->Name, this->ID);
}
}