/* 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 . */ #ifndef __FENNIX_KERNEL_TASKING_H__ #define __FENNIX_KERNEL_TASKING_H__ #include #include #include #include #include #include #include #include #include #include namespace Tasking { typedef unsigned long IP; typedef __UINTPTR_TYPE__ IPOffset; typedef unsigned long UPID; typedef unsigned long UTID; typedef __UINTPTR_TYPE__ Token; enum TaskArchitecture { UnknownArchitecture, x32, x64, ARM32, ARM64 }; enum TaskCompatibility { UnknownPlatform, Native, Linux, Windows }; enum TaskTrustLevel { UnknownElevation, Kernel, System, User }; enum TaskStatus { UnknownStatus, Ready, Running, Sleeping, Waiting, Stopped, Terminated }; enum TaskPriority { UnknownPriority = 0, Idle = 1, Low = 2, Normal = 5, High = 8, Critical = 10 }; struct TaskSecurity { TaskTrustLevel TrustLevel; Token UniqueToken; bool IsCritical; bool IsDebugEnabled; bool IsKernelDebugEnabled; }; struct TaskInfo { uint64_t OldUserTime = 0; uint64_t OldKernelTime = 0; uint64_t SleepUntil = 0; uint64_t KernelTime = 0, UserTime = 0, SpawnTime = 0, LastUpdateTime = 0; uint64_t Year, Month, Day, Hour, Minute, Second; bool Affinity[256]; // MAX_CPU TaskPriority Priority; TaskArchitecture Architecture; TaskCompatibility Compatibility; }; struct TCB { UTID ID; char Name[256]; struct PCB *Parent; IP EntryPoint; IPOffset Offset; int ExitCode; Memory::StackGuard *Stack; Memory::MemMgr *Memory; TaskStatus Status; #if defined(a64) CPU::x64::TrapFrame Registers; uint64_t GSBase, FSBase; #elif defined(a32) CPU::x32::TrapFrame Registers; // TODO uint64_t GSBase, FSBase; #elif defined(aa64) uint64_t Registers; // TODO #endif uintptr_t IPHistory[128]; TaskSecurity Security; TaskInfo Info; CPU::x64::FXState *FPU; void Rename(const char *name) { CriticalSection cs; if (strlen(name) > 256 || strlen(name) == 0) { debug("Invalid thread name"); return; } trace("Renaming thread %s to %s", Name, name); strncpy(Name, name, 256); } void SetPriority(TaskPriority priority) { CriticalSection cs; trace("Setting priority of thread %s to %d", Name, priority); Info.Priority = priority; } int GetExitCode() { return ExitCode; } void SetCritical(bool Critical) { CriticalSection cs; trace("Setting criticality of thread %s to %s", Name, Critical ? "true" : "false"); Security.IsCritical = Critical; } void SetDebugMode(bool Enable) { CriticalSection cs; trace("Setting debug mode of thread %s to %s", Name, Enable ? "true" : "false"); Security.IsDebugEnabled = Enable; } void SetKernelDebugMode(bool Enable) { CriticalSection cs; trace("Setting kernel debug mode of thread %s to %s", Name, Enable ? "true" : "false"); Security.IsKernelDebugEnabled = Enable; } }; struct PCB { UPID ID; char Name[256]; PCB *Parent; int ExitCode; TaskStatus Status; TaskSecurity Security; TaskInfo Info; std::vector Threads; std::vector Children; InterProcessCommunication::IPC *IPC; Memory::PageTable *PageTable; SymbolResolver::Symbols *ELFSymbolTable; VirtualFileSystem::Node *ProcessDirectory; VirtualFileSystem::Node *memDirectory; }; /** @brief Token Trust Level */ enum TTL { UnknownTrustLevel = 0b0001, Untrusted = 0b0010, Trusted = 0b0100, TrustedByKernel = 0b1000, FullTrust = Trusted | TrustedByKernel }; class Security { private: struct TokenData { Token token; int TrustLevel; uint64_t OwnerID; bool Process; }; std::vector Tokens; public: Token CreateToken(); bool TrustToken(Token token, TTL TrustLevel); bool AddTrustLevel(Token token, TTL TrustLevel); bool RemoveTrustLevel(Token token, TTL TrustLevel); bool UntrustToken(Token token); bool DestroyToken(Token token); bool IsTokenTrusted(Token token, TTL TrustLevel); bool IsTokenTrusted(Token token, int TrustLevel); int GetTokenTrustLevel(Token token); Security(); ~Security(); }; class Task : public Interrupts::Handler { private: Security SecurityManager; UPID NextPID = 0; UTID NextTID = 0; std::vector ProcessList; PCB *IdleProcess = nullptr; TCB *IdleThread = nullptr; TCB *CleanupThread = nullptr; std::atomic_uint64_t SchedulerTicks = 0; std::atomic_uint64_t LastTaskTicks = 0; bool StopScheduler = false; bool InvalidPCB(PCB *pcb); bool InvalidTCB(TCB *tcb); void RemoveThread(TCB *tcb); void RemoveProcess(PCB *pcb); void UpdateUsage(TaskInfo *Info, TaskSecurity *Security, int Core); bool FindNewProcess(void *CPUDataPointer); bool GetNextAvailableThread(void *CPUDataPointer); bool GetNextAvailableProcess(void *CPUDataPointer); bool SchedulerSearchProcessThread(void *CPUDataPointer); void UpdateProcessStatus(); void WakeUpThreads(); #if defined(a64) void Schedule(CPU::x64::TrapFrame *Frame); void OnInterruptReceived(CPU::x64::TrapFrame *Frame); #elif defined(a32) void Schedule(void *Frame); void OnInterruptReceived(CPU::x32::TrapFrame *Frame); #elif defined(aa64) void Schedule(CPU::aarch64::TrapFrame *Frame); void OnInterruptReceived(CPU::aarch64::TrapFrame *Frame); #endif public: void SetCleanupThread(TCB *Thread) { CleanupThread = Thread; } uint64_t GetSchedulerTicks() { return SchedulerTicks.load(); } uint64_t GetLastTaskTicks() { return LastTaskTicks.load(); } std::vector GetProcessList() { return ProcessList; } Security *GetSecurityManager() { return &SecurityManager; } void CleanupProcessesThread(); void Panic() { StopScheduler = true; } void Schedule(); void SignalShutdown(); void RevertProcessCreation(PCB *Process); void RevertThreadCreation(TCB *Thread); void KillThread(TCB *tcb, int Code) { tcb->Status = TaskStatus::Terminated; tcb->ExitCode = Code; } void KillProcess(PCB *pcb, int Code) { pcb->Status = TaskStatus::Terminated; pcb->ExitCode = Code; } /** * @brief Get the Current Process object * @return PCB* */ PCB *GetCurrentProcess(); /** * @brief Get the Current Thread object * @return TCB* */ TCB *GetCurrentThread(); PCB *GetProcessByID(UPID ID); TCB *GetThreadByID(UTID ID); /** @brief Wait for process to terminate */ void WaitForProcess(PCB *pcb); /** @brief Wait for thread to terminate */ void WaitForThread(TCB *tcb); void WaitForProcessStatus(PCB *pcb, TaskStatus Status); void WaitForThreadStatus(TCB *tcb, TaskStatus Status); /** * @brief Sleep for a given amount of milliseconds * * @param Milliseconds Amount of milliseconds to sleep */ void Sleep(uint64_t Milliseconds); PCB *CreateProcess(PCB *Parent, const char *Name, TaskTrustLevel TrustLevel, void *Image = nullptr, bool DoNotCreatePageTable = false); TCB *CreateThread(PCB *Parent, IP EntryPoint, const char **argv = nullptr, const char **envp = nullptr, const std::vector &auxv = std::vector(), IPOffset Offset = 0, TaskArchitecture Architecture = TaskArchitecture::x64, TaskCompatibility Compatibility = TaskCompatibility::Native, bool ThreadNotReady = false); Task(const IP EntryPoint); ~Task(); }; } #define PEXIT(Code) TaskManager->GetCurrentProcess()->ExitCode = Code #define TEXIT(Code) TaskManager->GetCurrentThread()->ExitCode = Code extern "C" void TaskingScheduler_OneShot(int TimeSlice); #endif // !__FENNIX_KERNEL_TASKING_H__