Kernel: Add barebones GeneralAllocator for >4096B
This commit is contained in:
parent
f1667b398a
commit
512be884ed
|
@ -26,6 +26,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/InterruptController.cpp
|
kernel/InterruptController.cpp
|
||||||
kernel/kernel.cpp
|
kernel/kernel.cpp
|
||||||
kernel/Memory/FixedWidthAllocator.cpp
|
kernel/Memory/FixedWidthAllocator.cpp
|
||||||
|
kernel/Memory/GeneralAllocator.cpp
|
||||||
kernel/Memory/Heap.cpp
|
kernel/Memory/Heap.cpp
|
||||||
kernel/Memory/kmalloc.cpp
|
kernel/Memory/kmalloc.cpp
|
||||||
kernel/Panic.cpp
|
kernel/Panic.cpp
|
||||||
|
|
|
@ -312,7 +312,7 @@ namespace Kernel
|
||||||
|
|
||||||
// Find any free page page (except for page 0)
|
// Find any free page page (except for page 0)
|
||||||
vaddr_t address = PAGE_SIZE;
|
vaddr_t address = PAGE_SIZE;
|
||||||
while ((address << 48) == 0)
|
while ((address >> 48) == 0)
|
||||||
{
|
{
|
||||||
if (!(get_page_flags(address) & Flags::Present))
|
if (!(get_page_flags(address) & Flags::Present))
|
||||||
return address;
|
return address;
|
||||||
|
@ -322,6 +322,27 @@ namespace Kernel
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vaddr_t MMU::get_free_contiguous_pages(size_t page_count) const
|
||||||
|
{
|
||||||
|
for (vaddr_t address = PAGE_SIZE; !(address >> 48); address += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
bool valid { true };
|
||||||
|
for (size_t page = 0; page < page_count; page++)
|
||||||
|
{
|
||||||
|
if (get_page_flags(address + page * PAGE_SIZE) & Flags::Present)
|
||||||
|
{
|
||||||
|
address += page;
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid)
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
bool MMU::is_page_free(vaddr_t page) const
|
bool MMU::is_page_free(vaddr_t page) const
|
||||||
{
|
{
|
||||||
ASSERT(page % PAGE_SIZE == 0);
|
ASSERT(page % PAGE_SIZE == 0);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/LinkedList.h>
|
||||||
|
#include <kernel/Memory/Heap.h>
|
||||||
|
#include <kernel/Memory/MMU.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class GeneralAllocator
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(GeneralAllocator);
|
||||||
|
BAN_NON_MOVABLE(GeneralAllocator);
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeneralAllocator(MMU&);
|
||||||
|
~GeneralAllocator();
|
||||||
|
|
||||||
|
vaddr_t allocate(size_t);
|
||||||
|
bool deallocate(vaddr_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Allocation
|
||||||
|
{
|
||||||
|
vaddr_t address { 0 };
|
||||||
|
BAN::Vector<paddr_t> pages;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
MMU& m_mmu;
|
||||||
|
BAN::LinkedList<Allocation> m_allocations;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -24,10 +24,10 @@ namespace Kernel
|
||||||
~MMU();
|
~MMU();
|
||||||
|
|
||||||
void identity_map_page(paddr_t, flags_t);
|
void identity_map_page(paddr_t, flags_t);
|
||||||
void identity_map_range(paddr_t, size_t, flags_t);
|
void identity_map_range(paddr_t, size_t bytes, flags_t);
|
||||||
|
|
||||||
void unmap_page(vaddr_t);
|
void unmap_page(vaddr_t);
|
||||||
void unmap_range(vaddr_t, size_t);
|
void unmap_range(vaddr_t, size_t bytes);
|
||||||
|
|
||||||
void map_page_at(paddr_t, vaddr_t, flags_t);
|
void map_page_at(paddr_t, vaddr_t, flags_t);
|
||||||
|
|
||||||
|
@ -35,10 +35,10 @@ namespace Kernel
|
||||||
flags_t get_page_flags(vaddr_t) const;
|
flags_t get_page_flags(vaddr_t) const;
|
||||||
|
|
||||||
bool is_page_free(vaddr_t) const;
|
bool is_page_free(vaddr_t) const;
|
||||||
bool is_range_free(vaddr_t, size_t) const;
|
bool is_range_free(vaddr_t, size_t bytes) const;
|
||||||
|
|
||||||
vaddr_t get_free_page() const;
|
vaddr_t get_free_page() const;
|
||||||
vaddr_t get_free_contiguous_pages(uint32_t) const;
|
vaddr_t get_free_contiguous_pages(size_t page_count) const;
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/FS/Inode.h>
|
#include <kernel/FS/Inode.h>
|
||||||
#include <kernel/Memory/FixedWidthAllocator.h>
|
#include <kernel/Memory/FixedWidthAllocator.h>
|
||||||
|
#include <kernel/Memory/GeneralAllocator.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/MMU.h>
|
#include <kernel/Memory/MMU.h>
|
||||||
#include <kernel/SpinLock.h>
|
#include <kernel/SpinLock.h>
|
||||||
|
@ -95,6 +96,7 @@ namespace Kernel
|
||||||
BAN::Vector<Thread*> m_threads;
|
BAN::Vector<Thread*> m_threads;
|
||||||
|
|
||||||
BAN::LinkedList<FixedWidthAllocator> m_fixed_width_allocators;
|
BAN::LinkedList<FixedWidthAllocator> m_fixed_width_allocators;
|
||||||
|
GeneralAllocator* m_general_allocator;
|
||||||
|
|
||||||
MMU* m_mmu { nullptr };
|
MMU* m_mmu { nullptr };
|
||||||
TTY* m_tty { nullptr };
|
TTY* m_tty { nullptr };
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include <kernel/Memory/GeneralAllocator.h>
|
||||||
|
#include <kernel/Process.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
GeneralAllocator::GeneralAllocator(MMU& mmu)
|
||||||
|
: m_mmu(mmu)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
GeneralAllocator::~GeneralAllocator()
|
||||||
|
{
|
||||||
|
while (!m_allocations.empty())
|
||||||
|
deallocate(m_allocations.front().address);
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr_t GeneralAllocator::allocate(size_t bytes)
|
||||||
|
{
|
||||||
|
size_t needed_pages = BAN::Math::div_round_up<size_t>(bytes, PAGE_SIZE);
|
||||||
|
|
||||||
|
Allocation allocation;
|
||||||
|
if (allocation.pages.resize(needed_pages, 0).is_error())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < needed_pages; i++)
|
||||||
|
{
|
||||||
|
paddr_t paddr = Heap::get().take_free_page();
|
||||||
|
if (paddr == 0)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < i; j++)
|
||||||
|
Heap::get().release_page(allocation.pages[j]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
allocation.pages[i] = paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocation.address = m_mmu.get_free_contiguous_pages(needed_pages);
|
||||||
|
for (size_t i = 0; i < needed_pages; i++)
|
||||||
|
m_mmu.map_page_at(allocation.pages[i], allocation.address + i * PAGE_SIZE, MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present);
|
||||||
|
|
||||||
|
MUST(m_allocations.push_back(BAN::move(allocation)));
|
||||||
|
return allocation.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GeneralAllocator::deallocate(vaddr_t address)
|
||||||
|
{
|
||||||
|
for (auto it = m_allocations.begin(); it != m_allocations.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->address != address)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_mmu.unmap_range(it->address, it->pages.size() * PAGE_SIZE);
|
||||||
|
for (auto paddr : it->pages)
|
||||||
|
Heap::get().release_page(paddr);
|
||||||
|
|
||||||
|
m_allocations.remove(it);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -118,6 +118,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
ASSERT(m_threads.empty());
|
ASSERT(m_threads.empty());
|
||||||
ASSERT(m_fixed_width_allocators.empty());
|
ASSERT(m_fixed_width_allocators.empty());
|
||||||
|
ASSERT(m_general_allocator == nullptr);
|
||||||
if (m_mmu)
|
if (m_mmu)
|
||||||
{
|
{
|
||||||
MMU::get().load();
|
MMU::get().load();
|
||||||
|
@ -152,6 +153,11 @@ namespace Kernel
|
||||||
|
|
||||||
// NOTE: We must clear allocators while the mmu is still alive
|
// NOTE: We must clear allocators while the mmu is still alive
|
||||||
m_fixed_width_allocators.clear();
|
m_fixed_width_allocators.clear();
|
||||||
|
if (m_general_allocator)
|
||||||
|
{
|
||||||
|
delete m_general_allocator;
|
||||||
|
m_general_allocator = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
dprintln("process {} exit", pid());
|
dprintln("process {} exit", pid());
|
||||||
s_process_lock.lock();
|
s_process_lock.lock();
|
||||||
|
@ -385,6 +391,8 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void*> Process::allocate(size_t bytes)
|
BAN::ErrorOr<void*> Process::allocate(size_t bytes)
|
||||||
{
|
{
|
||||||
|
vaddr_t address = 0;
|
||||||
|
|
||||||
if (bytes <= PAGE_SIZE)
|
if (bytes <= PAGE_SIZE)
|
||||||
{
|
{
|
||||||
// Do fixed width allocation
|
// Do fixed width allocation
|
||||||
|
@ -393,18 +401,40 @@ namespace Kernel
|
||||||
|
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
for (auto& allocator : m_fixed_width_allocators)
|
bool needs_new_allocator { true };
|
||||||
if (allocator.allocation_size() == allocation_size && allocator.allocations() < allocator.max_allocations())
|
|
||||||
return (void*)allocator.allocate();
|
|
||||||
|
|
||||||
MUST(m_fixed_width_allocators.emplace_back(mmu(), allocation_size));
|
for (auto& allocator : m_fixed_width_allocators)
|
||||||
return (void*)m_fixed_width_allocators.back().allocate();
|
{
|
||||||
|
if (allocator.allocation_size() == allocation_size && allocator.allocations() < allocator.max_allocations())
|
||||||
|
{
|
||||||
|
address = allocator.allocate();
|
||||||
|
needs_new_allocator = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_new_allocator)
|
||||||
|
{
|
||||||
|
TRY(m_fixed_width_allocators.emplace_back(mmu(), allocation_size));
|
||||||
|
address = m_fixed_width_allocators.back().allocate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Do general allocation
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
|
if (!m_general_allocator)
|
||||||
|
{
|
||||||
|
m_general_allocator = new GeneralAllocator(mmu());
|
||||||
|
if (m_general_allocator == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address = m_general_allocator->allocate(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
return (void*)address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::free(void* ptr)
|
void Process::free(void* ptr)
|
||||||
|
@ -422,6 +452,10 @@ namespace Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_general_allocator && m_general_allocator->deallocate((vaddr_t)ptr))
|
||||||
|
return;
|
||||||
|
|
||||||
dwarnln("free called on pointer that was not allocated");
|
dwarnln("free called on pointer that was not allocated");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define N 512
|
#define N 1024
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue