Compare commits
2 Commits
559d074ce4
...
662afad426
Author | SHA1 | Date | |
---|---|---|---|
662afad426 | |||
a3465c2f5e |
@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "memory/Paging.h"
|
#include "memory/Paging.h"
|
||||||
|
#include "utils/Result.h"
|
||||||
|
|
||||||
struct AddressSpace
|
struct AddressSpace
|
||||||
{
|
{
|
||||||
static AddressSpace create();
|
static Result<AddressSpace> create();
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "utils/Result.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define PMM_FAILED (void*)-1
|
|
||||||
#define PMM_DID_FAIL(addr) (void*)addr == PMM_FAILED
|
|
||||||
|
|
||||||
namespace PMM
|
namespace PMM
|
||||||
{
|
{
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void* request_page();
|
Result<void*> request_page();
|
||||||
void* request_pages(uint64_t count);
|
Result<void*> request_pages(uint64_t count);
|
||||||
|
|
||||||
void free_page(void* address);
|
void free_page(void* address);
|
||||||
void free_pages(void* address, uint64_t count);
|
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 "log/Log.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
|
#include "std/errno.h"
|
||||||
#include "std/stdlib.h"
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include "utils/move.h"
|
#include "utils/move.h"
|
||||||
|
|
||||||
AddressSpace AddressSpace::create()
|
Result<AddressSpace> AddressSpace::create()
|
||||||
{
|
{
|
||||||
AddressSpace result;
|
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);
|
memset(result.m_pml4, 0, PAGE_SIZE);
|
||||||
VMM::install_kernel_page_directory_into_address_space(result);
|
VMM::install_kernel_page_directory_into_address_space(result);
|
||||||
return move(result);
|
return move(result);
|
||||||
@ -156,8 +159,9 @@ void AddressSpace::clear()
|
|||||||
|
|
||||||
static PageTable* try_clone_page_table(PageTable* source)
|
static PageTable* try_clone_page_table(PageTable* source)
|
||||||
{
|
{
|
||||||
PageTable* dst = (PageTable*)PMM::request_page();
|
auto page = PMM::request_page();
|
||||||
if (PMM_DID_FAIL(dst)) { return 0; }
|
if (page.has_error()) { return 0; }
|
||||||
|
PageTable* dst = (PageTable*)page.release_value();
|
||||||
memcpy(dst, source, sizeof(PageTable));
|
memcpy(dst, source, sizeof(PageTable));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include "std/ensure.h"
|
#include "std/ensure.h"
|
||||||
|
|
||||||
|
// FIXME: Use Result in here.
|
||||||
|
|
||||||
void MemoryManager::init()
|
void MemoryManager::init()
|
||||||
{
|
{
|
||||||
KernelHeap::clear();
|
KernelHeap::clear();
|
||||||
@ -123,15 +125,15 @@ void* MemoryManager::get_page(int flags)
|
|||||||
|
|
||||||
void* MemoryManager::get_page_at(uint64_t addr, int flags)
|
void* MemoryManager::get_page_at(uint64_t addr, int flags)
|
||||||
{
|
{
|
||||||
void* physicalAddress = PMM::request_page();
|
auto paddr = PMM::request_page();
|
||||||
if (PMM_DID_FAIL(physicalAddress))
|
if (paddr.has_error())
|
||||||
{
|
{
|
||||||
#ifdef MM_DEBUG
|
#ifdef MM_DEBUG
|
||||||
kwarnln("OOM while allocating one page of memory. this is not good...");
|
kwarnln("OOM while allocating one page of memory. this is not good...");
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
VMM::map(addr, (uint64_t)physicalAddress, flags);
|
VMM::map(addr, (uint64_t)paddr.release_value(), flags);
|
||||||
return (void*)addr;
|
return (void*)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,17 +174,19 @@ void* MemoryManager::get_pages_at(uint64_t addr, uint64_t count, int flags)
|
|||||||
#endif
|
#endif
|
||||||
for (uint64_t i = 0; i < count; i++)
|
for (uint64_t i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
void* physicalAddress = PMM::request_page();
|
auto paddr = PMM::request_page();
|
||||||
if (PMM_DID_FAIL(physicalAddress)) // OOM: No physical memory available! Since this might be at the end of a
|
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
|
// long allocation, we should be able to recover most of it and allocate a
|
||||||
// smaller range, so this might not be fatal.
|
// smaller range, so this might not be fatal.
|
||||||
{
|
{
|
||||||
#ifdef MM_DEBUG
|
#ifdef MM_DEBUG
|
||||||
kwarnln("OOM while allocating page %ld of memory. this might be recoverable...", i);
|
kwarnln("OOM while allocating page %ld of memory. this might be recoverable...", i);
|
||||||
#endif
|
#endif
|
||||||
|
// FIXME: Weren't we supposed to free all previously allocated pages, to avoid leaks when failing large
|
||||||
|
// allocations?
|
||||||
return 0;
|
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;
|
return (void*)addr;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include "std/ensure.h"
|
#include "std/ensure.h"
|
||||||
|
#include "std/errno.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
|
|
||||||
extern BOOTBOOT bootboot;
|
extern BOOTBOOT bootboot;
|
||||||
@ -83,7 +84,7 @@ static void bitmap_set(uint64_t index, bool value)
|
|||||||
if (value) { virtual_bitmap_addr[byteIndex] |= bitIndexer; }
|
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++)
|
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 (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 = 0;
|
||||||
uint64_t contiguous_start = 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)
|
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]);
|
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
|
||||||
|
|
||||||
auto pde_create_if_not_present = [&]() {
|
auto pde_create_if_not_present = [&]() {
|
||||||
pt = (PageTable*)PMM::request_page();
|
auto pt_or_error = PMM::request_page();
|
||||||
ensure(!(PMM_DID_FAIL(pt)));
|
ensure(pt_or_error.has_value());
|
||||||
|
pt = (PageTable*)pt_or_error.release_value();
|
||||||
memset(pt, 0, PAGE_SIZE);
|
memset(pt, 0, PAGE_SIZE);
|
||||||
pde->set_address((uint64_t)pt);
|
pde->set_address((uint64_t)pt);
|
||||||
pde->present = true;
|
pde->present = true;
|
||||||
@ -341,7 +342,10 @@ void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space)
|
|||||||
|
|
||||||
if (!space_last_pdp_pde.present)
|
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);
|
memset(space_last_pdp, 0, PAGE_SIZE);
|
||||||
|
|
||||||
space_last_pdp_pde.present = true;
|
space_last_pdp_pde.present = true;
|
||||||
|
@ -171,7 +171,7 @@ long Scheduler::load_user_task(const char* filename)
|
|||||||
Interrupts::pop();
|
Interrupts::pop();
|
||||||
return -ENOMEM;
|
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);
|
VMM::switch_to_user_address_space(new_task->address_space);
|
||||||
long result;
|
long result;
|
||||||
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)
|
if ((result = ELFLoader::check_elf_image_from_filesystem(filename)) < 0)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
unset -f filter-lines
|
unset -f filter-lines
|
||||||
filter-lines()
|
filter-lines()
|
||||||
|
Loading…
Reference in New Issue
Block a user