diff options
Diffstat (limited to 'src/kernel/src/BitMapMgr.cc')
| -rw-r--r-- | src/kernel/src/BitMapMgr.cc | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/kernel/src/BitMapMgr.cc b/src/kernel/src/BitMapMgr.cc new file mode 100644 index 00000000..d7ecb810 --- /dev/null +++ b/src/kernel/src/BitMapMgr.cc @@ -0,0 +1,206 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifdef __NE_AMD64__ +#include <HALKit/AMD64/Paging.h> +#elif defined(__NE_ARM64__) +#include <HALKit/ARM64/Paging.h> +#endif + +#include <ArchKit/ArchKit.h> +#include <NeKit/KernelPanic.h> + +#define kBitMapMagic (0x10210U) + +#define kBitMapMagIdx (0U) +#define kBitMapSizeIdx (1U) +#define kBitMapUsedIdx (2U) + +///! @author Amlal El Mahrouss (amlal@nekernel.org) + +namespace Kernel { +namespace HAL { + namespace Detail { + /***********************************************************************************/ + /// \brief Proxy Interface to manage a bitmap allocator. + /***********************************************************************************/ + class IBitMapProxy final { + public: + explicit IBitMapProxy() = default; + ~IBitMapProxy() = default; + + NE_COPY_DELETE(IBitMapProxy) + + auto IsBitMap(VoidPtr page_ptr) -> Bool { + if (!page_ptr) return No; + + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(page_ptr); + + if (!ptr_bit_set[kBitMapMagIdx] || ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) return No; + + return Yes; + } + + auto FreeBitMap(VoidPtr page_ptr) -> Bool { + if (this->IsBitMap(page_ptr) == No) return No; + + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(page_ptr); + + kBitMapCursor += ptr_bit_set[kBitMapSizeIdx]; + + ptr_bit_set[kBitMapMagIdx] = kBitMapMagic; + ptr_bit_set[kBitMapUsedIdx] = No; + + this->GetBitMapStatus(ptr_bit_set); + + return Yes; + } + + UInt32 MakeMMFlags(Bool wr, Bool user) { + UInt32 flags = kMMFlagsPresent; + + if (wr) flags |= kMMFlagsWr; + if (user) flags |= kMMFlagsUser; + + return flags; + } + + /***********************************************************************************/ + /// @brief Iterate over availables bitmap, until we find a free entry. + /// @param base_ptr base pointer to look on. + /// @param size the size of the requested data structure. + /// @param wr is writable flag? + /// @param user is user flag? + /// @param pad additional padding added to **size** + /// @return The new free address, or nullptr. + /***********************************************************************************/ + auto FindBitMap(VoidPtr base_ptr, SizeT size, Bool wr, Bool user, SizeT pad) -> VoidPtr { + if (!size) return nullptr; + + if (kBitMapCursor > kKernelBitMpSize) { + err_global_get() = kErrorOutOfBitMapMemory; + + (Void)(kout << "Bitmap limit reached, can't allocate more bitmaps." << kendl); + return nullptr; + } + + VoidPtr base = reinterpret_cast<VoidPtr>((UIntPtr) base_ptr); + MUST_PASS(base); + + if (!base) return nullptr; + + STATIC SizeT biggest = 0UL; + + while (YES) { + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(base); + + if (ptr_bit_set[kBitMapMagIdx] == kBitMapMagic && + ptr_bit_set[kBitMapSizeIdx] == (size + pad)) { + if (ptr_bit_set[kBitMapUsedIdx] == No) { + ptr_bit_set[kBitMapSizeIdx] = size + pad; + ptr_bit_set[kBitMapUsedIdx] = Yes; + + this->GetBitMapStatus(ptr_bit_set); + + UInt32 flags = this->MakeMMFlags(wr, user); + mm_map_page(ptr_bit_set, (VoidPtr)mm_get_page_addr(ptr_bit_set), flags); + + if (biggest < (size + pad)) biggest = size + pad; + + kBitMapCursor += size + pad; + + return (VoidPtr) ptr_bit_set; + } + } else if (ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) { + ptr_bit_set[kBitMapMagIdx] = kBitMapMagic; + ptr_bit_set[kBitMapSizeIdx] = (size + pad); + ptr_bit_set[kBitMapUsedIdx] = Yes; + + this->GetBitMapStatus(ptr_bit_set); + + UInt32 flags = this->MakeMMFlags(wr, user); + mm_map_page(ptr_bit_set, (VoidPtr)mm_get_page_addr(ptr_bit_set), flags); + + if (biggest < (size + pad)) biggest = (size + pad); + + kBitMapCursor += size + pad; + + return (VoidPtr) ptr_bit_set; + } + + UIntPtr raw_base = reinterpret_cast<UIntPtr>(base); + UIntPtr offset = (ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) + ? (size + pad) + : ptr_bit_set[kBitMapSizeIdx]; + + base = reinterpret_cast<VoidPtr>(raw_base + offset); + if (base == nullptr) return nullptr; + } + + return nullptr; + } + + /// @brief Print Bitmap status + auto GetBitMapStatus(UIntPtr* ptr_bit_set) -> Void { + if (!this->IsBitMap(ptr_bit_set)) { + (Void)(kout << "Not a BitMap: " << hex_number((UIntPtr) ptr_bit_set) << kendl); + return; + } + + (Void)(kout << "Magic: " << hex_number(ptr_bit_set[kBitMapMagIdx]) << kendl); + (Void)(kout << "Is Allocated? " << (ptr_bit_set[kBitMapUsedIdx] ? "YES" : "NO") << kendl); + (Void)(kout << "Size of BitMap (B): " << number(ptr_bit_set[kBitMapSizeIdx]) << kendl); + (Void)(kout << "Size of BitMap (KIB): " << number(KIB(ptr_bit_set[kBitMapSizeIdx])) + << kendl); + (Void)(kout << "Size of BitMap (MIB): " << number(MIB(ptr_bit_set[kBitMapSizeIdx])) + << kendl); + (Void)(kout << "Size of BitMap (GIB): " << number(GIB(ptr_bit_set[kBitMapSizeIdx])) + << kendl); + (Void)(kout << "Size of BitMap (TIB): " << number(TIB(ptr_bit_set[kBitMapSizeIdx])) + << kendl); + (Void)(kout << "BitMap Address: " << hex_number((UIntPtr) ptr_bit_set) << kendl); + } + }; + } // namespace Detail + + STATIC Detail::IBitMapProxy kBitMapMgr; + + auto mm_is_bitmap(VoidPtr ptr) -> BOOL { + return kBitMapMgr.IsBitMap(ptr); + } + + /***********************************************************************************/ + /// @brief Allocate a new page to be used by the OS. + /// @param wr read/write bit. + /// @param user user bit. + /// @return a new bitmap allocated pointer. + /***********************************************************************************/ + auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page, SizeT pad) -> VoidPtr { + VoidPtr ptr_new = nullptr; + if (is_page) return nullptr; + + ptr_new = kBitMapMgr.FindBitMap(kKernelBitMpStart, size, wr, user, pad); + + if (!ptr_new) { + ke_panic(RUNTIME_CHECK_VIRTUAL_OUT_OF_MEM, "Out of memory bitmap"); + return nullptr; + } + + return ptr_new; + } + + /***********************************************************************************/ + /// @brief Free Bitmap, and mark it as absent. + /// @param ptr the pointer to free. + /***********************************************************************************/ + auto mm_free_bitmap(VoidPtr ptr) -> Bool { + if (!ptr) return No; + + Bool ret = kBitMapMgr.FreeBitMap(ptr); + return ret; + } +} // namespace HAL +} // namespace Kernel |
