Luna/kernel/src/memory/UserVM.cpp
apio df95126ccd
All checks were successful
continuous-integration/drone/push Build is passing
kernel: Remove unneeded debug logs & random cleanups
2023-04-14 21:10:38 +02:00

123 lines
3.1 KiB
C++

#include "memory/UserVM.h"
#include "Log.h"
#include "arch/MMU.h"
#include "memory/Heap.h"
#include <luna/CString.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);
}
Result<OwnedPtr<UserVM>> UserVM::clone()
{
void* const base = TRY(kmalloc(m_bitmap.size_in_bytes()));
auto guard = make_scope_guard([&] { kfree(base); });
OwnedPtr<UserVM> ptr = TRY(make_owned<UserVM>(base, m_bitmap.size_in_bytes()));
memcpy(ptr->m_bitmap.location(), m_bitmap.location(), m_bitmap.size_in_bytes());
guard.deactivate();
return move(ptr);
}
UserVM::UserVM(void* base, usize 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);
return true;
}
Result<u64> UserVM::alloc_one_page()
{
u64 index;
bool ok = m_bitmap.find_and_toggle(false).try_set_value(index);
if (!ok)
{
bool success = TRY(try_expand());
if (!success) return err(ENOMEM);
index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle(false), ENOMEM));
}
return VM_BASE + index * ARCH_PAGE_SIZE;
}
Result<u64> UserVM::alloc_several_pages(usize count)
{
u64 index;
bool ok = m_bitmap.find_and_toggle_region(false, count).try_set_value(index);
if (!ok)
{
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));
}
return VM_BASE + index * ARCH_PAGE_SIZE;
}
Result<bool> 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);
// NOTE: POSIX says munmap() should silently do nothing if the address is not mapped, instead of throwing an error
// like EFAULT.
if (!m_bitmap.get(index)) return false;
m_bitmap.set(index, false);
return true;
}
Result<bool> 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);
// NOTE: Same as above.
if (!TRY(m_bitmap.try_match_region(index, count, true))) return false;
m_bitmap.clear_region(index, count, false);
return true;
}
UserVM::~UserVM()
{
m_bitmap.deallocate();
}