From c4870d08fa4bfb2613bf22a0b7cf306b388f58a4 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 29 Mar 2025 05:03:14 +0100 Subject: ddk: refactor: reorganize kit into a standard kernel kit. sched: refactor: refactor scheduler file names, for future additions. xcoff: refactor: document and improve XCOFF for NeFS (regarding Ne's FW) codemgr: refactor: make a difference between kernel and user processes. refactor: document project overall. Signed-off-by: Amlal El Mahrouss --- dev/kernel/src/BinaryMutex.cc | 2 +- dev/kernel/src/CodeMgr.cc | 4 +- dev/kernel/src/FS/HeFS.cc | 2 +- dev/kernel/src/FS/NeFS.cc | 2 +- dev/kernel/src/HardwareThreadScheduler.cc | 2 +- dev/kernel/src/IDylibObject.cc | 2 +- dev/kernel/src/IPEFDylibObject.cc | 2 +- dev/kernel/src/Network/IPCAddr.cc | 2 +- dev/kernel/src/Network/IPCMsg.cc | 2 +- dev/kernel/src/PEFCodeMgr.cc | 4 +- dev/kernel/src/ProcessScheduler.cc | 626 ++++++++++++++++++++++++++++++ dev/kernel/src/ProcessTeam.cc | 59 +++ dev/kernel/src/ThreadLocalStorage.cc | 2 +- dev/kernel/src/UserProcessScheduler.cc | 626 ------------------------------ dev/kernel/src/UserProcessTeam.cc | 59 --- 15 files changed, 698 insertions(+), 698 deletions(-) create mode 100644 dev/kernel/src/ProcessScheduler.cc create mode 100644 dev/kernel/src/ProcessTeam.cc delete mode 100644 dev/kernel/src/UserProcessScheduler.cc delete mode 100644 dev/kernel/src/UserProcessTeam.cc (limited to 'dev/kernel/src') diff --git a/dev/kernel/src/BinaryMutex.cc b/dev/kernel/src/BinaryMutex.cc index 6426e5df..112bdbc7 100644 --- a/dev/kernel/src/BinaryMutex.cc +++ b/dev/kernel/src/BinaryMutex.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -#include +#include #include namespace Kernel diff --git a/dev/kernel/src/CodeMgr.cc b/dev/kernel/src/CodeMgr.cc index 37c5b726..407c9775 100644 --- a/dev/kernel/src/CodeMgr.cc +++ b/dev/kernel/src/CodeMgr.cc @@ -6,7 +6,7 @@ #include #include -#include +#include namespace Kernel { @@ -17,7 +17,7 @@ namespace Kernel /// @return if the process was started or not. /***********************************************************************************/ - ProcessID rtl_create_process(rtl_main_kind main, const Char* process_name) noexcept + ProcessID rtl_create_user_process(rtl_main_kind main, const Char* process_name) noexcept { if (!process_name || *process_name == 0) diff --git a/dev/kernel/src/FS/HeFS.cc b/dev/kernel/src/FS/HeFS.cc index b6f1bede..3d6c5ec4 100644 --- a/dev/kernel/src/FS/HeFS.cc +++ b/dev/kernel/src/FS/HeFS.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #endif // ifdef __FSKIT_INCLUDES_HeFS__ diff --git a/dev/kernel/src/FS/NeFS.cc b/dev/kernel/src/FS/NeFS.cc index 2e7cfbe7..0490b39c 100644 --- a/dev/kernel/src/FS/NeFS.cc +++ b/dev/kernel/src/FS/NeFS.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/dev/kernel/src/HardwareThreadScheduler.cc b/dev/kernel/src/HardwareThreadScheduler.cc index 1aa990ac..9a2762bc 100644 --- a/dev/kernel/src/HardwareThreadScheduler.cc +++ b/dev/kernel/src/HardwareThreadScheduler.cc @@ -5,7 +5,7 @@ ------------------------------------------- */ #include -#include +#include #include #include diff --git a/dev/kernel/src/IDylibObject.cc b/dev/kernel/src/IDylibObject.cc index c760fe57..7fab3595 100644 --- a/dev/kernel/src/IDylibObject.cc +++ b/dev/kernel/src/IDylibObject.cc @@ -10,6 +10,6 @@ #include #include -#include +#include using namespace Kernel; diff --git a/dev/kernel/src/IPEFDylibObject.cc b/dev/kernel/src/IPEFDylibObject.cc index 29fe578e..49709bc1 100644 --- a/dev/kernel/src/IPEFDylibObject.cc +++ b/dev/kernel/src/IPEFDylibObject.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/dev/kernel/src/Network/IPCAddr.cc b/dev/kernel/src/Network/IPCAddr.cc index 11466c7e..ae3f8d77 100644 --- a/dev/kernel/src/Network/IPCAddr.cc +++ b/dev/kernel/src/Network/IPCAddr.cc @@ -6,7 +6,7 @@ #include #include -#include +#include namespace Kernel { diff --git a/dev/kernel/src/Network/IPCMsg.cc b/dev/kernel/src/Network/IPCMsg.cc index 288cfb6d..ee089176 100644 --- a/dev/kernel/src/Network/IPCMsg.cc +++ b/dev/kernel/src/Network/IPCMsg.cc @@ -6,7 +6,7 @@ #include #include -#include +#include namespace Kernel { diff --git a/dev/kernel/src/PEFCodeMgr.cc b/dev/kernel/src/PEFCodeMgr.cc index b8139439..d85fdba8 100644 --- a/dev/kernel/src/PEFCodeMgr.cc +++ b/dev/kernel/src/PEFCodeMgr.cc @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -246,7 +246,7 @@ namespace Kernel namespace Utils { - ProcessID rtl_create_process(PEFLoader& exec, const Int32& process_kind) noexcept + ProcessID rtl_create_user_process(PEFLoader& exec, const Int32& process_kind) noexcept { auto errOrStart = exec.FindStart(); diff --git a/dev/kernel/src/ProcessScheduler.cc b/dev/kernel/src/ProcessScheduler.cc new file mode 100644 index 00000000..45a82d54 --- /dev/null +++ b/dev/kernel/src/ProcessScheduler.cc @@ -0,0 +1,626 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + FILE: UserProcessScheduler.cc + PURPOSE: Low level/Ring-3 Process scheduler. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessScheduler.cc +/// @brief Low level/Ring-3 process scheduler. +/***********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +///! BUGS: 0 + +namespace Kernel +{ + /***********************************************************************************/ + /// @brief Exit Code global variable. + /***********************************************************************************/ + + STATIC UInt32 kLastExitCode = 0U; + + /***********************************************************************************/ + /// @brief External reference of the thread scheduler. + /***********************************************************************************/ + + STATIC UserProcessScheduler kProcessScheduler; + + UserProcess::UserProcess() = default; + UserProcess::~UserProcess() = default; + + /// @brief Gets the last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + + const UInt32& sched_get_exit_code(void) noexcept + { + return kLastExitCode; + } + + /***********************************************************************************/ + /// @brief Crashes the current process. + /***********************************************************************************/ + + Void UserProcess::Crash() + { + if (this->Status != ProcessStatusKind::kRunning) + return; + + kout << this->Name << ": crashed, error id: " << number(kErrorProcessFault) << kendl; + this->Exit(kErrorProcessFault); + } + + /***********************************************************************************/ + /// @brief boolean operator, check status. + /***********************************************************************************/ + + UserProcess::operator bool() + { + return this->Status == ProcessStatusKind::kRunning; + } + + /***********************************************************************************/ + /// @brief Gets the local last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + /***********************************************************************************/ + + const UInt32& UserProcess::GetExitCode() noexcept + { + return this->fLastExitCode; + } + + /***********************************************************************************/ + /// @brief Error code variable getter. + /***********************************************************************************/ + + Int32& UserProcess::GetLocalCode() noexcept + { + return this->fLocalCode; + } + + /***********************************************************************************/ + /// @brief Wakes process header. + /// @param should_wakeup if the program shall wakeup or not. + /***********************************************************************************/ + + Void UserProcess::Wake(const Bool should_wakeup) + { + this->Status = + should_wakeup ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen; + } + + /***********************************************************************************/ + /** @brief Allocate pointer to track list. */ + /***********************************************************************************/ + + ErrorOr UserProcess::New(const SizeT& sz, const SizeT& pad_amount) + { +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + auto vm_register = hal_read_cr3(); + hal_write_cr3(this->VMRegister); + + auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); + + hal_write_cr3(vm_register); +#else + auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); +#endif + + if (!this->ProcessMemoryHeap) + { + this->ProcessMemoryHeap = new ProcessMemoryHeapList(); + + this->ProcessMemoryHeap->MemoryEntryPad = pad_amount; + this->ProcessMemoryHeap->MemoryEntrySize = sz; + + this->ProcessMemoryHeap->MemoryEntry = ptr; + + this->ProcessMemoryHeap->MemoryPrev = nullptr; + this->ProcessMemoryHeap->MemoryNext = nullptr; + } + else + { + ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; + ProcessMemoryHeapList* prev_entry = nullptr; + + while (entry) + { + if (entry->MemoryEntry == nullptr) + break; // chose to break here, when we get an already allocated memory entry for our needs. + + prev_entry = entry; + entry = entry->MemoryNext; + } + + entry->MemoryNext = new ProcessMemoryHeapList(); + entry->MemoryNext->MemoryEntry = ptr; + + entry->MemoryNext->MemoryPrev = entry; + entry->MemoryNext->MemoryNext = nullptr; + } + + this->UsedMemory += sz; + + return ErrorOr(ptr); + } + + /***********************************************************************************/ + /// @brief Gets the name of the current process. + /***********************************************************************************/ + + const Char* UserProcess::GetName() noexcept + { + return this->Name; + } + + /***********************************************************************************/ + /// @brief Gets the owner of the process. + /***********************************************************************************/ + + const User* UserProcess::GetOwner() noexcept + { + return this->Owner; + } + + /// @brief UserProcess status getter. + const ProcessStatusKind& UserProcess::GetStatus() noexcept + { + return this->Status; + } + + /***********************************************************************************/ + /** + @brief Affinity is the time slot allowed for the process. + */ + /***********************************************************************************/ + + const AffinityKind& UserProcess::GetAffinity() noexcept + { + return this->Affinity; + } + + /***********************************************************************************/ + /** + @brief Exit process method. + @param exit_code The process's exit code. + */ + /***********************************************************************************/ + + Void UserProcess::Exit(const Int32& exit_code) + { + this->Status = exit_code > 0 ? ProcessStatusKind::kKilled : ProcessStatusKind::kFrozen; + this->fLastExitCode = exit_code; + + kLastExitCode = exit_code; + + auto memory_heap_list = this->ProcessMemoryHeap; + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + auto pd = hal_read_cr3(); + hal_write_cr3(this->VMRegister); +#endif + + // Deleting memory lists. Make sure to free all of them. + while (memory_heap_list) + { + if (memory_heap_list->MemoryEntry) + { + MUST_PASS(mm_delete_heap(memory_heap_list->MemoryEntry)); + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + hal_write_cr3(pd); +#endif + + auto next = memory_heap_list->MemoryNext; + + mm_delete_heap(memory_heap_list); + + memory_heap_list = next; + } + + //! Free the memory's page directory. + HAL::mm_free_bitmap(this->VMRegister); + + //! Delete image if not done already. + if (this->Image.fCode && mm_is_valid_heap(this->Image.fCode)) + mm_delete_heap(this->Image.fCode); + + //! Delete blob too. + if (this->Image.fBlob && mm_is_valid_heap(this->Image.fBlob)) + mm_delete_heap(this->Image.fBlob); + + //! Delete stack frame. + if (this->StackFrame && mm_is_valid_heap(this->StackFrame)) + mm_delete_heap((VoidPtr)this->StackFrame); + + //! Delete stack reserve. + if (this->StackReserve && mm_is_valid_heap(this->StackReserve)) + mm_delete_heap(reinterpret_cast(this->StackReserve)); + + //! Avoid use after free. + this->Image.fBlob = nullptr; + this->Image.fCode = nullptr; + this->StackFrame = nullptr; + this->StackReserve = nullptr; + + if (this->Kind == kExectuableDylibKind) + { + Bool success = false; + + rtl_fini_dylib(*this, reinterpret_cast(this->DylibDelegate), &success); + + if (!success) + { + ke_panic(RUNTIME_CHECK_PROCESS); + } + + this->DylibDelegate = nullptr; + } + + this->ProcessId = 0UL; + this->Status = ProcessStatusKind::kFinished; + + --this->ProcessParentTeam->mProcessCount; + + delete this; + } + + /***********************************************************************************/ + /// @brief Add process to team. + /// @param process the process *Ref* class. + /// @return the process index inside the team. + /***********************************************************************************/ + + ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr image) + { + ProcessID pid = this->mTeam.mProcessCount; + + if (pid > kSchedProcessLimitPerTeam) + { + return kErrorProcessFault; + } + + ++this->mTeam.mProcessCount; + + UserProcess& process = this->mTeam.mProcessList[pid]; + + process.Image.fCode = code; + process.Image.fBlob = image; + + rt_copy_memory(reinterpret_cast(const_cast(name)), process.Name, rt_string_len(name)); + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + process.VMRegister = new PDE(); + + if (!process.VMRegister) + { + process.Crash(); + return kErrorProcessFault; + } + + UInt32 flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.VMRegister, process.VMRegister, flags); +#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.StackFrame = new HAL::StackFrame(); + + if (!process.StackFrame) + { + process.Crash(); + return kErrorProcessFault; + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.StackFrame, process.StackFrame, flags); +#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + + // React according to process kind. + switch (process.Kind) + { + case UserProcess::kExectuableDylibKind: { + process.DylibDelegate = rtl_init_dylib(process); + MUST_PASS(process.DylibDelegate); + } + default: { + kout << "Unknown process kind: " << hex_number(process.Kind) << kendl; + break; + } + } + + process.StackReserve = new UInt8[process.StackSize]; + rt_set_memory(process.StackReserve, 0, process.StackSize); + + if (!process.StackReserve) + { + process.Crash(); + return kErrorProcessFault; + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.StackReserve, process.StackReserve, flags); +#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.ProcessParentTeam = &mTeam; + + process.ProcessId = pid; + process.Status = ProcessStatusKind::kStarting; + process.PTime = (UIntPtr)AffinityKind::kStandard; + + kout << "PID: " << number(process.ProcessId) << kendl; + kout << "Name: " << process.Name << kendl; + + return pid; + } + + /***********************************************************************************/ + /// @brief Retrieves the singleton of the process scheduler. + /***********************************************************************************/ + + UserProcessScheduler& UserProcessScheduler::The() + { + return kProcessScheduler; + } + + /***********************************************************************************/ + + /// @brief Remove process from the team. + /// @param process_id process slot inside team. + /// @retval true process was removed. + /// @retval false process doesn't exist in team. + + /***********************************************************************************/ + + const Bool UserProcessScheduler::Remove(ProcessID process_id) + { + // check if process is within range. + if (process_id > mTeam.mProcessList.Count()) + return No; + + mTeam.mProcessList[process_id].Exit(0); + + return Yes; + } + + /// @brief Is it a user scheduler? + + const Bool UserProcessScheduler::IsUser() + { + return Yes; + } + + /// @brief Is it a kernel scheduler? + + const Bool UserProcessScheduler::IsKernel() + { + return No; + } + + /// @brief Is it a SMP scheduler? + + const Bool UserProcessScheduler::HasMP() + { + return Yes; + } + + /***********************************************************************************/ + /// @brief Run User scheduler object. + /// @return Process count executed within a team. + /***********************************************************************************/ + + const SizeT UserProcessScheduler::Run() noexcept + { + SizeT process_index = 0UL; //! we store this guy to tell the scheduler how many + //! things we have scheduled. + + if (mTeam.mProcessCount < 1) + { + kout << "UserProcessScheduler::Run(): This team doesn't have any process!\r"; + return 0UL; + } + for (; process_index < mTeam.AsArray().Capacity(); ++process_index) + { + auto& process = mTeam.AsArray()[process_index]; + + //! check if the process needs to be run. + if (UserProcessHelper::CanBeScheduled(process)) + { + // Set current process header. + this->CurrentProcess() = process; + + process.PTime = static_cast(process.Affinity); + + kout << "Switch to: '" << process.Name << "'.\r"; + + // tell helper to find a core to schedule on. + BOOL ret = UserProcessHelper::Switch(process.Image.fCode, &process.StackReserve[process.StackSize - 1], process.StackFrame, + process.ProcessId); + + if (!ret) + { + if (process.Affinity == AffinityKind::kRealTime) + continue; + + kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; + + process.Crash(); + } + } + else + { + --process.PTime; + } + } + + return process_index; + } + + /// @brief Gets the current scheduled team. + /// @return + UserProcessTeam& UserProcessScheduler::CurrentTeam() + { + return mTeam; + } + + /// @internal + + /// @brief Gets current running process. + /// @return + Ref& UserProcessScheduler::CurrentProcess() + { + return mTeam.AsRef(); + } + + /// @brief Current proccess id getter. + /// @return UserProcess ID integer. + ErrorOr UserProcessHelper::TheCurrentPID() + { + if (!kProcessScheduler.CurrentProcess()) + return ErrorOr{kErrorProcessFault}; + + kout << "UserProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; + return ErrorOr{kProcessScheduler.CurrentProcess().Leak().ProcessId}; + } + + /// @brief Check if process can be schedulded. + /// @param process the process reference. + /// @retval true can be schedulded. + /// @retval false cannot be schedulded. + Bool UserProcessHelper::CanBeScheduled(const UserProcess& process) + { + if (process.Status == ProcessStatusKind::kKilled || + process.Status == ProcessStatusKind::kFinished || + process.Status == ProcessStatusKind::kStarting || + process.Status == ProcessStatusKind::kFrozen) + return No; + + if (process.Status == ProcessStatusKind::kInvalid) + return No; + + if (!process.Image.fCode) + return No; + + if (!process.Name[0]) + return No; + + // real time processes shouldn't wait that much. + if (process.Affinity == AffinityKind::kRealTime) + return Yes; + + return process.PTime < 1; + } + + /***********************************************************************************/ + /** + * @brief Start scheduling current AP. + */ + /***********************************************************************************/ + + SizeT UserProcessHelper::StartScheduling() + { + return kProcessScheduler.Run(); + } + + /***********************************************************************************/ + /** + * \brief Does a context switch in a CPU. + * \param the_stack the stackframe of the running app. + * \param new_pid the process's PID. + */ + /***********************************************************************************/ + + Bool UserProcessHelper::Switch(VoidPtr image, UInt8* stack, HAL::StackFramePtr frame_ptr, const PID& new_pid) + { + for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Capacity(); ++index) + { + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPInvalid || + HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPBoot) + continue; + + // A fallback is a special core for real-time tasks which needs immediate execution. + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPRealTime) + { + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity != AffinityKind::kRealTime) + continue; + + if (HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid)) + { + PTime prev_ptime = HardwareThreadScheduler::The()[index].Leak()->fPTime; + + HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + + PID prev_pid = UserProcessHelper::TheCurrentPID(); + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; + + return YES; + } + + continue; + } + + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity == AffinityKind::kRealTime) + continue; + + //////////////////////////////////////////////////////////// + /// Prepare task switch. /// + //////////////////////////////////////////////////////////// + + Bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid); + + //////////////////////////////////////////////////////////// + /// Rollback on fail. /// + //////////////////////////////////////////////////////////// + + if (!ret) + continue; + + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; + + HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + HardwareThreadScheduler::The()[index].Leak()->Wake(YES); + + return Yes; + } + + return No; + } + + //////////////////////////////////////////////////////////// + /// @brief this checks if any process is on the team. + //////////////////////////////////////////////////////////// + UserProcessScheduler::operator bool() + { + return mTeam.AsArray().Count() > 0; + } + + //////////////////////////////////////////////////////////// + /// @brief this checks if no process is on the team. + //////////////////////////////////////////////////////////// + Bool UserProcessScheduler::operator!() + { + return mTeam.AsArray().Count() == 0; + } +} // namespace Kernel diff --git a/dev/kernel/src/ProcessTeam.cc b/dev/kernel/src/ProcessTeam.cc new file mode 100644 index 00000000..80c9e5da --- /dev/null +++ b/dev/kernel/src/ProcessTeam.cc @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessTeam.cc +/// @brief Process teams implementation. +/***********************************************************************************/ + +#include + +namespace Kernel +{ + UserProcessTeam::UserProcessTeam() + { + for (SizeT i = 0U; i < this->mProcessList.Count(); ++i) + { + this->mProcessList[i] = UserProcess(); + this->mProcessList[i].PTime = 0; + this->mProcessList[i].Status = ProcessStatusKind::kKilled; + } + + this->mProcessCount = 0UL; + } + + /***********************************************************************************/ + /// @brief UserProcess list array getter. + /// @return The list of process to schedule. + /***********************************************************************************/ + + Array& UserProcessTeam::AsArray() + { + return this->mProcessList; + } + + /***********************************************************************************/ + /// @brief Get team ID. + /// @return The team's ID. + /***********************************************************************************/ + + ProcessID& UserProcessTeam::Id() noexcept + { + return this->mTeamId; + } + + /***********************************************************************************/ + /// @brief Get current process getter as Ref. + /// @return The current process header. + /***********************************************************************************/ + + Ref& UserProcessTeam::AsRef() + { + return this->mCurrentProcess; + } +} // namespace Kernel + +// last rev 05-03-24 diff --git a/dev/kernel/src/ThreadLocalStorage.cc b/dev/kernel/src/ThreadLocalStorage.cc index e784943d..8f537c06 100644 --- a/dev/kernel/src/ThreadLocalStorage.cc +++ b/dev/kernel/src/ThreadLocalStorage.cc @@ -9,7 +9,7 @@ #include #include -#include +#include #include /***********************************************************************************/ diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc deleted file mode 100644 index 99dbc410..00000000 --- a/dev/kernel/src/UserProcessScheduler.cc +++ /dev/null @@ -1,626 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. - - FILE: UserProcessScheduler.cc - PURPOSE: Low level/Ring-3 Process scheduler. - -------------------------------------------- */ - -/***********************************************************************************/ -/// @file UserProcessScheduler.cc -/// @brief Low level/Ring-3 process scheduler. -/***********************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -///! BUGS: 0 - -namespace Kernel -{ - /***********************************************************************************/ - /// @brief Exit Code global variable. - /***********************************************************************************/ - - STATIC UInt32 kLastExitCode = 0U; - - /***********************************************************************************/ - /// @brief External reference of the thread scheduler. - /***********************************************************************************/ - - STATIC UserProcessScheduler kProcessScheduler; - - UserProcess::UserProcess() = default; - UserProcess::~UserProcess() = default; - - /// @brief Gets the last exit code. - /// @note Not thread-safe. - /// @return Int32 the last exit code. - - const UInt32& sched_get_exit_code(void) noexcept - { - return kLastExitCode; - } - - /***********************************************************************************/ - /// @brief Crashes the current process. - /***********************************************************************************/ - - Void UserProcess::Crash() - { - if (this->Status != ProcessStatusKind::kRunning) - return; - - kout << this->Name << ": crashed, error id: " << number(kErrorProcessFault) << kendl; - this->Exit(kErrorProcessFault); - } - - /***********************************************************************************/ - /// @brief boolean operator, check status. - /***********************************************************************************/ - - UserProcess::operator bool() - { - return this->Status == ProcessStatusKind::kRunning; - } - - /***********************************************************************************/ - /// @brief Gets the local last exit code. - /// @note Not thread-safe. - /// @return Int32 the last exit code. - /***********************************************************************************/ - - const UInt32& UserProcess::GetExitCode() noexcept - { - return this->fLastExitCode; - } - - /***********************************************************************************/ - /// @brief Error code variable getter. - /***********************************************************************************/ - - Int32& UserProcess::GetLocalCode() noexcept - { - return this->fLocalCode; - } - - /***********************************************************************************/ - /// @brief Wakes process header. - /// @param should_wakeup if the program shall wakeup or not. - /***********************************************************************************/ - - Void UserProcess::Wake(const Bool should_wakeup) - { - this->Status = - should_wakeup ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen; - } - - /***********************************************************************************/ - /** @brief Allocate pointer to track list. */ - /***********************************************************************************/ - - ErrorOr UserProcess::New(const SizeT& sz, const SizeT& pad_amount) - { -#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - auto vm_register = hal_read_cr3(); - hal_write_cr3(this->VMRegister); - - auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); - - hal_write_cr3(vm_register); -#else - auto ptr = mm_new_heap(sz, Yes, Yes, pad_amount); -#endif - - if (!this->ProcessMemoryHeap) - { - this->ProcessMemoryHeap = new ProcessMemoryHeapList(); - - this->ProcessMemoryHeap->MemoryEntryPad = pad_amount; - this->ProcessMemoryHeap->MemoryEntrySize = sz; - - this->ProcessMemoryHeap->MemoryEntry = ptr; - - this->ProcessMemoryHeap->MemoryPrev = nullptr; - this->ProcessMemoryHeap->MemoryNext = nullptr; - } - else - { - ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; - ProcessMemoryHeapList* prev_entry = nullptr; - - while (entry) - { - if (entry->MemoryEntry == nullptr) - break; // chose to break here, when we get an already allocated memory entry for our needs. - - prev_entry = entry; - entry = entry->MemoryNext; - } - - entry->MemoryNext = new ProcessMemoryHeapList(); - entry->MemoryNext->MemoryEntry = ptr; - - entry->MemoryNext->MemoryPrev = entry; - entry->MemoryNext->MemoryNext = nullptr; - } - - this->UsedMemory += sz; - - return ErrorOr(ptr); - } - - /***********************************************************************************/ - /// @brief Gets the name of the current process. - /***********************************************************************************/ - - const Char* UserProcess::GetName() noexcept - { - return this->Name; - } - - /***********************************************************************************/ - /// @brief Gets the owner of the process. - /***********************************************************************************/ - - const User* UserProcess::GetOwner() noexcept - { - return this->Owner; - } - - /// @brief UserProcess status getter. - const ProcessStatusKind& UserProcess::GetStatus() noexcept - { - return this->Status; - } - - /***********************************************************************************/ - /** - @brief Affinity is the time slot allowed for the process. - */ - /***********************************************************************************/ - - const AffinityKind& UserProcess::GetAffinity() noexcept - { - return this->Affinity; - } - - /***********************************************************************************/ - /** - @brief Exit process method. - @param exit_code The process's exit code. - */ - /***********************************************************************************/ - - Void UserProcess::Exit(const Int32& exit_code) - { - this->Status = exit_code > 0 ? ProcessStatusKind::kKilled : ProcessStatusKind::kFrozen; - this->fLastExitCode = exit_code; - - kLastExitCode = exit_code; - - auto memory_heap_list = this->ProcessMemoryHeap; - -#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - auto pd = hal_read_cr3(); - hal_write_cr3(this->VMRegister); -#endif - - // Deleting memory lists. Make sure to free all of them. - while (memory_heap_list) - { - if (memory_heap_list->MemoryEntry) - { - MUST_PASS(mm_delete_heap(memory_heap_list->MemoryEntry)); - } - -#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - hal_write_cr3(pd); -#endif - - auto next = memory_heap_list->MemoryNext; - - mm_delete_heap(memory_heap_list); - - memory_heap_list = next; - } - - //! Free the memory's page directory. - HAL::mm_free_bitmap(this->VMRegister); - - //! Delete image if not done already. - if (this->Image.fCode && mm_is_valid_heap(this->Image.fCode)) - mm_delete_heap(this->Image.fCode); - - //! Delete blob too. - if (this->Image.fBlob && mm_is_valid_heap(this->Image.fBlob)) - mm_delete_heap(this->Image.fBlob); - - //! Delete stack frame. - if (this->StackFrame && mm_is_valid_heap(this->StackFrame)) - mm_delete_heap((VoidPtr)this->StackFrame); - - //! Delete stack reserve. - if (this->StackReserve && mm_is_valid_heap(this->StackReserve)) - mm_delete_heap(reinterpret_cast(this->StackReserve)); - - //! Avoid use after free. - this->Image.fBlob = nullptr; - this->Image.fCode = nullptr; - this->StackFrame = nullptr; - this->StackReserve = nullptr; - - if (this->Kind == kExectuableDylibKind) - { - Bool success = false; - - rtl_fini_dylib(*this, reinterpret_cast(this->DylibDelegate), &success); - - if (!success) - { - ke_panic(RUNTIME_CHECK_PROCESS); - } - - this->DylibDelegate = nullptr; - } - - this->ProcessId = 0UL; - this->Status = ProcessStatusKind::kFinished; - - --this->ProcessParentTeam->mProcessCount; - - delete this; - } - - /***********************************************************************************/ - /// @brief Add process to team. - /// @param process the process *Ref* class. - /// @return the process index inside the team. - /***********************************************************************************/ - - ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr image) - { - ProcessID pid = this->mTeam.mProcessCount; - - if (pid > kSchedProcessLimitPerTeam) - { - return kErrorProcessFault; - } - - ++this->mTeam.mProcessCount; - - UserProcess& process = this->mTeam.mProcessList[pid]; - - process.Image.fCode = code; - process.Image.fBlob = image; - - rt_copy_memory(reinterpret_cast(const_cast(name)), process.Name, rt_string_len(name)); - -#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - process.VMRegister = new PDE(); - - if (!process.VMRegister) - { - process.Crash(); - return kErrorProcessFault; - } - - UInt32 flags = HAL::kMMFlagsPresent; - flags |= HAL::kMMFlagsWr; - flags |= HAL::kMMFlagsUser; - - HAL::mm_map_page((VoidPtr)process.VMRegister, process.VMRegister, flags); -#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - - process.StackFrame = new HAL::StackFrame(); - - if (!process.StackFrame) - { - process.Crash(); - return kErrorProcessFault; - } - -#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - flags = HAL::kMMFlagsPresent; - flags |= HAL::kMMFlagsWr; - flags |= HAL::kMMFlagsUser; - - HAL::mm_map_page((VoidPtr)process.StackFrame, process.StackFrame, flags); -#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - - // React according to process kind. - switch (process.Kind) - { - case UserProcess::kExectuableDylibKind: { - process.DylibDelegate = rtl_init_dylib(process); - MUST_PASS(process.DylibDelegate); - } - default: { - kout << "Unknown process kind: " << hex_number(process.Kind) << kendl; - break; - } - } - - process.StackReserve = new UInt8[process.StackSize]; - rt_set_memory(process.StackReserve, 0, process.StackSize); - - if (!process.StackReserve) - { - process.Crash(); - return kErrorProcessFault; - } - -#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - flags = HAL::kMMFlagsPresent; - flags |= HAL::kMMFlagsWr; - flags |= HAL::kMMFlagsUser; - - HAL::mm_map_page((VoidPtr)process.StackReserve, process.StackReserve, flags); -#endif // ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ - - process.ProcessParentTeam = &mTeam; - - process.ProcessId = pid; - process.Status = ProcessStatusKind::kStarting; - process.PTime = (UIntPtr)AffinityKind::kStandard; - - kout << "PID: " << number(process.ProcessId) << kendl; - kout << "Name: " << process.Name << kendl; - - return pid; - } - - /***********************************************************************************/ - /// @brief Retrieves the singleton of the process scheduler. - /***********************************************************************************/ - - UserProcessScheduler& UserProcessScheduler::The() - { - return kProcessScheduler; - } - - /***********************************************************************************/ - - /// @brief Remove process from the team. - /// @param process_id process slot inside team. - /// @retval true process was removed. - /// @retval false process doesn't exist in team. - - /***********************************************************************************/ - - const Bool UserProcessScheduler::Remove(ProcessID process_id) - { - // check if process is within range. - if (process_id > mTeam.mProcessList.Count()) - return No; - - mTeam.mProcessList[process_id].Exit(0); - - return Yes; - } - - /// @brief Is it a user scheduler? - - const Bool UserProcessScheduler::IsUser() - { - return Yes; - } - - /// @brief Is it a kernel scheduler? - - const Bool UserProcessScheduler::IsKernel() - { - return No; - } - - /// @brief Is it a SMP scheduler? - - const Bool UserProcessScheduler::HasMP() - { - return Yes; - } - - /***********************************************************************************/ - /// @brief Run User scheduler object. - /// @return Process count executed within a team. - /***********************************************************************************/ - - const SizeT UserProcessScheduler::Run() noexcept - { - SizeT process_index = 0UL; //! we store this guy to tell the scheduler how many - //! things we have scheduled. - - if (mTeam.mProcessCount < 1) - { - kout << "UserProcessScheduler::Run(): This team doesn't have any process!\r"; - return 0UL; - } - for (; process_index < mTeam.AsArray().Capacity(); ++process_index) - { - auto& process = mTeam.AsArray()[process_index]; - - //! check if the process needs to be run. - if (UserProcessHelper::CanBeScheduled(process)) - { - // Set current process header. - this->CurrentProcess() = process; - - process.PTime = static_cast(process.Affinity); - - kout << "Switch to: '" << process.Name << "'.\r"; - - // tell helper to find a core to schedule on. - BOOL ret = UserProcessHelper::Switch(process.Image.fCode, &process.StackReserve[process.StackSize - 1], process.StackFrame, - process.ProcessId); - - if (!ret) - { - if (process.Affinity == AffinityKind::kRealTime) - continue; - - kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; - - process.Crash(); - } - } - else - { - --process.PTime; - } - } - - return process_index; - } - - /// @brief Gets the current scheduled team. - /// @return - UserProcessTeam& UserProcessScheduler::CurrentTeam() - { - return mTeam; - } - - /// @internal - - /// @brief Gets current running process. - /// @return - Ref& UserProcessScheduler::CurrentProcess() - { - return mTeam.AsRef(); - } - - /// @brief Current proccess id getter. - /// @return UserProcess ID integer. - ErrorOr UserProcessHelper::TheCurrentPID() - { - if (!kProcessScheduler.CurrentProcess()) - return ErrorOr{kErrorProcessFault}; - - kout << "UserProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; - return ErrorOr{kProcessScheduler.CurrentProcess().Leak().ProcessId}; - } - - /// @brief Check if process can be schedulded. - /// @param process the process reference. - /// @retval true can be schedulded. - /// @retval false cannot be schedulded. - Bool UserProcessHelper::CanBeScheduled(const UserProcess& process) - { - if (process.Status == ProcessStatusKind::kKilled || - process.Status == ProcessStatusKind::kFinished || - process.Status == ProcessStatusKind::kStarting || - process.Status == ProcessStatusKind::kFrozen) - return No; - - if (process.Status == ProcessStatusKind::kInvalid) - return No; - - if (!process.Image.fCode) - return No; - - if (!process.Name[0]) - return No; - - // real time processes shouldn't wait that much. - if (process.Affinity == AffinityKind::kRealTime) - return Yes; - - return process.PTime < 1; - } - - /***********************************************************************************/ - /** - * @brief Start scheduling current AP. - */ - /***********************************************************************************/ - - SizeT UserProcessHelper::StartScheduling() - { - return kProcessScheduler.Run(); - } - - /***********************************************************************************/ - /** - * \brief Does a context switch in a CPU. - * \param the_stack the stackframe of the running app. - * \param new_pid the process's PID. - */ - /***********************************************************************************/ - - Bool UserProcessHelper::Switch(VoidPtr image, UInt8* stack, HAL::StackFramePtr frame_ptr, const PID& new_pid) - { - for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Capacity(); ++index) - { - if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPInvalid || - HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPBoot) - continue; - - // A fallback is a special core for real-time tasks which needs immediate execution. - if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPRealTime) - { - if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity != AffinityKind::kRealTime) - continue; - - if (HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid)) - { - PTime prev_ptime = HardwareThreadScheduler::The()[index].Leak()->fPTime; - - HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; - - PID prev_pid = UserProcessHelper::TheCurrentPID(); - UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; - - return YES; - } - - continue; - } - - if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity == AffinityKind::kRealTime) - continue; - - //////////////////////////////////////////////////////////// - /// Prepare task switch. /// - //////////////////////////////////////////////////////////// - - Bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid); - - //////////////////////////////////////////////////////////// - /// Rollback on fail. /// - //////////////////////////////////////////////////////////// - - if (!ret) - continue; - - UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; - - HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; - HardwareThreadScheduler::The()[index].Leak()->Wake(YES); - - return Yes; - } - - return No; - } - - //////////////////////////////////////////////////////////// - /// @brief this checks if any process is on the team. - //////////////////////////////////////////////////////////// - UserProcessScheduler::operator bool() - { - return mTeam.AsArray().Count() > 0; - } - - //////////////////////////////////////////////////////////// - /// @brief this checks if no process is on the team. - //////////////////////////////////////////////////////////// - Bool UserProcessScheduler::operator!() - { - return mTeam.AsArray().Count() == 0; - } -} // namespace Kernel diff --git a/dev/kernel/src/UserProcessTeam.cc b/dev/kernel/src/UserProcessTeam.cc deleted file mode 100644 index a0a39054..00000000 --- a/dev/kernel/src/UserProcessTeam.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. - -------------------------------------------- */ - -/***********************************************************************************/ -/// @file UserProcessTeam.cc -/// @brief Process teams implementation. -/***********************************************************************************/ - -#include - -namespace Kernel -{ - UserProcessTeam::UserProcessTeam() - { - for (SizeT i = 0U; i < this->mProcessList.Count(); ++i) - { - this->mProcessList[i] = UserProcess(); - this->mProcessList[i].PTime = 0; - this->mProcessList[i].Status = ProcessStatusKind::kKilled; - } - - this->mProcessCount = 0UL; - } - - /***********************************************************************************/ - /// @brief UserProcess list array getter. - /// @return The list of process to schedule. - /***********************************************************************************/ - - Array& UserProcessTeam::AsArray() - { - return this->mProcessList; - } - - /***********************************************************************************/ - /// @brief Get team ID. - /// @return The team's ID. - /***********************************************************************************/ - - ProcessID& UserProcessTeam::Id() noexcept - { - return this->mTeamId; - } - - /***********************************************************************************/ - /// @brief Get current process getter as Ref. - /// @return The current process header. - /***********************************************************************************/ - - Ref& UserProcessTeam::AsRef() - { - return this->mCurrentProcess; - } -} // namespace Kernel - -// last rev 05-03-24 -- cgit v1.2.3