From 51b6c13b161f58ae4a94848dd9f818167b406ab5 Mon Sep 17 00:00:00 2001 From: Nathan Giddings Date: Sun, 4 Apr 2021 19:05:26 -0500 Subject: [PATCH] Rewrote page allocator; now allocate one at a time --- src/pageallocator.cpp | 270 ------------------------------------- src/pageallocator.hpp | 107 +-------------- src/pageallocatorstack.cpp | 52 +++++++ src/pageallocatorstack.hpp | 34 +++++ 4 files changed, 92 insertions(+), 371 deletions(-) delete mode 100755 src/pageallocator.cpp create mode 100644 src/pageallocatorstack.cpp create mode 100644 src/pageallocatorstack.hpp diff --git a/src/pageallocator.cpp b/src/pageallocator.cpp deleted file mode 100755 index 43ea72b..0000000 --- a/src/pageallocator.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "pageallocator.hpp" -#include "systypes.hpp" -#include "memorymap.hpp" -#include "memorytype.hpp" - -#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m))) - -uint32_t ilog2(uint32_t n, bool roundUp) -{ - uint32_t m = n; - uint32_t count = 0; - bool isPowerOfTwo = true; - while(m) - { - if((m & 1) == 1 && m > 1) - { - isPowerOfTwo = false; - } - count++; - m >>= 1; - } - return count - (isPowerOfTwo ? 1 : (roundUp ? 0 : 1)); -} - -kernelns::BuddyAllocator::BuddyAllocator() -{ - -} - -kernelns::BuddyAllocator::BuddyAllocator(const kernelns::MemoryMap& memmap, - char* bitmap, size_t blockCount, - size_t treeHeight) -{ - this->bitmap = bitmap; - this->blockSize = 4096; - this->blockCount = blockCount; - this->treeHeight = treeHeight; - for(size_t i = 0; i <= treeHeight; i++) - { - for(size_t j = 0; j < (blockCount >> i); j++) - { - reserveNode(i, j); - } - } - physaddr_t location = 0x100000; - for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++) - { - if(memmap[i].getType() != (unsigned int) MemoryType::Available) - continue; - if(memmap[i].getLocation() > location) - location = roundUp(memmap[i].getLocation(), 4096); - while(memmap[i].contains(location, 4096)) - { - freeNode(0, location / 4096); - if(isFree(0, getBuddy(location / 4096))) - merge(0, location / 4096); - location += 4096; - } - } -} - -kernelns::BuddyAllocator::BuddyAllocator(char* bitmap, size_t blockSize, - size_t blockCount, size_t treeHeight) -{ - this->bitmap = bitmap; - this->blockSize = blockSize; - this->blockCount = blockCount; - this->treeHeight = treeHeight; - for(size_t i = 0; i <= treeHeight; i++) - { - for(size_t j = 0; j < (blockCount >> i); j++) - { - if(i < treeHeight) - reserveNode(i, j); - else - freeNode(i, j); - } - } -} - -physaddr_t kernelns::BuddyAllocator::allocate(size_t size) -{ - size_t height = ilog2(roundUp(size, blockSize) / blockSize, true); - if(height > treeHeight) // Requested block size is greater than maximum - { - return 0; - } - else - { - size_t index = findFreeBlock(height); - if(index == INVALID) // Failed to find a big enough free block; out of memory - { - return 0; - } - else - { - reserveNode(height, index); - return nodeToAddress(height, index); - } - } -} - -void kernelns::BuddyAllocator::free(physaddr_t location, size_t size) -{ - size_t height = ilog2(roundUp(size, blockSize) / blockSize, true); - if(height <= treeHeight) - { - size_t index = addressToNode(height, location); - freeNode(height, index); - if(isFree(height, getBuddy(index))) - { - merge(height, index); - } - } -} - -size_t kernelns::BuddyAllocator::freeBlocks() const -{ - size_t count = 0; - for(size_t j = 0; j < blockCount; j++) - { - if(isFree(0, j)) - { - count++; - } - } - return count; -} - -size_t kernelns::BuddyAllocator::maxAllocationSize() const -{ - for(size_t i = treeHeight; i >= 0; i--) - { - for(size_t j = 0; j < (blockCount >> i); j++) - { - if(isFree(i, j)) - { - return 1 << i; - } - } - } - return 0; -} - -size_t kernelns::BuddyAllocator::getBlockSize() const -{ - return blockSize; -} - -size_t kernelns::BuddyAllocator::getMemorySize() const -{ - return blockCount; -} - -size_t kernelns::BuddyAllocator::findFreeBlock(size_t height) -{ - for(size_t i = 0; i < (blockCount >> height); i++) - { - if(isFree(height, i)) - { - return i; - } - } - if(height < treeHeight) - { - size_t parentIndex = findFreeBlock(height + 1); - if(parentIndex != INVALID) - { - return split(height + 1, parentIndex); - } - } - return INVALID; -} - -size_t kernelns::BuddyAllocator::split(size_t height, size_t index) -{ - if(height > 0 && isFree(height, index)) - { - reserveNode(height, index); - freeNode(height - 1, getChild(index)); - freeNode(height - 1, getBuddy(getChild(index))); - return getChild(index); - } - else - { - return INVALID; - } -} - -size_t kernelns::BuddyAllocator::merge(size_t height, size_t index) -{ - if(isFree(height, index) && isFree(height, getBuddy(index)) && height < treeHeight) - { - reserveNode(height, index); - reserveNode(height, getBuddy(index)); - freeNode(height + 1, getParent(index)); - if((height + 1) < treeHeight) - { - if(isFree(height + 1, getBuddy(getParent(index)))) - { - return merge(height + 1, getParent(index)); - - } - } - return getParent(index); - } - else - { - return INVALID; - } -} - -size_t kernelns::BuddyAllocator::getBuddy(size_t index) -{ - return index ^ 1; -} - -size_t kernelns::BuddyAllocator::getParent(size_t index) -{ - return index / 2; -} - -size_t kernelns::BuddyAllocator::getChild(size_t index) -{ - return index * 2; -} - -physaddr_t kernelns::BuddyAllocator::nodeToAddress(size_t height, size_t index) - const -{ - return index * (blockSize << height); -} - -size_t kernelns::BuddyAllocator::addressToNode(size_t height, - physaddr_t location) const -{ - return location / (blockSize << height); -} - -void kernelns::BuddyAllocator::reserveNode(size_t height, size_t index) -{ - size_t bit = (height == 0) ? 0 - : ((blockCount * 2) - (blockCount >> (height - 1))); - bit += index; - bitmap[bit / 8] |= 1 << (bit % 8); -} - -void kernelns::BuddyAllocator::freeNode(size_t height, size_t index) -{ - size_t bit = (height == 0) ? 0 - : ((blockCount * 2) - (blockCount >> (height - 1))); - bit += index; - bitmap[bit / 8] &= ~(1 << (bit % 8)); -} - -bool kernelns::BuddyAllocator::isFree(size_t height, size_t index) const -{ - size_t bit = (height == 0) ? 0 - : ((blockCount * 2) - (blockCount >> (height - 1))); - bit += index; - char data = bitmap[bit / 8] & (1 << (bit % 8)); - if(data == 0) - { - return true; - } - else - { - return false; - } -} diff --git a/src/pageallocator.hpp b/src/pageallocator.hpp index 15b1ce5..2e600a7 100755 --- a/src/pageallocator.hpp +++ b/src/pageallocator.hpp @@ -3,46 +3,33 @@ #include #include "systypes.hpp" -#include "memorymap.hpp" namespace kernelns { /** - * Interface for a dymanic memory allocator. + * Interface for a physical memory allocator. */ class PageAllocator { public: /** - * Allocate a block of memory containing 'size' bytes. May round up - * depending on the implementation. + * Allocate a single page, returning its physical address. Upon failure, + * returns an error code such that the least signifigant byte is nonzero. */ - virtual physaddr_t allocate(size_t size) = 0; + virtual physaddr_t next() = 0; /** - * Free the region of memory starting at 'location' and containing - * 'size' bytes. + * Frees a single page that has previously been allocated. */ - virtual void free(physaddr_t location, size_t size) = 0; + virtual void free(physaddr_t location) = 0; /** * @returns the total number of free blocks of memory. */ virtual size_t freeBlocks() const = 0; - /** - * @returns the size in blocks of the largest possible allocation that - * will not fail due to lack of memory. - */ - virtual size_t maxAllocationSize() const = 0; - - /** - * @returns the size in bytes of a single block. - */ - virtual size_t getBlockSize() const = 0; - /** * @returns the total number of blocks managed by this memory * allocator. @@ -50,88 +37,6 @@ public: virtual size_t getMemorySize() const = 0; }; - -class BuddyAllocator : public PageAllocator -{ -public: - - BuddyAllocator(); - - BuddyAllocator(const MemoryMap& memmap, char* bitmap, size_t blockCount, - size_t treeHeight); - - BuddyAllocator(char* bitmap, size_t blockSize, size_t blockCount, - size_t treeHeight); - - /** - * Allocate a block of memory containing at least 'size' bytes. - * Rounds up to the nearest power of 2 times the size of a block. - */ - virtual physaddr_t allocate(size_t size); - - /** - * Free the region of memory starting at 'location' and containing - * 'size' bytes. - */ - virtual void free(physaddr_t location, size_t size); - - /** - * @returns the total number of free blocks of memory. - */ - virtual size_t freeBlocks() const; - - /** - * @returns the size in blocks of the largest possible allocation that - * will not fail due to lack of memory. - */ - virtual size_t maxAllocationSize() const; - - /** - * @returns the size in bytes of a single block. - */ - virtual size_t getBlockSize() const; - - /** - * @returns the total number of blocks managed by this memory - * allocator. - */ - virtual size_t getMemorySize() const; - -private: - - static const size_t INVALID = (size_t) -1; - - char* bitmap; - - size_t blockSize; - - size_t blockCount; - - size_t treeHeight; - - size_t findFreeBlock(size_t height); - - size_t split(size_t height, size_t index); - - size_t merge(size_t height, size_t index); - - size_t getBuddy(size_t index); - - size_t getParent(size_t index); - - size_t getChild(size_t index); - - physaddr_t nodeToAddress(size_t height, size_t index) const; - - size_t addressToNode(size_t height, physaddr_t location) const; - - void reserveNode(size_t height, size_t index); - - void freeNode(size_t height, size_t index); - - bool isFree(size_t height, size_t index) const; - -}; } diff --git a/src/pageallocatorstack.cpp b/src/pageallocatorstack.cpp new file mode 100644 index 0000000..8425dcd --- /dev/null +++ b/src/pageallocatorstack.cpp @@ -0,0 +1,52 @@ +#include "pageallocatorstack.hpp" +#include "memorytype.hpp" + +using namespace kernelns; + +PageAllocatorStack::PageAllocatorStack(physaddr_t *stackBase, physaddr_t *stackTop, size_t frameSize, const MemoryMap& memoryMap) +{ + m_base = stackBase; + m_top = stackTop; + m_stack = m_base; + for(int i = 0; i < memoryMap.size(); i++) + { + if((MemoryType) memoryMap[i].getType() == MemoryType::Available) + { + for(int j = 0; j < memoryMap[i].getSize() / frameSize; j++) + { + free(memoryMap[i].getLocation() + j * frameSize); + } + } + } +} + +physaddr_t PageAllocatorStack::next() +{ + if(m_stack < m_base) + { + physaddr_t frame = *m_stack; + *m_stack = (physaddr_t) 0; + m_stack++; + return frame; + } + return (physaddr_t) -1; +} + +void PageAllocatorStack::free(physaddr_t location) +{ + if(m_stack > m_top) + { + m_stack--; + *m_stack = location; + } +} + +size_t PageAllocatorStack::freeBlocks() const +{ + return m_base - m_stack; +} + +size_t PageAllocatorStack::getMemorySize() const +{ + return m_totalSize; +} \ No newline at end of file diff --git a/src/pageallocatorstack.hpp b/src/pageallocatorstack.hpp new file mode 100644 index 0000000..f5710ed --- /dev/null +++ b/src/pageallocatorstack.hpp @@ -0,0 +1,34 @@ +#ifndef PAGEALLOCATORSTACK_H +#define PAGEALLOCATORSTACK_H + +#include "pageallocator.hpp" +#include "memorymap.hpp" + +namespace kernelns +{ + +class PageAllocatorStack : public PageAllocator +{ +public: + + PageAllocatorStack(physaddr_t *stackBase, physaddr_t *stackTop, size_t frameSize, const MemoryMap& memoryMap); + + virtual physaddr_t next(); + + virtual void free(physaddr_t location); + + virtual size_t freeBlocks() const; + + virtual size_t getMemorySize() const; + +private: + + size_t m_totalSize; + + physaddr_t *m_stack, *m_base, *m_top; + +}; + +} + +#endif \ No newline at end of file