Rewrote page allocator; now allocate one at a time
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,46 +3,33 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "systypes.hpp"
|
#include "systypes.hpp"
|
||||||
#include "memorymap.hpp"
|
|
||||||
|
|
||||||
namespace kernelns
|
namespace kernelns
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a dymanic memory allocator.
|
* Interface for a physical memory allocator.
|
||||||
*/
|
*/
|
||||||
class PageAllocator
|
class PageAllocator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a block of memory containing 'size' bytes. May round up
|
* Allocate a single page, returning its physical address. Upon failure,
|
||||||
* depending on the implementation.
|
* 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
|
* Frees a single page that has previously been allocated.
|
||||||
* 'size' bytes.
|
|
||||||
*/
|
*/
|
||||||
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.
|
* @returns the total number of free blocks of memory.
|
||||||
*/
|
*/
|
||||||
virtual size_t freeBlocks() const = 0;
|
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
|
* @returns the total number of blocks managed by this memory
|
||||||
* allocator.
|
* allocator.
|
||||||
@@ -51,88 +38,6 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
52
src/pageallocatorstack.cpp
Normal file
52
src/pageallocatorstack.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
34
src/pageallocatorstack.hpp
Normal file
34
src/pageallocatorstack.hpp
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user