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/ArchKit/ArchKit.h | 6 +- dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc | 4 +- .../HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc | 2 +- dev/kernel/HALKit/AMD64/HalKernelMain.cc | 2 +- .../AMD64/HalSchedulerCorePrimitivesAMD64.cc | 2 +- dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 20 +- dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc | 2 +- dev/kernel/HALKit/ARM64/HalKernelMain.cc | 2 +- dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc | 2 +- .../ARM64/HalSchedulerCorePrimitivesARM64.cc | 2 +- dev/kernel/KernelKit/CodeMgr.h | 8 +- dev/kernel/KernelKit/DriveMgr.h | 2 +- dev/kernel/KernelKit/IDylibObject.h | 2 +- dev/kernel/KernelKit/IPEFDylibObject.h | 2 +- dev/kernel/KernelKit/KPC.h | 72 +-- dev/kernel/KernelKit/PECodeMgr.h | 2 +- dev/kernel/KernelKit/PEFCodeMgr.h | 6 +- dev/kernel/KernelKit/ProcessScheduler.h | 379 +++++++++++++ dev/kernel/KernelKit/ProcessScheduler.inl | 62 ++ dev/kernel/KernelKit/ThreadLocalStorage.inl | 2 +- dev/kernel/KernelKit/UserProcessScheduler.h | 379 ------------- dev/kernel/KernelKit/UserProcessScheduler.inl | 62 -- dev/kernel/KernelKit/XCOFF.h | 28 +- 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 -- 38 files changed, 1231 insertions(+), 1215 deletions(-) create mode 100644 dev/kernel/KernelKit/ProcessScheduler.h create mode 100644 dev/kernel/KernelKit/ProcessScheduler.inl delete mode 100644 dev/kernel/KernelKit/UserProcessScheduler.h delete mode 100644 dev/kernel/KernelKit/UserProcessScheduler.inl 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') diff --git a/dev/kernel/ArchKit/ArchKit.h b/dev/kernel/ArchKit/ArchKit.h index 51d47bc8..e70ce988 100644 --- a/dev/kernel/ArchKit/ArchKit.h +++ b/dev/kernel/ArchKit/ArchKit.h @@ -63,10 +63,14 @@ namespace Kernel return *(volatile DataKind*)(base + reg); } + /// @brief Hardware Abstraction Layer namespace HAL { + /// @brief Check whether this pointer is a bitmap object. + /// @param ptr argument to verify. + /// @param whether successful or not. auto mm_is_bitmap(VoidPtr ptr) -> Bool; - } + } // namespace HAL } // namespace Kernel typedef Kernel::Void (*rt_syscall_proc)(Kernel::VoidPtr); diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc index 3d0cee00..0791b28f 100644 --- a/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc +++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc @@ -5,11 +5,11 @@ ------------------------------------------- */ #include -#include +#include #include #include #include -#include +#include #include #include #include diff --git a/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc index b1fa95a4..273ea96b 100644 --- a/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc +++ b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc @@ -5,7 +5,7 @@ ------------------------------------------- */ #include -#include +#include #include #include diff --git a/dev/kernel/HALKit/AMD64/HalKernelMain.cc b/dev/kernel/HALKit/AMD64/HalKernelMain.cc index 30463f5d..8b092509 100644 --- a/dev/kernel/HALKit/AMD64/HalKernelMain.cc +++ b/dev/kernel/HALKit/AMD64/HalKernelMain.cc @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include diff --git a/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc b/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc index 6b287060..cb766477 100644 --- a/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc +++ b/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc @@ -5,7 +5,7 @@ ------------------------------------------- */ #include -#include +#include namespace Kernel { diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc index 2ef2fda7..38a1742b 100644 --- a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -133,9 +133,9 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz } /// prepare command header. - volatile HbaCmdHeader* command_header = ((HbaCmdHeader*)(((UInt64)kSATAHba->Ports[kSATAIndex].Clb))); + volatile HbaCmdHeader* command_header = ((volatile HbaCmdHeader*)(((UInt64)kSATAHba->Ports[kSATAIndex].Clb))); - /// jump to found slot. + /// Offset to specific command slot. command_header += slot; MUST_PASS(command_header); @@ -144,9 +144,9 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz command_header->Write = Write; command_header->Prdtl = (UInt16)((size_buffer - 1) / 8); - HbaCmdTbl* command_table = (HbaCmdTbl*)((VoidPtr)((UInt64)command_header->Ctba)); + volatile HbaCmdTbl* command_table = (volatile HbaCmdTbl*)((VoidPtr)((UInt64)command_header->Ctba)); - rt_set_memory(command_table, 0, sizeof(HbaCmdTbl) + (command_header->Prdtl - 1) * sizeof(HbaPrdtEntry)); + rt_set_memory((HbaCmdTbl*)command_table, 0, sizeof(HbaCmdTbl) + (command_header->Prdtl - 1) * sizeof(HbaPrdtEntry)); MUST_PASS(command_table); @@ -154,7 +154,7 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz UInt16 prd_i = 0; - for (; prd_i < (command_header->Prdtl - 1); prd_i++) + for (; prd_i < (command_header->Prdtl - 1); ++prd_i) { command_table->Prdt[prd_i].Dbc = ((command_header->Prdtl - 1) / 8); command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys); @@ -164,11 +164,13 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz buffer_phys += command_table->Prdt[prd_i].Dbc; } - FisRegH2D* h2d_fis = (FisRegH2D*)(&command_table->Cfis); + volatile FisRegH2D* h2d_fis = (volatile FisRegH2D*)(&command_table->Cfis); + + rt_set_memory((FisRegH2D*)h2d_fis, 0, sizeof(FisRegH2D)); h2d_fis->FisType = kFISTypeRegH2D; h2d_fis->CmdOrCtrl = CommandOrCTRL; - h2d_fis->Command = Identify ? (kAHCICmdIdentify) : (Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx); + h2d_fis->Command = (Identify ? (kAHCICmdIdentify) : (Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx)); h2d_fis->Lba0 = (lba)&0xFF; h2d_fis->Lba1 = (lba >> 8) & 0xFF; @@ -213,6 +215,8 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz err_global_get() = kErrorDiskIsCorrupted; return; } + + err_global_get() = kErrorSuccess; } /*** diff --git a/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc b/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc index 60f5bda3..a1d86bf4 100644 --- a/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc +++ b/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc @@ -7,7 +7,7 @@ #include #include #include -#include +#include #define GICD_BASE 0x08000000 // Distributor base address #define GICC_BASE 0x08010000 // CPU interface base address diff --git a/dev/kernel/HALKit/ARM64/HalKernelMain.cc b/dev/kernel/HALKit/ARM64/HalKernelMain.cc index e5ee3d42..573d6341 100644 --- a/dev/kernel/HALKit/ARM64/HalKernelMain.cc +++ b/dev/kernel/HALKit/ARM64/HalKernelMain.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc b/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc index 629e4eca..ae74bcba 100644 --- a/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc +++ b/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -#include +#include namespace Kernel { diff --git a/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc b/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc index 00a11fac..f0caa44e 100644 --- a/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc +++ b/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc @@ -5,7 +5,7 @@ ------------------------------------------- */ #include -#include +#include namespace Kernel { diff --git a/dev/kernel/KernelKit/CodeMgr.h b/dev/kernel/KernelKit/CodeMgr.h index 15ec420e..c781263e 100644 --- a/dev/kernel/KernelKit/CodeMgr.h +++ b/dev/kernel/KernelKit/CodeMgr.h @@ -33,5 +33,11 @@ namespace Kernel /// @note This sets up a new stack, anything on the main function that calls the Kernel will not be accessible. /// @param main the start of the process. /// @return The team's process id. - ProcessID rtl_create_process(rtl_main_kind main, const Char* process_name) noexcept; + ProcessID rtl_create_kernel_process(rtl_main_kind main, const Char* process_name) noexcept; + + /// @brief Executes a new process from a function. User code only. + /// @note This sets up a new stack, anything on the main function that calls the Kernel will not be accessible. + /// @param main the start of the process. + /// @return The team's process id. + ProcessID rtl_create_user_process(rtl_main_kind main, const Char* process_name) noexcept; } // namespace Kernel diff --git a/dev/kernel/KernelKit/DriveMgr.h b/dev/kernel/KernelKit/DriveMgr.h index 9d461703..a8c3dec5 100644 --- a/dev/kernel/KernelKit/DriveMgr.h +++ b/dev/kernel/KernelKit/DriveMgr.h @@ -7,7 +7,7 @@ #ifndef INC_DRIVE_MANAGER_H #define INC_DRIVE_MANAGER_H -#include +#include #include #include #include diff --git a/dev/kernel/KernelKit/IDylibObject.h b/dev/kernel/KernelKit/IDylibObject.h index f02fb9d3..faecede0 100644 --- a/dev/kernel/KernelKit/IDylibObject.h +++ b/dev/kernel/KernelKit/IDylibObject.h @@ -16,7 +16,7 @@ namespace Kernel { - /// @brief DLL class object. A handle to a shared library. + /// @brief Dylib class object. A handle to a shared library. class IDylibObject { public: diff --git a/dev/kernel/KernelKit/IPEFDylibObject.h b/dev/kernel/KernelKit/IPEFDylibObject.h index 22360e50..8c4ec22a 100644 --- a/dev/kernel/KernelKit/IPEFDylibObject.h +++ b/dev/kernel/KernelKit/IPEFDylibObject.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include namespace Kernel diff --git a/dev/kernel/KernelKit/KPC.h b/dev/kernel/KernelKit/KPC.h index c6724282..3e52be64 100644 --- a/dev/kernel/KernelKit/KPC.h +++ b/dev/kernel/KernelKit/KPC.h @@ -21,44 +21,44 @@ namespace Kernel { - typedef Int32 HError; + typedef Int32 KPCError; - inline HError kErrorLocalNumber = 0UL; + inline KPCError kErrorLocalNumber = 0UL; - inline constexpr HError kErrorSuccess = 0; - inline constexpr HError kErrorExecutable = 33; - inline constexpr HError kErrorExecutableLib = 34; - inline constexpr HError kErrorFileNotFound = 35; - inline constexpr HError kErrorDirectoryNotFound = 36; - inline constexpr HError kErrorDiskReadOnly = 37; - inline constexpr HError kErrorDiskIsFull = 38; - inline constexpr HError kErrorProcessFault = 39; - inline constexpr HError kErrorSocketHangUp = 40; - inline constexpr HError kErrorThreadLocalStorage = 41; - inline constexpr HError kErrorMath = 42; - inline constexpr HError kErrorNoNetwork = 43; - inline constexpr HError kErrorHeapOutOfMemory = 44; - inline constexpr HError kErrorNoSuchDisk = 45; - inline constexpr HError kErrorFileExists = 46; - inline constexpr HError kErrorFormatFailed = 47; - inline constexpr HError kErrorNetworkTimeout = 48; - inline constexpr HError kErrorInternal = 49; - inline constexpr HError kErrorForkAlreadyExists = 50; - inline constexpr HError kErrorOutOfTeamSlot = 51; - inline constexpr HError kErrorHeapNotPresent = 52; - inline constexpr HError kErrorNoEntrypoint = 53; - inline constexpr HError kErrorDiskIsCorrupted = 54; - inline constexpr HError kErrorDisk = 55; - inline constexpr HError kErrorInvalidData = 56; - inline constexpr HError kErrorAsync = 57; - inline constexpr HError kErrorNonBlocking = 58; - inline constexpr HError kErrorIPC = 59; - inline constexpr HError kErrorSign = 60; - inline constexpr HError kErrorInvalidCreds = 61; - inline constexpr HError kErrorCDTrayBroken = 62; - inline constexpr HError kErrorUnrecoverableDisk = 63; - inline constexpr HError kErrorFileLocked = 64; - inline constexpr HError kErrorUnimplemented = -1; + inline constexpr KPCError kErrorSuccess = 0; + inline constexpr KPCError kErrorExecutable = 33; + inline constexpr KPCError kErrorExecutableLib = 34; + inline constexpr KPCError kErrorFileNotFound = 35; + inline constexpr KPCError kErrorDirectoryNotFound = 36; + inline constexpr KPCError kErrorDiskReadOnly = 37; + inline constexpr KPCError kErrorDiskIsFull = 38; + inline constexpr KPCError kErrorProcessFault = 39; + inline constexpr KPCError kErrorSocketHangUp = 40; + inline constexpr KPCError kErrorThreadLocalStorage = 41; + inline constexpr KPCError kErrorMath = 42; + inline constexpr KPCError kErrorNoNetwork = 43; + inline constexpr KPCError kErrorHeapOutOfMemory = 44; + inline constexpr KPCError kErrorNoSuchDisk = 45; + inline constexpr KPCError kErrorFileExists = 46; + inline constexpr KPCError kErrorFormatFailed = 47; + inline constexpr KPCError kErrorNetworkTimeout = 48; + inline constexpr KPCError kErrorInternal = 49; + inline constexpr KPCError kErrorForkAlreadyExists = 50; + inline constexpr KPCError kErrorOutOfTeamSlot = 51; + inline constexpr KPCError kErrorHeapNotPresent = 52; + inline constexpr KPCError kErrorNoEntrypoint = 53; + inline constexpr KPCError kErrorDiskIsCorrupted = 54; + inline constexpr KPCError kErrorDisk = 55; + inline constexpr KPCError kErrorInvalidData = 56; + inline constexpr KPCError kErrorAsync = 57; + inline constexpr KPCError kErrorNonBlocking = 58; + inline constexpr KPCError kErrorIPC = 59; + inline constexpr KPCError kErrorSign = 60; + inline constexpr KPCError kErrorInvalidCreds = 61; + inline constexpr KPCError kErrorCDTrayBroken = 62; + inline constexpr KPCError kErrorUnrecoverableDisk = 63; + inline constexpr KPCError kErrorFileLocked = 64; + inline constexpr KPCError kErrorUnimplemented = -1; /// @brief Does a system wide bug check. /// @param void no params are needed. diff --git a/dev/kernel/KernelKit/PECodeMgr.h b/dev/kernel/KernelKit/PECodeMgr.h index 1e445b9f..cf7f625d 100644 --- a/dev/kernel/KernelKit/PECodeMgr.h +++ b/dev/kernel/KernelKit/PECodeMgr.h @@ -3,7 +3,7 @@ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. File: PECodeMgr.h - Purpose: PE32+ Code Mgr and DLL mgr. + Purpose: PE32+ Code Mgr and Dylib mgr. Revision History: diff --git a/dev/kernel/KernelKit/PEFCodeMgr.h b/dev/kernel/KernelKit/PEFCodeMgr.h index aa82f84d..3d96c6c0 100644 --- a/dev/kernel/KernelKit/PEFCodeMgr.h +++ b/dev/kernel/KernelKit/PEFCodeMgr.h @@ -13,10 +13,10 @@ #include #ifndef INC_PROCESS_SCHEDULER_H -#include +#include #endif -#define kPefApplicationMime "application/vnd-zka-executable" +#define kPefApplicationMime "application/vnd-amlal-executable" namespace Kernel { @@ -65,7 +65,7 @@ namespace Kernel namespace Utils { - ProcessID rtl_create_process(PEFLoader& exec, const Int32& procKind) noexcept; + ProcessID rtl_create_user_process(PEFLoader& exec, const Int32& procKind) noexcept; } // namespace Utils } // namespace Kernel diff --git a/dev/kernel/KernelKit/ProcessScheduler.h b/dev/kernel/KernelKit/ProcessScheduler.h new file mode 100644 index 00000000..5e88d1ec --- /dev/null +++ b/dev/kernel/KernelKit/ProcessScheduler.h @@ -0,0 +1,379 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef INC_PROCESS_SCHEDULER_H +#define INC_PROCESS_SCHEDULER_H + +#include +#include +#include +#include + +#define kSchedMinMicroTime (AffinityKind::kStandard) +#define kSchedInvalidPID ((PID)~0) +#define kSchedProcessLimitPerTeam (32U) + +#define kSchedMaxMemoryLimit gib_cast(128) /* max physical memory limit */ +#define kSchedMaxStackSz mib_cast(8) /* maximum stack size */ + +#define kSchedNameLen (128U) + +//////////////////////////////////////////////////// +// Last revision date is: Fri Mar 28 2025 // +//////////////////////////////////////////////////// + +namespace Kernel +{ + //! @note Forward class declaration. + + class IDylibObject; + class UserProcess; + class UserProcessTeam; + class UserProcessScheduler; + class UserProcessHelper; + + typedef UInt64 PTime; + + /***********************************************************************************/ + //! @brief Local Process identifier. + /***********************************************************************************/ + typedef Int64 ProcessID; + + /***********************************************************************************/ + //! @brief Local Process status enum. + /***********************************************************************************/ + enum class ProcessStatusKind : Int32 + { + kInvalid, + kStarting, + kRunning, + kKilled, + kFrozen, + kFinished, + kCount, + }; + + /***********************************************************************************/ + //! @brief Affinity is the amount of nano-seconds this process is going to run. + /***********************************************************************************/ + enum class AffinityKind : Int32 + { + kRealTime = 500, + kVeryHigh = 250, + kHigh = 200, + kStandard = 1000, + kLowUsage = 1500, + kVeryLowUsage = 2000, + }; + + /***********************************************************************************/ + //! Operators for AffinityKind + /***********************************************************************************/ + + inline bool operator<(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast(lhs); + Int32 rhs_int = static_cast(rhs); + + return lhs_int < rhs_int; + } + + inline bool operator>(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast(lhs); + Int32 rhs_int = static_cast(rhs); + + return lhs_int > rhs_int; + } + + inline bool operator<=(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast(lhs); + Int32 rhs_int = static_cast(rhs); + + return lhs_int <= rhs_int; + } + + inline bool operator>=(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast(lhs); + Int32 rhs_int = static_cast(rhs); + + return lhs_int >= rhs_int; + } + + /***********************************************************************************/ + /// @brief Subsystem enum type. + /***********************************************************************************/ + + enum class ProcessSubsystem : Int32 + { + kProcessSubsystemSecurity = 100, + kProcessSubsystemApplication, + kProcessSubsystemService, + kProcessSubsystemDriver, + kProcessSubsystemInvalid = 256U, + kProcessSubsystemCount = 4, + }; + + using ProcessTime = UInt64; + using PID = UInt64; + + /***********************************************************************************/ + /// @note For User manager, tells where we run the code. + /***********************************************************************************/ + enum class ProcessLevelRing : Int32 + { + kRingStdUser = 1, + kRingSuperUser = 2, + kRingGuestUser = 5, + kRingCount = 5, + }; + + /***********************************************************************************/ + /// @brief Helper type to describe a code image. + /***********************************************************************************/ + using ImagePtr = VoidPtr; + + struct UserProcessImage final + { + explicit UserProcessImage() = default; + + ImagePtr fCode; + ImagePtr fBlob; + + Bool HasCode() + { + return this->fCode != nullptr; + } + + Bool HasImage() + { + return this->fBlob != nullptr; + } + }; + + /***********************************************************************************/ + /// @name UserProcess + /// @brief User process class, holds information about the running process/thread. + /***********************************************************************************/ + class UserProcess final + { + public: + explicit UserProcess(); + ~UserProcess(); + + public: + NE_COPY_DEFAULT(UserProcess); + + public: + Char Name[kSchedNameLen] = {"Process"}; + ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemInvalid}; + User* Owner{nullptr}; + HAL::StackFramePtr StackFrame{nullptr}; + AffinityKind Affinity{AffinityKind::kStandard}; + ProcessStatusKind Status{ProcessStatusKind::kFinished}; + UInt8* StackReserve{nullptr}; + UserProcessImage Image{}; + SizeT StackSize{kSchedMaxStackSz}; + IDylibObject* DylibDelegate{nullptr}; + SizeT MemoryCursor{0UL}; + SizeT MemoryLimit{kSchedMaxMemoryLimit}; + SizeT UsedMemory{0UL}; + + struct ProcessMemoryHeapList final + { + VoidPtr MemoryEntry{nullptr}; + SizeT MemoryEntrySize{0UL}; + SizeT MemoryEntryPad{0UL}; + + struct ProcessMemoryHeapList* MemoryPrev{nullptr}; + struct ProcessMemoryHeapList* MemoryNext{nullptr}; + }; + + struct UserProcessSignal final + { + UIntPtr SignalArg; + ProcessStatusKind PreviousStatus; + UIntPtr SignalID; + }; + + UserProcessSignal ProcessSignal; + ProcessMemoryHeapList* ProcessMemoryHeap{nullptr}; + UserProcessTeam* ProcessParentTeam; + + VoidPtr VMRegister{0UL}; + + enum + { + kInvalidExecutableKind, + kExectuableKind, + kExectuableDylibKind, + kExectuableKindCount, + }; + + ProcessTime PTime{0}; //! @brief Process allocated tine. + + PID ProcessId{kSchedInvalidPID}; + Int32 Kind{kExectuableKind}; + + public: + /***********************************************************************************/ + //! @brief boolean operator, check status. + /***********************************************************************************/ + operator bool(); + + /***********************************************************************************/ + ///! @brief Crashes the app, exits with code ~0. + /***********************************************************************************/ + Void Crash(); + + /***********************************************************************************/ + ///! @brief Exits the app. + /***********************************************************************************/ + Void Exit(const Int32& exit_code = 0); + + /***********************************************************************************/ + ///! @brief TLS allocate. + ///! @param sz size of data structure. + ///! @param pad_amount amount to add after pointer. + ///! @return A wrapped pointer, or error code. + /***********************************************************************************/ + ErrorOr New(const SizeT& sz, const SizeT& pad_amount = 0); + + /***********************************************************************************/ + ///! @brief TLS free. + ///! @param ptr the pointer to free. + ///! @param sz the size of it. + /***********************************************************************************/ + template + Boolean Delete(ErrorOr ptr, const SizeT& sz); + + /***********************************************************************************/ + ///! @brief Wakes up thread. + /***********************************************************************************/ + Void Wake(const Bool wakeup = false); + + public: + /***********************************************************************************/ + //! @brief Gets the local exit code. + /***********************************************************************************/ + const UInt32& GetExitCode() noexcept; + + /***********************************************************************************/ + ///! @brief Get the process's name + ///! @example 'C Runtime Library' + /***********************************************************************************/ + const Char* GetName() noexcept; + + /***********************************************************************************/ + //! @brief return local error code of process. + //! @return Int32 local error code. + /***********************************************************************************/ + Int32& GetLocalCode() noexcept; + + const User* GetOwner() noexcept; + const ProcessStatusKind& GetStatus() noexcept; + const AffinityKind& GetAffinity() noexcept; + + private: + UInt32 fLastExitCode{0}; + Int32 fLocalCode{0}; + + friend UserProcessScheduler; + friend UserProcessHelper; + }; + + /// \brief Processs Team (contains multiple processes inside it.) + /// Equivalent to a process batch + class UserProcessTeam final + { + public: + explicit UserProcessTeam(); + ~UserProcessTeam() = default; + + NE_COPY_DEFAULT(UserProcessTeam); + + Array& AsArray(); + Ref& AsRef(); + ProcessID& Id() noexcept; + + public: + Array mProcessList; + Ref mCurrentProcess; + ProcessID mTeamId{0}; + ProcessID mProcessCount{0}; + }; + + typedef Array UserThreadArray; + + using UserProcessRef = UserProcess&; + + /***********************************************************************************/ + /// @brief Process scheduler class. + /// The main class which you call to schedule user processes. + /***********************************************************************************/ + class UserProcessScheduler final : public ISchedulable + { + friend class UserProcessHelper; + + public: + explicit UserProcessScheduler() = default; + ~UserProcessScheduler() override = default; + + NE_COPY_DEFAULT(UserProcessScheduler) + + operator bool(); + bool operator!(); + + public: + UserProcessTeam& CurrentTeam(); + + public: + ProcessID Spawn(const Char* name, VoidPtr code, VoidPtr image); + const Bool Remove(ProcessID process_id); + + const Bool IsUser() override; + const Bool IsKernel() override; + const Bool HasMP() override; + + public: + Ref& CurrentProcess(); + const SizeT Run() noexcept; + + public: + STATIC UserProcessScheduler& The(); + + private: + UserProcessTeam mTeam{}; + }; + + /***********************************************************************************/ + /** + * \brief UserProcess helper class, which contains needed utilities for the scheduler. + */ + /***********************************************************************************/ + + class UserProcessHelper final + { + public: + STATIC Bool Switch(VoidPtr image_ptr, UInt8* stack_ptr, HAL::StackFramePtr frame_ptr, const PID& new_pid); + STATIC Bool CanBeScheduled(const UserProcess& process); + STATIC ErrorOr TheCurrentPID(); + STATIC SizeT StartScheduling(); + }; + + const UInt32& sched_get_exit_code(void) noexcept; +} // namespace Kernel + +#include +#include + +//////////////////////////////////////////////////// +// END +//////////////////////////////////////////////////// + +#endif /* ifndef INC_PROCESS_SCHEDULER_H */ diff --git a/dev/kernel/KernelKit/ProcessScheduler.inl b/dev/kernel/KernelKit/ProcessScheduler.inl new file mode 100644 index 00000000..b624e623 --- /dev/null +++ b/dev/kernel/KernelKit/ProcessScheduler.inl @@ -0,0 +1,62 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + FILE: ProcessScheduler.inl + PURPOSE: Low level/Ring-3 Process scheduler. + +------------------------------------------- */ + +namespace Kernel +{ + /***********************************************************************************/ + /** @brief Free pointer from usage. */ + /***********************************************************************************/ + + template + Boolean UserProcess::Delete(ErrorOr ptr, const SizeT& sz) + { + if (!ptr) + return No; + + if (!this->ProcessMemoryHeap) + { + kout << "Process's heap is empty.\r"; + return No; + } + + ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; + + while (entry != nullptr) + { + if (entry->MemoryEntry == ptr.Leak().Leak()) + { + this->UsedMemory -= entry->MemoryEntrySize; + +#ifdef __NE_AMD64__ + auto pd = hal_read_cr3(); + + hal_write_cr3(this->VMRegister); + + auto ret = mm_delete_heap(entry->MemoryEntry); + + hal_write_cr3(pd); + + return ret == kErrorSuccess; +#else + Bool ret = mm_delete_heap(ptr.Leak().Leak()); + + return ret == kErrorSuccess; +#endif + } + + entry = entry->MemoryNext; + } + + kout << "Invalid Pointer: Trying to free a pointer which doesn't exist.\r"; + + this->Crash(); + + return No; + } +} // namespace Kernel diff --git a/dev/kernel/KernelKit/ThreadLocalStorage.inl b/dev/kernel/KernelKit/ThreadLocalStorage.inl index 0517dada..f9f9da12 100644 --- a/dev/kernel/KernelKit/ThreadLocalStorage.inl +++ b/dev/kernel/KernelKit/ThreadLocalStorage.inl @@ -8,7 +8,7 @@ //! @brief Allocate resources from the process's heap storage. #ifndef INC_PROCESS_SCHEDULER_H -#include +#include #endif template diff --git a/dev/kernel/KernelKit/UserProcessScheduler.h b/dev/kernel/KernelKit/UserProcessScheduler.h deleted file mode 100644 index b9c1676b..00000000 --- a/dev/kernel/KernelKit/UserProcessScheduler.h +++ /dev/null @@ -1,379 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifndef INC_PROCESS_SCHEDULER_H -#define INC_PROCESS_SCHEDULER_H - -#include -#include -#include -#include - -#define kSchedMinMicroTime (AffinityKind::kStandard) -#define kSchedInvalidPID ((PID)~0) -#define kSchedProcessLimitPerTeam (32U) - -#define kSchedMaxMemoryLimit gib_cast(128) /* max physical memory limit */ -#define kSchedMaxStackSz mib_cast(8) /* maximum stack size */ - -#define kSchedNameLen (128U) - -//////////////////////////////////////////////////// -// Last revision date is: Fri Mar 28 2025 // -//////////////////////////////////////////////////// - -namespace Kernel -{ - //! @note Forward class declaration. - - class IDylibObject; - class UserProcess; - class UserProcessTeam; - class UserProcessScheduler; - class UserProcessHelper; - - typedef UInt64 PTime; - - /***********************************************************************************/ - //! @brief Local Process identifier. - /***********************************************************************************/ - typedef Int64 ProcessID; - - /***********************************************************************************/ - //! @brief Local Process status enum. - /***********************************************************************************/ - enum class ProcessStatusKind : Int32 - { - kInvalid, - kStarting, - kRunning, - kKilled, - kFrozen, - kFinished, - kCount, - }; - - /***********************************************************************************/ - //! @brief Affinity is the amount of nano-seconds this process is going to run. - /***********************************************************************************/ - enum class AffinityKind : Int32 - { - kRealTime = 500, - kVeryHigh = 250, - kHigh = 200, - kStandard = 1000, - kLowUsage = 1500, - kVeryLowUsage = 2000, - }; - - /***********************************************************************************/ - //! Operators for AffinityKind - /***********************************************************************************/ - - inline bool operator<(AffinityKind lhs, AffinityKind rhs) - { - Int32 lhs_int = static_cast(lhs); - Int32 rhs_int = static_cast(rhs); - - return lhs_int < rhs_int; - } - - inline bool operator>(AffinityKind lhs, AffinityKind rhs) - { - Int32 lhs_int = static_cast(lhs); - Int32 rhs_int = static_cast(rhs); - - return lhs_int > rhs_int; - } - - inline bool operator<=(AffinityKind lhs, AffinityKind rhs) - { - Int32 lhs_int = static_cast(lhs); - Int32 rhs_int = static_cast(rhs); - - return lhs_int <= rhs_int; - } - - inline bool operator>=(AffinityKind lhs, AffinityKind rhs) - { - Int32 lhs_int = static_cast(lhs); - Int32 rhs_int = static_cast(rhs); - - return lhs_int >= rhs_int; - } - - /***********************************************************************************/ - /// @brief Subsystem enum type. - /***********************************************************************************/ - - enum class ProcessSubsystem : Int32 - { - kProcessSubsystemSecurity = 100, - kProcessSubsystemApplication, - kProcessSubsystemService, - kProcessSubsystemDriver, - kProcessSubsystemInvalid = 256U, - kProcessSubsystemCount = 4, - }; - - using ProcessTime = UInt64; - using PID = UInt64; - - /***********************************************************************************/ - /// @note For User manager, tells where we run the code. - /***********************************************************************************/ - enum class ProcessLevelRing : Int32 - { - kRingStdUser = 1, - kRingSuperUser = 2, - kRingGuestUser = 5, - kRingCount = 5, - }; - - /***********************************************************************************/ - /// @brief Helper type to describe a code image. - /***********************************************************************************/ - using ImagePtr = VoidPtr; - - struct UserProcessImage final - { - explicit UserProcessImage() = default; - - ImagePtr fCode; - ImagePtr fBlob; - - Bool HasCode() - { - return this->fCode != nullptr; - } - - Bool HasImage() - { - return this->fBlob != nullptr; - } - }; - - /***********************************************************************************/ - /// @name UserProcess - /// @brief User process class, holds information about the running process/thread. - /***********************************************************************************/ - class UserProcess final - { - public: - explicit UserProcess(); - ~UserProcess(); - - public: - NE_COPY_DEFAULT(UserProcess); - - public: - Char Name[kSchedNameLen] = {"Process"}; - ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemInvalid}; - User* Owner{nullptr}; - HAL::StackFramePtr StackFrame{nullptr}; - AffinityKind Affinity{AffinityKind::kStandard}; - ProcessStatusKind Status{ProcessStatusKind::kFinished}; - UInt8* StackReserve{nullptr}; - UserProcessImage Image{}; - SizeT StackSize{kSchedMaxStackSz}; - IDylibObject* DylibDelegate{nullptr}; - SizeT MemoryCursor{0UL}; - SizeT MemoryLimit{kSchedMaxMemoryLimit}; - SizeT UsedMemory{0UL}; - - struct ProcessMemoryHeapList final - { - VoidPtr MemoryEntry{nullptr}; - SizeT MemoryEntrySize{0UL}; - SizeT MemoryEntryPad{0UL}; - - struct ProcessMemoryHeapList* MemoryPrev{nullptr}; - struct ProcessMemoryHeapList* MemoryNext{nullptr}; - }; - - struct UserProcessSignal final - { - UIntPtr SignalArg; - ProcessStatusKind PreviousStatus; - UIntPtr SignalID; - }; - - UserProcessSignal ProcessSignal; - ProcessMemoryHeapList* ProcessMemoryHeap{nullptr}; - UserProcessTeam* ProcessParentTeam; - - VoidPtr VMRegister{0UL}; - - enum - { - kInvalidExecutableKind, - kExectuableKind, - kExectuableDylibKind, - kExectuableKindCount, - }; - - ProcessTime PTime{0}; //! @brief Process allocated tine. - - PID ProcessId{kSchedInvalidPID}; - Int32 Kind{kExectuableKind}; - - public: - /***********************************************************************************/ - //! @brief boolean operator, check status. - /***********************************************************************************/ - operator bool(); - - /***********************************************************************************/ - ///! @brief Crashes the app, exits with code ~0. - /***********************************************************************************/ - Void Crash(); - - /***********************************************************************************/ - ///! @brief Exits the app. - /***********************************************************************************/ - Void Exit(const Int32& exit_code = 0); - - /***********************************************************************************/ - ///! @brief TLS allocate. - ///! @param sz size of data structure. - ///! @param pad_amount amount to add after pointer. - ///! @return A wrapped pointer, or error code. - /***********************************************************************************/ - ErrorOr New(const SizeT& sz, const SizeT& pad_amount = 0); - - /***********************************************************************************/ - ///! @brief TLS free. - ///! @param ptr the pointer to free. - ///! @param sz the size of it. - /***********************************************************************************/ - template - Boolean Delete(ErrorOr ptr, const SizeT& sz); - - /***********************************************************************************/ - ///! @brief Wakes up thread. - /***********************************************************************************/ - Void Wake(const Bool wakeup = false); - - public: - /***********************************************************************************/ - //! @brief Gets the local exit code. - /***********************************************************************************/ - const UInt32& GetExitCode() noexcept; - - /***********************************************************************************/ - ///! @brief Get the process's name - ///! @example 'C Runtime Library' - /***********************************************************************************/ - const Char* GetName() noexcept; - - /***********************************************************************************/ - //! @brief return local error code of process. - //! @return Int32 local error code. - /***********************************************************************************/ - Int32& GetLocalCode() noexcept; - - const User* GetOwner() noexcept; - const ProcessStatusKind& GetStatus() noexcept; - const AffinityKind& GetAffinity() noexcept; - - private: - UInt32 fLastExitCode{0}; - Int32 fLocalCode{0}; - - friend UserProcessScheduler; - friend UserProcessHelper; - }; - - /// \brief Processs Team (contains multiple processes inside it.) - /// Equivalent to a process batch - class UserProcessTeam final - { - public: - explicit UserProcessTeam(); - ~UserProcessTeam() = default; - - NE_COPY_DEFAULT(UserProcessTeam); - - Array& AsArray(); - Ref& AsRef(); - ProcessID& Id() noexcept; - - public: - Array mProcessList; - Ref mCurrentProcess; - ProcessID mTeamId{0}; - ProcessID mProcessCount{0}; - }; - - typedef Array UserThreadArray; - - using UserProcessRef = UserProcess&; - - /***********************************************************************************/ - /// @brief Process scheduler class. - /// The main class which you call to schedule user processes. - /***********************************************************************************/ - class UserProcessScheduler final : public ISchedulable - { - friend class UserProcessHelper; - - public: - explicit UserProcessScheduler() = default; - ~UserProcessScheduler() override = default; - - NE_COPY_DEFAULT(UserProcessScheduler) - - operator bool(); - bool operator!(); - - public: - UserProcessTeam& CurrentTeam(); - - public: - ProcessID Spawn(const Char* name, VoidPtr code, VoidPtr image); - const Bool Remove(ProcessID process_id); - - const Bool IsUser() override; - const Bool IsKernel() override; - const Bool HasMP() override; - - public: - Ref& CurrentProcess(); - const SizeT Run() noexcept; - - public: - STATIC UserProcessScheduler& The(); - - private: - UserProcessTeam mTeam{}; - }; - - /***********************************************************************************/ - /** - * \brief UserProcess helper class, which contains needed utilities for the scheduler. - */ - /***********************************************************************************/ - - class UserProcessHelper final - { - public: - STATIC Bool Switch(VoidPtr image_ptr, UInt8* stack_ptr, HAL::StackFramePtr frame_ptr, const PID& new_pid); - STATIC Bool CanBeScheduled(const UserProcess& process); - STATIC ErrorOr TheCurrentPID(); - STATIC SizeT StartScheduling(); - }; - - const UInt32& sched_get_exit_code(void) noexcept; -} // namespace Kernel - -#include -#include - -//////////////////////////////////////////////////// -// END -//////////////////////////////////////////////////// - -#endif /* ifndef INC_PROCESS_SCHEDULER_H */ diff --git a/dev/kernel/KernelKit/UserProcessScheduler.inl b/dev/kernel/KernelKit/UserProcessScheduler.inl deleted file mode 100644 index 4b3d5820..00000000 --- a/dev/kernel/KernelKit/UserProcessScheduler.inl +++ /dev/null @@ -1,62 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. - - FILE: UserProcessScheduler.inl - PURPOSE: Low level/Ring-3 Process scheduler. - -------------------------------------------- */ - -namespace Kernel -{ - /***********************************************************************************/ - /** @brief Free pointer from usage. */ - /***********************************************************************************/ - - template - Boolean UserProcess::Delete(ErrorOr ptr, const SizeT& sz) - { - if (!ptr) - return No; - - if (!this->ProcessMemoryHeap) - { - kout << "Process Memory is empty.\r"; - return No; - } - - ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; - - while (entry != nullptr) - { - if (entry->MemoryEntry == ptr.Leak().Leak()) - { - this->UsedMemory -= entry->MemoryEntrySize; - -#ifdef __NE_AMD64__ - auto pd = hal_read_cr3(); - - hal_write_cr3(this->VMRegister); - - auto ret = mm_delete_heap(entry->MemoryEntry); - - hal_write_cr3(pd); - - return ret == kErrorSuccess; -#else - Bool ret = mm_delete_heap(ptr.Leak().Leak()); - - return ret == kErrorSuccess; -#endif - } - - entry = entry->MemoryNext; - } - - kout << "Invalid Pointer: Trying to free a pointer which doesn't exist.\r"; - - this->Crash(); - - return No; - } -} // namespace Kernel diff --git a/dev/kernel/KernelKit/XCOFF.h b/dev/kernel/KernelKit/XCOFF.h index d38c2e02..eb536c01 100644 --- a/dev/kernel/KernelKit/XCOFF.h +++ b/dev/kernel/KernelKit/XCOFF.h @@ -16,18 +16,19 @@ #include -#define kXCOFF64Magic (0x01F7) +#define kXCOFF64Magic (0x01F7) +#define kXCOFF64ForkNameLen (256U) #define kXCOFFRelFlg (0x0001) #define kXCOFFExecutable (0x0002) #define kXCOFFLnno (0x0004) #define kXCOFFLSyms (0x0008) -struct XCoffFileHeader; -struct XCoffForkHeader; +struct XCOFF_FILE_HEADER; +struct XCOFF_FORK_HEADER; /// @brief XCoff file header, meant for POWER apps. -typedef struct XCoffFileHeader +typedef struct XCOFF_FILE_HEADER { Kernel::UInt16 fMagic; Kernel::UInt16 fTarget; @@ -36,16 +37,17 @@ typedef struct XCoffFileHeader Kernel::UIntPtr fSymPtr; Kernel::UInt32 fNumSyms; Kernel::UInt16 fOptHdr; // ?: Number of bytes in optional header -} XCoffFileHeader64; +} XCOFF_FILE_HEADER, XCOFF_FILE_HEADER32, XCOFF_FILE_HEADER64; -#define kForkNameLen (256U) - -/// @brief This the executable manifest fork. -typedef struct XCoffForkHeader +/// @brief This the executable's manifest fork, designed for NeFS. +/// @param fPropertiesXMLFork The XML fork of the executable. +/// @param fDynamicLoaderFork The DYLD fork metadata. +/// @param fCodeSignFork Executable's certificate contained in a fork. +typedef struct XCOFF_FORK_HEADER { - Kernel::Char fPropertiesXMLFork[kForkNameLen]; - Kernel::Char fDynamicLoaderFork[kForkNameLen]; - Kernel::Char fCodeSignFork[kForkNameLen]; -} XCoffForkHeader; + Kernel::Char fPropertiesXMLFork[kXCOFF64ForkNameLen]; + Kernel::Char fDynamicLoaderFork[kXCOFF64ForkNameLen]; + Kernel::Char fCodeSignFork[kXCOFF64ForkNameLen]; +} XCOFF_FORK_HEADER; #endif // ifndef INC_XOCFF_H 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