From dfaf137915094e7ba72f7d7f1f57dc5158d1b6ab Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 9 Jul 2024 20:51:20 +0200 Subject: MHR-36: A set of major fixes for bootloader and kernel alongside new implementations. - Implement realloc for kernel scheduler improvements. - Fixed readAll on bootloader's BFileReader. - Add resources for zeta installation. - Add STB header. - Process Heap which replaced the previous User Heap. Signed-off-by: Amlal El Mahrouss --- Kernel/Sources/KeMain.cxx | 2 +- Kernel/Sources/KernelHeap.cxx | 36 ++++- Kernel/Sources/ProcessHeap.cxx | 256 ++++++++++++++++++++++++++++++++++++ Kernel/Sources/ProcessScheduler.cxx | 34 +++-- Kernel/Sources/UserHeap.cxx | 256 ------------------------------------ 5 files changed, 311 insertions(+), 273 deletions(-) create mode 100644 Kernel/Sources/ProcessHeap.cxx delete mode 100644 Kernel/Sources/UserHeap.cxx (limited to 'Kernel/Sources') diff --git a/Kernel/Sources/KeMain.cxx b/Kernel/Sources/KeMain.cxx index 0ba882af..d4c02990 100644 --- a/Kernel/Sources/KeMain.cxx +++ b/Kernel/Sources/KeMain.cxx @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Kernel/Sources/KernelHeap.cxx b/Kernel/Sources/KernelHeap.cxx index 295c4e76..2cf89480 100644 --- a/Kernel/Sources/KernelHeap.cxx +++ b/Kernel/Sources/KernelHeap.cxx @@ -11,7 +11,7 @@ #include //! @file KernelHeap.cxx -//! @brief Kernel allocator. +//! @brief Kernel heap allocator. #define kKernelHeapMagic (0xD4D7D5) #define kKernelHeapHeaderPaddingSz (16U) @@ -47,23 +47,47 @@ namespace Kernel typedef HeapInformationBlock* HeapInformationBlockPtr; } // namespace Detail + /// @brief Declare a new size for allocatedPtr. + /// @param allocatedPtr the pointer. + /// @return + voidPtr ke_realloc_ke_heap(voidPtr allocatedPtr, SizeT newSz) + { + if (!allocatedPtr || newSz < 1) + return nullptr; + + Detail::HeapInformationBlockPtr heapInfoBlk = + reinterpret_cast( + (UIntPtr)allocatedPtr - sizeof(Detail::HeapInformationBlock)); + + heapInfoBlk->fTargetPtrSize = newSz; + + if (heapInfoBlk->fCRC32 > 0) + { + MUST_PASS(ke_protect_ke_heap(allocatedPtr)); + } + + return allocatedPtr; + } + /// @brief allocate chunk of memory. /// @param sz size of pointer /// @param rw read write (true to enable it) /// @param user is it accesible by user processes? /// @return the pointer - VoidPtr ke_new_ke_heap(SizeT sz, const bool rw, const bool user) + VoidPtr ke_new_ke_heap(const SizeT sz, const bool rw, const bool user) { - if (sz == 0) - ++sz; + auto szFix = sz; + + if (szFix == 0) + ++szFix; - auto wrapper = kHeapPageManager.Request(rw, user, false, sz); + auto wrapper = kHeapPageManager.Request(rw, user, false, szFix); Detail::HeapInformationBlockPtr heapInfo = reinterpret_cast( wrapper.VirtualAddress()); - heapInfo->fTargetPtrSize = sz; + heapInfo->fTargetPtrSize = szFix; heapInfo->fMagic = kKernelHeapMagic; heapInfo->fCRC32 = 0; // dont fill it for now. heapInfo->fTargetPtr = wrapper.VirtualAddress(); diff --git a/Kernel/Sources/ProcessHeap.cxx b/Kernel/Sources/ProcessHeap.cxx new file mode 100644 index 00000000..b5988c5f --- /dev/null +++ b/Kernel/Sources/ProcessHeap.cxx @@ -0,0 +1,256 @@ +/* ------------------------------------------- + + Copyright Zeta Electronics Corporation + +------------------------------------------- */ + +#include +#include +#include + +#define kHeapHeaderPaddingSz (16U) + +/// @file ProcessHeap.cxx +/// @brief User Heap Manager, Process heap allocator. +/// @note if you want to look at the kernel allocator, please look for +/// KernelHeap.cxx +/// BUGS: 0 + +namespace Kernel +{ + /** + * @brief Process Heap Header + * @note Allocated per process, it denotes the user's heap. + */ + struct UserHeapHeader final + { + UInt32 fMagic; + Int32 fFlags; + Boolean fFree; + UInt8 fPadding[kHeapHeaderPaddingSz]; + }; + + /** + * @brief User Heap Manager class, takes care of allocating the process pools. + * @note This rely on Virtual Memory! Consider adding good vmem support when + * @note porting to a new arch. + */ + class UserHeapManager final + { + UserHeapManager() = delete; + + public: + ~UserHeapManager() = default; + + public: + STATIC SizeT& Count() + { + return s_NumPools; + } + + STATIC Ref& Leak() + { + return s_Pmm; + } + + STATIC Boolean& IsEnabled() + { + return s_PoolsAreEnabled; + } + + STATIC MutableArray>& The() + { + return s_Pool; + } + + private: + STATIC Size s_NumPools; + STATIC Ref s_Pmm; + + private: + STATIC Boolean s_PoolsAreEnabled; + STATIC MutableArray> s_Pool; + }; + + //! declare fields + + SizeT UserHeapManager::s_NumPools = 0UL; + Ref UserHeapManager::s_Pmm; + Boolean UserHeapManager::s_PoolsAreEnabled = true; + MutableArray> UserHeapManager::s_Pool; + + STATIC VoidPtr ke_find_unused_heap(Int32 flags); + STATIC Void ke_free_heap_internal(VoidPtr vaddr); + STATIC VoidPtr ke_make_heap_internal(VoidPtr vaddr, Int32 flags); + STATIC Boolean ke_check_and_free_heap(const SizeT& index, VoidPtr ptr); + + /// @brief Find an unused heap header to allocate on. + /// @param flags the flags to use. + /// @return VoidPtr the heap pointer. + STATIC VoidPtr ke_find_unused_heap(Int32 flags) + { + for (SizeT index = 0; index < kUserHeapMaxSz; ++index) + { + if (UserHeapManager::The()[index] && + !UserHeapManager::The()[index].Leak().Leak().Present()) + { + UserHeapManager::Leak().Leak().TogglePresent( + UserHeapManager::The()[index].Leak().Leak(), true); + kcout << "[ke_find_unused_heap] Done, trying to make a pool now...\r"; + + return ke_make_heap_internal( + (VoidPtr)UserHeapManager::The()[index].Leak().Leak().VirtualAddress(), + flags); + } + } + + return nullptr; + } + + /// @brief Makes a new heap for the process to use. + /// @param virtualAddress the virtual address of the process. + /// @param flags the flags. + /// @return + STATIC VoidPtr ke_make_heap_internal(VoidPtr virtualAddress, Int32 flags) + { + if (virtualAddress) + { + UserHeapHeader* poolHdr = reinterpret_cast(virtualAddress); + + if (!poolHdr->fFree) + { + kcout + << "[ke_make_heap_internal] poolHdr->fFree, HeapPtr already exists\n"; + return nullptr; + } + + poolHdr->fFlags = flags; + poolHdr->fMagic = kUserHeapMag; + poolHdr->fFree = false; + + kcout << "[ke_make_heap_internal] New allocation has been done.\n"; + return reinterpret_cast( + (reinterpret_cast(virtualAddress) + sizeof(UserHeapHeader))); + } + + kcout << "[ke_make_heap_internal] Address is invalid"; + return nullptr; + } + + /// @brief Internally makrs the heap as free. + /// This is done by setting the fFree bit to true + /// @param virtualAddress + /// @return + STATIC Void ke_free_heap_internal(VoidPtr virtualAddress) + { + UserHeapHeader* poolHdr = reinterpret_cast( + reinterpret_cast(virtualAddress) - sizeof(UserHeapHeader)); + + if (poolHdr->fMagic == kUserHeapMag) + { + if (!poolHdr->fFree) + { + ProcessScheduler::The().Leak().TheCurrent().Leak().Crash(); + return; + } + + poolHdr->fFree = true; + poolHdr->fFlags = 0; + + kcout << "[ke_free_heap_internal] Successfully marked header as free!\r"; + } + } + + /** + * @brief Check for the ptr and frees it. + * + * @param index Where to look at. + * @param ptr The ptr to check. + * @return Boolean true if successful. + */ + STATIC Boolean ke_check_and_free_heap(const SizeT& index, VoidPtr ptr) + { + if (UserHeapManager::The()[index]) + { + // ErrorOr<>::operator Boolean + /// if (address matches) + /// -> Free heap. + if (UserHeapManager::The()[index].Leak().Leak().VirtualAddress() == + (UIntPtr)ptr) + { + UserHeapManager::Leak().Leak().FreePage( + UserHeapManager::The()[index].Leak().Leak()); + + --UserHeapManager::Count(); + + ke_free_heap_internal(ptr); + ptr = nullptr; + + return true; + } + } + + return false; + } + + /// @brief Creates a new pool pointer. + /// @param flags the flags attached to it. + /// @return a pool pointer with selected permissions. + VoidPtr rt_new_heap(Int32 flags) + { + if (!UserHeapManager::IsEnabled()) + return nullptr; + + if (UserHeapManager::Count() > kUserHeapMaxSz) + return nullptr; + + if (VoidPtr ret = ke_find_unused_heap(flags)) + return ret; + + // this wasn't set to true + auto ref_page = UserHeapManager::Leak().Leak().RequestPage( + ((flags & kUserHeapUser)), (flags & kUserHeapRw)); + + if (ref_page) + { + ///! reserve page. + UserHeapManager::The()[UserHeapManager::Count()].Leak() = ref_page; + auto& ref = UserHeapManager::Count(); + + ++ref; // increment the number of addresses we have now. + + // finally make the pool address. + return ke_make_heap_internal( + reinterpret_cast(ref_page.Leak().VirtualAddress()), flags); + } + + return nullptr; + } + + /// @brief free a pool pointer. + /// @param ptr The pool pointer to free. + /// @return status code + Int32 rt_free_heap(VoidPtr ptr) + { + if (!UserHeapManager::IsEnabled()) + return -1; + + if (ptr) + { + SizeT base = UserHeapManager::Count(); + + if (ke_check_and_free_heap(base, ptr)) + return 0; + + for (SizeT index = 0; index < kUserHeapMaxSz; ++index) + { + if (ke_check_and_free_heap(index, ptr)) + return 0; + + --base; + } + } + + return -1; + } +} // namespace Kernel diff --git a/Kernel/Sources/ProcessScheduler.cxx b/Kernel/Sources/ProcessScheduler.cxx index 98851d41..f8330ae8 100644 --- a/Kernel/Sources/ProcessScheduler.cxx +++ b/Kernel/Sources/ProcessScheduler.cxx @@ -206,15 +206,23 @@ namespace Kernel if (mTeam.AsArray().Count() > kSchedProcessLimitPerTeam) return -kErrorOutOfTeamSlot; - kcout << "ProcessScheduler::Add(Ref& process)\r"; + kcout << "ProcessScheduler:: adding process to team...\r"; /// Create heap according to type of process. if (process.Leak().Kind == ProcessHeader::kAppKind) + { process.Leak().HeapPtr = rt_new_heap(kUserHeapUser | kUserHeapRw); + } else if (process.Leak().Kind == ProcessHeader::kShLibKind) + { process.Leak().HeapPtr = rt_new_heap(kUserHeapUser | kUserHeapRw | kUserHeapShared); + } else - process.Leak().HeapPtr = rt_new_heap(kUserHeapDriver | kUserHeapRw); + { + // something went wrong, do not continue, process kind is incorrect. + process.Leak().Crash(); + return -kErrorProcessFault; + } process.Leak().StackFrame = reinterpret_cast( ke_new_ke_heap(sizeof(HAL::StackFrame), true, false)); @@ -226,22 +234,28 @@ namespace Kernel process.Leak().ProcessId = (mTeam.AsArray().Count() - 1); process.Leak().HeapCursor = process.Leak().HeapPtr; - mTeam.AsArray().Add(process); + MUST_PASS(mTeam.AsArray().Add(process)); - return mTeam.AsArray().Count() - 1; + return (mTeam.AsArray().Count() - 1); } /// @brief Remove process from list. - /// @param process - /// @return - bool ProcessScheduler::Remove(SizeT process) + /// @param processSlot process slot inside team. + /// @retval true process was removed. + /// @retval false process doesn't exist in team. + Bool ProcessScheduler::Remove(SizeT processSlot) { - if (process > mTeam.AsArray().Count()) + // check if process is within range. + if (processSlot > mTeam.AsArray().Count()) + return false; + + // also check if the process isn't a dummy one. + if (mTeam.AsArray()[processSlot].Leak().Leak().Image == nullptr) return false; - kcout << "ProcessScheduler::Remove(SizeT process)\r"; + kcout << "ProcessScheduler: removing process\r"; - return mTeam.AsArray().Remove(process); + return mTeam.AsArray().Remove(processSlot); } /// @brief Run scheduler. diff --git a/Kernel/Sources/UserHeap.cxx b/Kernel/Sources/UserHeap.cxx deleted file mode 100644 index 453d1f30..00000000 --- a/Kernel/Sources/UserHeap.cxx +++ /dev/null @@ -1,256 +0,0 @@ -/* ------------------------------------------- - - Copyright Zeta Electronics Corporation - -------------------------------------------- */ - -#include -#include -#include - -#define kHeapHeaderPaddingSz (16U) - -/// @file UserHeap.cxx -/// @brief User Heap Manager, Process heap allocator. -/// @note if you want to look at the kernel allocator, please look for -/// KernelHeap.cxx -/// BUGS: 0 - -namespace Kernel -{ - /** - * @brief Process Heap Header - * @note Allocated per process, it denotes the user's heap. - */ - struct UserHeapHeader final - { - UInt32 fMagic; - Int32 fFlags; - Boolean fFree; - UInt8 fPadding[kHeapHeaderPaddingSz]; - }; - - /** - * @brief User Heap Manager class, takes care of allocating the process pools. - * @note This rely on Virtual Memory! Consider adding good vmem support when - * @note porting to a new arch. - */ - class UserHeapManager final - { - UserHeapManager() = delete; - - public: - ~UserHeapManager() = default; - - public: - STATIC SizeT& Count() - { - return s_NumPools; - } - - STATIC Ref& Leak() - { - return s_Pmm; - } - - STATIC Boolean& IsEnabled() - { - return s_PoolsAreEnabled; - } - - STATIC MutableArray>& The() - { - return s_Pool; - } - - private: - STATIC Size s_NumPools; - STATIC Ref s_Pmm; - - private: - STATIC Boolean s_PoolsAreEnabled; - STATIC MutableArray> s_Pool; - }; - - //! declare fields - - SizeT UserHeapManager::s_NumPools = 0UL; - Ref UserHeapManager::s_Pmm; - Boolean UserHeapManager::s_PoolsAreEnabled = true; - MutableArray> UserHeapManager::s_Pool; - - STATIC VoidPtr ke_find_unused_heap(Int32 flags); - STATIC Void ke_free_heap_internal(VoidPtr vaddr); - STATIC VoidPtr ke_make_heap_internal(VoidPtr vaddr, Int32 flags); - STATIC Boolean ke_check_and_free_heap(const SizeT& index, VoidPtr ptr); - - /// @brief Find an unused heap header to allocate on. - /// @param flags the flags to use. - /// @return VoidPtr the heap pointer. - STATIC VoidPtr ke_find_unused_heap(Int32 flags) - { - for (SizeT index = 0; index < kUserHeapMaxSz; ++index) - { - if (UserHeapManager::The()[index] && - !UserHeapManager::The()[index].Leak().Leak().Present()) - { - UserHeapManager::Leak().Leak().TogglePresent( - UserHeapManager::The()[index].Leak().Leak(), true); - kcout << "[ke_find_unused_heap] Done, trying to make a pool now...\r"; - - return ke_make_heap_internal( - (VoidPtr)UserHeapManager::The()[index].Leak().Leak().VirtualAddress(), - flags); - } - } - - return nullptr; - } - - /// @brief Makes a new heap for the process to use. - /// @param virtualAddress the virtual address of the process. - /// @param flags the flags. - /// @return - STATIC VoidPtr ke_make_heap_internal(VoidPtr virtualAddress, Int32 flags) - { - if (virtualAddress) - { - UserHeapHeader* poolHdr = reinterpret_cast(virtualAddress); - - if (!poolHdr->fFree) - { - kcout - << "[ke_make_heap_internal] poolHdr->fFree, HeapPtr already exists\n"; - return nullptr; - } - - poolHdr->fFlags = flags; - poolHdr->fMagic = kUserHeapMag; - poolHdr->fFree = false; - - kcout << "[ke_make_heap_internal] New allocation has been done.\n"; - return reinterpret_cast( - (reinterpret_cast(virtualAddress) + sizeof(UserHeapHeader))); - } - - kcout << "[ke_make_heap_internal] Address is invalid"; - return nullptr; - } - - /// @brief Internally makrs the heap as free. - /// This is done by setting the fFree bit to true - /// @param virtualAddress - /// @return - STATIC Void ke_free_heap_internal(VoidPtr virtualAddress) - { - UserHeapHeader* poolHdr = reinterpret_cast( - reinterpret_cast(virtualAddress) - sizeof(UserHeapHeader)); - - if (poolHdr->fMagic == kUserHeapMag) - { - if (!poolHdr->fFree) - { - ProcessScheduler::The().Leak().TheCurrent().Leak().Crash(); - return; - } - - poolHdr->fFree = true; - poolHdr->fFlags = 0; - - kcout << "[ke_free_heap_internal] Successfully marked header as free!\r"; - } - } - - /** - * @brief Check for the ptr and frees it. - * - * @param index Where to look at. - * @param ptr The ptr to check. - * @return Boolean true if successful. - */ - STATIC Boolean ke_check_and_free_heap(const SizeT& index, VoidPtr ptr) - { - if (UserHeapManager::The()[index]) - { - // ErrorOr<>::operator Boolean - /// if (address matches) - /// -> Free heap. - if (UserHeapManager::The()[index].Leak().Leak().VirtualAddress() == - (UIntPtr)ptr) - { - UserHeapManager::Leak().Leak().FreePage( - UserHeapManager::The()[index].Leak().Leak()); - - --UserHeapManager::Count(); - - ke_free_heap_internal(ptr); - ptr = nullptr; - - return true; - } - } - - return false; - } - - /// @brief Creates a new pool pointer. - /// @param flags the flags attached to it. - /// @return a pool pointer with selected permissions. - VoidPtr rt_new_heap(Int32 flags) - { - if (!UserHeapManager::IsEnabled()) - return nullptr; - - if (UserHeapManager::Count() > kUserHeapMaxSz) - return nullptr; - - if (VoidPtr ret = ke_find_unused_heap(flags)) - return ret; - - // this wasn't set to true - auto ref_page = UserHeapManager::Leak().Leak().RequestPage( - ((flags & kUserHeapUser)), (flags & kUserHeapRw)); - - if (ref_page) - { - ///! reserve page. - UserHeapManager::The()[UserHeapManager::Count()].Leak() = ref_page; - auto& ref = UserHeapManager::Count(); - - ++ref; // increment the number of addresses we have now. - - // finally make the pool address. - return ke_make_heap_internal( - reinterpret_cast(ref_page.Leak().VirtualAddress()), flags); - } - - return nullptr; - } - - /// @brief free a pool pointer. - /// @param ptr The pool pointer to free. - /// @return status code - Int32 rt_free_heap(VoidPtr ptr) - { - if (!UserHeapManager::IsEnabled()) - return -1; - - if (ptr) - { - SizeT base = UserHeapManager::Count(); - - if (ke_check_and_free_heap(base, ptr)) - return 0; - - for (SizeT index = 0; index < kUserHeapMaxSz; ++index) - { - if (ke_check_and_free_heap(index, ptr)) - return 0; - - --base; - } - } - - return -1; - } -} // namespace Kernel -- cgit v1.2.3