Kernel: Add a Result class

This commit is contained in:
apio 2022-11-12 11:30:28 +01:00
parent a3465c2f5e
commit 662afad426
9 changed files with 176 additions and 26 deletions

View File

@ -1,9 +1,10 @@
#pragma once
#include "memory/Paging.h"
#include "utils/Result.h"
struct AddressSpace
{
static AddressSpace create();
static Result<AddressSpace> create();
void destroy();

View File

@ -1,15 +1,13 @@
#pragma once
#include "utils/Result.h"
#include <stdint.h>
#define PMM_FAILED (void*)-1
#define PMM_DID_FAIL(addr) (void*)addr == PMM_FAILED
namespace PMM
{
void init();
void* request_page();
void* request_pages(uint64_t count);
Result<void*> request_page();
Result<void*> request_pages(uint64_t count);
void free_page(void* address);
void free_pages(void* address, uint64_t count);

View File

@ -0,0 +1,125 @@
#pragma once
#include "std/ensure.h"
#include "std/string.h"
#include "utils/move.h"
#include "utils/new.h"
struct Error
{
Error(int err)
{
error = err;
}
int error;
};
template <typename T> class Result
{
public:
Result(const T& value)
{
m_storage.store_reference(value);
m_has_value = true;
m_has_error = false;
}
Result(T&& value)
{
m_storage.store_movable_reference(move(value));
m_has_value = true;
m_has_error = false;
}
Result(const Result<T>& other)
{
m_storage.store_reference(other.m_storage.fetch_reference());
m_has_value = true;
m_has_error = false;
}
Result(Result<T>&& other)
{
m_storage.store_movable_reference(move(other.m_storage.fetch_reference()));
m_has_value = true;
m_has_error = false;
}
Result(const Error& err)
{
m_error = err.error;
m_has_error = true;
m_has_value = false;
}
bool has_error()
{
return m_has_error;
}
bool has_value()
{
return m_has_value;
}
int error()
{
ensure(has_error());
return m_error;
}
Error release_error()
{
ensure(has_error());
return {m_error};
}
T value()
{
ensure(has_value());
return m_storage.fetch_reference();
}
T release_value()
{
ensure(has_value());
T item = m_storage.fetch_reference();
m_has_value = false;
return move(item);
}
private:
struct Storage
{
unsigned char buffer[sizeof(T)];
T* fetch_ptr()
{
return (T*)buffer;
}
T& fetch_reference()
{
return *fetch_ptr();
}
void store_ptr(T* ptr)
{
new (buffer) T(*ptr);
}
void store_reference(const T& ref)
{
new (buffer) T(ref);
}
void store_movable_reference(T&& ref)
{
new (buffer) T(ref);
}
};
Storage m_storage;
int m_error;
bool m_has_error;
bool m_has_value;
};

View File

@ -0,0 +1,13 @@
#pragma once
#include <stddef.h>
inline void* operator new(size_t, void* p) noexcept
{
return p;
}
inline void* operator new[](size_t, void* p) noexcept
{
return p;
}
inline void operator delete(void*, void*) noexcept {};
inline void operator delete[](void*, void*) noexcept {};

View File

@ -4,14 +4,17 @@
#include "log/Log.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "utils/move.h"
AddressSpace AddressSpace::create()
Result<AddressSpace> AddressSpace::create()
{
AddressSpace result;
result.m_pml4 = (PageTable*)PMM::request_page();
auto page = PMM::request_page();
if (page.has_error()) return page.release_error();
result.m_pml4 = (PageTable*)page.release_value();
memset(result.m_pml4, 0, PAGE_SIZE);
VMM::install_kernel_page_directory_into_address_space(result);
return move(result);
@ -156,8 +159,9 @@ void AddressSpace::clear()
static PageTable* try_clone_page_table(PageTable* source)
{
PageTable* dst = (PageTable*)PMM::request_page();
if (PMM_DID_FAIL(dst)) { return 0; }
auto page = PMM::request_page();
if (page.has_error()) { return 0; }
PageTable* dst = (PageTable*)page.release_value();
memcpy(dst, source, sizeof(PageTable));
return dst;
}

View File

@ -10,6 +10,8 @@
#include "misc/utils.h"
#include "std/ensure.h"
// FIXME: Use Result in here.
void MemoryManager::init()
{
KernelHeap::clear();
@ -123,15 +125,15 @@ void* MemoryManager::get_page(int flags)
void* MemoryManager::get_page_at(uint64_t addr, int flags)
{
void* physicalAddress = PMM::request_page();
if (PMM_DID_FAIL(physicalAddress))
auto paddr = PMM::request_page();
if (paddr.has_error())
{
#ifdef MM_DEBUG
kwarnln("OOM while allocating one page of memory. this is not good...");
#endif
return 0;
}
VMM::map(addr, (uint64_t)physicalAddress, flags);
VMM::map(addr, (uint64_t)paddr.release_value(), flags);
return (void*)addr;
}
@ -172,17 +174,19 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
#endif
for (uint64_t i = 0; i < count; i++)
{
void* physicalAddress = PMM::request_page();
if (PMM_DID_FAIL(physicalAddress)) // OOM: No physical memory available! Since this might be at the end of a
auto paddr = PMM::request_page();
if (paddr.has_error()) // OOM: No physical memory available! Since this might be at the end of a
// long allocation, we should be able to recover most of it and allocate a
// smaller range, so this might not be fatal.
{
#ifdef MM_DEBUG
kwarnln("OOM while allocating page %ld of memory. this might be recoverable...", i);
#endif
// FIXME: Weren't we supposed to free all previously allocated pages, to avoid leaks when failing large
// allocations?
return 0;
}
VMM::map(addr + (i * PAGE_SIZE), (uint64_t)physicalAddress, flags);
VMM::map(addr + (i * PAGE_SIZE), (uint64_t)paddr.release_value(), flags);
}
return (void*)addr;
}

View File

@ -7,6 +7,7 @@
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/ensure.h"
#include "std/errno.h"
#include "std/string.h"
extern BOOTBOOT bootboot;
@ -83,7 +84,7 @@ static void bitmap_set(uint64_t index, bool value)
if (value) { virtual_bitmap_addr[byteIndex] |= bitIndexer; }
}
void* PMM::request_page()
Result<void*> PMM::request_page()
{
for (uint64_t index = start_index; index < (bitmap_size * 8); index++)
{
@ -95,10 +96,10 @@ void* PMM::request_page()
return (void*)(index * PAGE_SIZE);
}
return PMM_FAILED;
return {ENOMEM};
}
void* PMM::request_pages(uint64_t count)
Result<void*> PMM::request_pages(uint64_t count)
{
uint64_t contiguous = 0;
uint64_t contiguous_start = 0;
@ -125,7 +126,7 @@ void* PMM::request_pages(uint64_t count)
}
}
return PMM_FAILED;
return {ENOMEM};
}
void PMM::free_page(void* address)

View File

@ -196,8 +196,9 @@ PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vadd
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
auto pde_create_if_not_present = [&]() {
pt = (PageTable*)PMM::request_page();
ensure(!(PMM_DID_FAIL(pt)));
auto pt_or_error = PMM::request_page();
ensure(pt_or_error.has_value());
pt = (PageTable*)pt_or_error.release_value();
memset(pt, 0, PAGE_SIZE);
pde->set_address((uint64_t)pt);
pde->present = true;
@ -341,7 +342,10 @@ void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space)
if (!space_last_pdp_pde.present)
{
space_last_pdp = (PageTable*)PMM::request_page(); // FIXME: Add out-of-memory checks.
auto result = PMM::request_page();
ensure(result.has_value()); // FIXME: Propagate this error.
space_last_pdp = (PageTable*)result.release_value();
memset(space_last_pdp, 0, PAGE_SIZE);
space_last_pdp_pde.present = true;

View File

@ -171,7 +171,7 @@ long Scheduler::load_user_task(const char* filename)
Interrupts::pop();
return -ENOMEM;
}
new_task->address_space = AddressSpace::create();
new_task->address_space = AddressSpace::create().release_value(); // FIXME: Propagate this error.
VMM::switch_to_user_address_space(new_task->address_space);
long result;
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)