Luna/kernel/src/memory/UserVM.cpp
apio 944d32de36
All checks were successful
continuous-integration/drone/push Build is passing
Bitmap: Introduce new malloc-aware initialization functions
Lets us call resize(new_size) instead of initialize(realloc(location, new_size), new_size)
2023-01-21 23:16:50 +01:00

112 lines
2.9 KiB
C++

#include "memory/UserVM.h"
#include "Log.h"
#include "arch/MMU.h"
#include "memory/Heap.h"
#include <luna/ScopeGuard.h>
static constexpr u64 VM_BASE = 0x10000000;
static constexpr usize INITIAL_VM_SIZE = 80;
static constexpr usize MAX_VM_SIZE = 1024 * 1024 * 16;
Result<OwnedPtr<UserVM>> UserVM::try_create()
{
void* const base = TRY(kmalloc(INITIAL_VM_SIZE));
auto guard = make_scope_guard([&] { kfree(base); });
OwnedPtr<UserVM> ptr = TRY(make_owned<UserVM>(base, INITIAL_VM_SIZE));
guard.deactivate();
return move(ptr);
}
UserVM::UserVM(void* base, usize size)
{
kdbgln("user vm created with base=%p, size=%zu", base, size);
m_bitmap.initialize(base, size);
m_bitmap.clear(false);
}
Result<bool> UserVM::try_expand(usize size)
{
if (m_bitmap.size_in_bytes() == MAX_VM_SIZE) { return false; }
const usize old_size = m_bitmap.size_in_bytes();
usize new_size = old_size + size;
if (new_size > MAX_VM_SIZE) new_size = MAX_VM_SIZE;
m_bitmap.resize(new_size);
m_bitmap.clear_region(old_size * 8, (new_size - old_size) * 8, false);
kdbgln("user vm expanded to base=%p, size=%zu", m_bitmap.location(), new_size);
return true;
}
Result<u64> UserVM::alloc_one_page()
{
u64 index;
const auto maybe_index = m_bitmap.find_and_toggle(false);
if (!maybe_index.has_value())
{
bool success = TRY(try_expand());
if (!success) return err(ENOMEM);
index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle(false), ENOMEM));
}
else
index = maybe_index.value();
return VM_BASE + index * ARCH_PAGE_SIZE;
}
Result<u64> UserVM::alloc_several_pages(usize count)
{
u64 index;
const auto maybe_index = m_bitmap.find_and_toggle_region(false, count);
if (!maybe_index.has_value())
{
bool success = TRY(try_expand((count / 8) + INITIAL_VM_SIZE));
if (!success) return err(ENOMEM);
index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle_region(false, count), ENOMEM));
}
else
index = maybe_index.value();
return VM_BASE + index * ARCH_PAGE_SIZE;
}
Result<void> UserVM::free_one_page(u64 address)
{
if (address < VM_BASE) return err(EINVAL);
const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE;
if (index > (MAX_VM_SIZE * 8)) return err(EINVAL);
if (!m_bitmap.get(index)) return err(EFAULT);
m_bitmap.set(index, false);
return {};
}
Result<void> UserVM::free_several_pages(u64 address, usize count)
{
if (address < VM_BASE) return err(EINVAL);
const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE;
if ((index + count) > (MAX_VM_SIZE * 8)) return err(EINVAL);
if (!m_bitmap.match_region(index, count, true)) return err(EFAULT);
m_bitmap.clear_region(index, count, false);
return {};
}
UserVM::~UserVM()
{
kdbgln("user vm destroyed: base=%p, size=%zu", m_bitmap.location(), m_bitmap.size_in_bytes());
m_bitmap.deallocate();
}