Kernel: Add a Result class
This commit is contained in:
parent
a3465c2f5e
commit
662afad426
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
125
kernel/include/utils/Result.h
Normal file
125
kernel/include/utils/Result.h
Normal 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;
|
||||
};
|
13
kernel/include/utils/new.h
Normal file
13
kernel/include/utils/new.h
Normal 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 {};
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
// long allocation, we should be able to recover most of it and allocate a
|
||||
// smaller range, so this might not be fatal.
|
||||
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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user