diff --git a/src/memory/FrameAllocator.cc b/src/memory/FrameAllocator.cc index 0250503..3dc0a10 100644 --- a/src/memory/FrameAllocator.cc +++ b/src/memory/FrameAllocator.cc @@ -10,6 +10,7 @@ #include "kstd/Memory.hh" #include "kstd/PrintFormat.hh" #include "memory/FrameAllocator.hh" +#include "memory/Memory.hh" namespace kernel { @@ -23,16 +24,68 @@ void FrameAllocator::initialize(const StartupInformation& startupInformation) { // Page frame bitmap starts immediately after the kernel. - mBitmap = reinterpret_cast(startupInformation.kernelEnd); + mBitmap = reinterpret_cast(startupInformation.kernelEnd); - const u32 pageSize = startupInformation.pageSize; - const u32 numberOfPages = startupInformation.multibootInformation->memoryKB() * 1024 / pageSize; - mBitmapSize = numberOfPages / (sizeof(FrameBitmap) * 8); + const u32 numberOfPages = startupInformation.memorySize() / memory::pageSize; + const u32 pagesPerBitmap = Bitmap::length; + + mBitmapSize = numberOfPages / pagesPerBitmap; + if ((numberOfPages % pagesPerBitmap) != 0) { + // Add an extra bitmap for the last few pages. + mBitmapSize++; + } kstd::printFormat("Allocated bitmap of %ld bytes for %ld pages at 0x%08lX\n", mBitmapSize, numberOfPages, u32(mBitmap)); // TODO: Before modifying this memory, maybe make sure none of the multiboot information is hanging out there? + kstd::Memory::zero(mBitmap, mBitmapSize); + + // Lower 1 MB is always allocated. + reserveRange(0, 0x100000); + // Kernel image (including this frame bitmap) is always allocated. + reserveRange(startupInformation.kernelStart, startupInformation.kernelSize() + mBitmapSize); +} + +void +FrameAllocator::reserveRange(u32 start, + u32 length) +{ + // TODO: `start` and `length` validation. + const u32 pagesPerBitmap = Bitmap::length; + + const u32 startPage = memory::pageAlignDown(start) / memory::pageSize; + const u32 endPage = memory::pageAlignUp(start + length) / memory::pageSize; + + // Iterators + u32 page = startPage; + u32 bitmapIndex = start / pagesPerBitmap; + u8 bitmapOffset = start % pagesPerBitmap; + + kstd::printFormat("Reserving %ld pages for memory addresses between 0x%08lX and 0x%08lX\n", endPage - startPage, start, start + length); + + // Fill in any entries that aren't aligned to pagesPerBitmap at the beginning. + while (bitmapOffset != 0) { + mBitmap[bitmapIndex].set(bitmapOffset); + bitmapOffset = (bitmapOffset + 1) % 8; + page++; + if (bitmapOffset == 0) { + bitmapIndex++; + } + } + + // Fill in entries in `pagesPerBitmap` sized chunks. + while ((endPage - page) > pagesPerBitmap) { + mBitmap[bitmapIndex++].fill(); + page += pagesPerBitmap; + } + + // Fill in any entries that aren't aligned to `pagesPerBitmap` at the end of the range. + while ((endPage - page) > 0) { + mBitmap[bitmapIndex].set(bitmapOffset); + bitmapOffset = (bitmapOffset + 1) % 8; + page++; + } } } /* namespace kernel */ diff --git a/src/memory/FrameAllocator.hh b/src/memory/FrameAllocator.hh index 5d99937..7496fec 100644 --- a/src/memory/FrameAllocator.hh +++ b/src/memory/FrameAllocator.hh @@ -10,9 +10,9 @@ #define __MEMORY_FRAMEALLOCATOR_HH__ #include "StartupInformation.hh" +#include "kstd/Bitmap.hh" #include "kstd/Types.hh" - namespace kernel { struct FrameAllocator @@ -22,12 +22,15 @@ struct FrameAllocator void initialize(const StartupInformation& startupInformation); private: - typedef u8 FrameBitmap; + typedef kstd::Bitmap Bitmap; /** Starting address of the frame allocation bitmap. */ - FrameBitmap* mBitmap; - /** Size of the bitmap in bytes. */ + Bitmap* mBitmap; + /** Size of the bitmap in `sizeof(Bitmap)` units. */ u32 mBitmapSize; + + /** Reserve a range of memory. */ + void reserveRange(u32 start, u32 length); }; } /* namespace */