From 2d3399ab6072acd85811a54fce8eff50628888b6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:35:34 +0000 Subject: x86_64: move files out of the way --- .../src/memory/allocator/area_frame_allocator.cpp | 85 +++++++++ .../src/memory/allocator/tiny_frame_allocator.cpp | 34 ++++ arch/x86_64/pre/src/memory/heap/bump_allocator.cpp | 54 ++++++ .../pre/src/memory/heap/global_heap_allocator.cpp | 135 ++++++++++++++ .../pre/src/memory/heap/linked_list_allocator.cpp | 177 ++++++++++++++++++ arch/x86_64/pre/src/memory/heap/memory_block.cpp | 15 ++ .../pre/src/memory/heap/user_heap_allocator.cpp | 200 +++++++++++++++++++++ arch/x86_64/pre/src/memory/main.cpp | 77 ++++++++ .../src/memory/multiboot/elf_symbols_section.cpp | 13 ++ arch/x86_64/pre/src/memory/multiboot/reader.cpp | 135 ++++++++++++++ .../pre/src/memory/paging/active_page_table.cpp | 98 ++++++++++ .../pre/src/memory/paging/inactive_page_table.cpp | 20 +++ arch/x86_64/pre/src/memory/paging/page_entry.cpp | 63 +++++++ arch/x86_64/pre/src/memory/paging/page_table.cpp | 128 +++++++++++++ .../pre/src/memory/paging/temporary_page.cpp | 29 +++ arch/x86_64/pre/src/memory/paging/virtual_page.cpp | 33 ++++ 16 files changed, 1296 insertions(+) create mode 100644 arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/bump_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/memory_block.cpp create mode 100644 arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp create mode 100644 arch/x86_64/pre/src/memory/main.cpp create mode 100644 arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp create mode 100644 arch/x86_64/pre/src/memory/multiboot/reader.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/active_page_table.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/page_entry.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/page_table.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/temporary_page.cpp create mode 100644 arch/x86_64/pre/src/memory/paging/virtual_page.cpp (limited to 'arch/x86_64/pre/src/memory') diff --git a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp new file mode 100644 index 0000000..a5a1b49 --- /dev/null +++ b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp @@ -0,0 +1,85 @@ +#include "arch/memory/allocator/area_frame_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include +#include + +namespace teachos::arch::memory::allocator +{ + area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) + : next_free_frame() + , current_area(std::nullopt) + , memory_areas(mem_info.areas) + , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) + , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) + , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) + , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) + { + choose_next_area(); + } + + auto area_frame_allocator::choose_next_area() -> void + { + current_area = std::nullopt; + auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { + auto address = area.base_address + area.area_length - 1; + return physical_frame::containing_address(address) >= next_free_frame; + }); + + auto const lowest_area_with_free_frames = std::ranges::min_element( + next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); + + if (lowest_area_with_free_frames != next_area_with_free_frames.end()) + { + current_area = *lowest_area_with_free_frames; + // Update the `next_free_frame` according to the new memory area + auto const start_frame = physical_frame::containing_address(current_area.value().base_address); + if (next_free_frame < start_frame) + { + next_free_frame = start_frame; + } + } + } + + auto area_frame_allocator::allocate_frame() -> std::optional + { + // Only try to allocate memory if current_area is not null, because + // the current_area is null if there is no more available memory. + if (!current_area.has_value()) + { + return std::nullopt; + } + + auto const address = current_area.value().base_address + current_area.value().area_length - 1; + physical_frame current_area_last_frame = physical_frame::containing_address(address); + + if (next_free_frame > current_area_last_frame) + { + // All frames of current area are used, switch to next area. + choose_next_area(); + } + else if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; + } + else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; + } + else + { + // Frame is unused, increment `next_free_frame` and return it. + next_free_frame.frame_number += 1; + return next_free_frame; + } + + // `physical_frame` was not valid, try it again with the updated `next_free_frame`. + return allocate_frame(); + } + + auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { (void)physical_frame; } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp new file mode 100644 index 0000000..3cdf9c7 --- /dev/null +++ b/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp @@ -0,0 +1,34 @@ +#include "arch/memory/allocator/tiny_frame_allocator.hpp" + +#include "arch/exception_handling/panic.hpp" + +namespace teachos::arch::memory::allocator +{ + auto tiny_frame_allocator::allocate_frame() -> std::optional + { + for (auto & frame_option : frames) + { + if (frame_option.has_value()) + { + auto value = frame_option; + frame_option.reset(); + return value; + } + } + return std::nullopt; + } + + auto tiny_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void + { + for (auto & frame_option : frames) + { + if (!frame_option.has_value()) + { + frame_option.emplace(physical_frame); + return; + } + } + exception_handling::panic( + "[Tiny Frame Allocator] Attempted to deallocate more than the 3 frames, that can be held"); + } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp b/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp new file mode 100644 index 0000000..525f45c --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/bump_allocator.cpp @@ -0,0 +1,54 @@ +#include "arch/memory/heap/bump_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include + +namespace teachos::arch::memory::heap +{ + namespace + { + template + auto saturating_add(T x, T y) -> T + requires std::is_unsigned_v + { + if (x > std::numeric_limits::max() - y) + { + return std::numeric_limits::max(); + } + T result = x + y; + return result; + } + } // namespace + + auto bump_allocator::allocate(std::size_t size) -> void * + { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); + // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time + // causing the value to differ and the calculation to have to be redone. + for (;;) + { + auto const alloc_end = saturating_add(alloc_start, size); + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); + // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another + // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation + // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. + auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); + if (updated) + { + return reinterpret_cast(alloc_start); + } + } + } + + auto bump_allocator::deallocate(void * pointer) noexcept -> void + { + if (pointer) + { + } + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp new file mode 100644 index 0000000..35cd623 --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp @@ -0,0 +1,135 @@ +#include "arch/memory/heap/global_heap_allocator.hpp" + +#include "arch/context_switching/syscall/main.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/segment_register.hpp" +#include "arch/memory/heap/bump_allocator.hpp" +#include "arch/memory/heap/linked_list_allocator.hpp" +#include "arch/memory/heap/user_heap_allocator.hpp" + +namespace teachos::arch::memory::heap +{ + namespace + { + constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."; + constexpr uint16_t KERNEL_CODE_INDEX = 1U; + + [[gnu::section(".user_text")]] + auto os_in_kernel_mode() -> bool + { + auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); + return cs.get_index() == KERNEL_CODE_INDEX; + } + } // namespace + + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; + user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; + + auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } + + auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); } + + auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); } + + auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); } + + auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void + { + exception_handling::assert(kernel_allocator_instance == nullptr, + "Calling register_heap_allocator_type can only be done once."); + + switch (new_type) + { + case heap_allocator_type::NONE: + // Nothing to do + break; + case heap_allocator_type::BUMP: { + static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + break; + } + case heap_allocator_type::LINKED_LIST: { + static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + break; + } + } + + [[gnu::section(".user_data")]] + static user_heap_allocator user_allocator{}; + user_allocator_instance = &user_allocator; + } + + auto global_heap_allocator::kernel() -> heap_allocator & + { + exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); + + return *kernel_allocator_instance; + } + + auto global_heap_allocator::user() -> user_heap_allocator & + { + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); + return *user_allocator_instance; + } +} // namespace teachos::arch::memory::heap + +auto operator new(std::size_t size) -> void * +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); +} + +auto operator delete(void * pointer) noexcept -> void +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} + +auto operator delete(void * pointer, std::size_t size) noexcept -> void +{ + (void)size; + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} + +auto operator new[](std::size_t size) -> void * +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); +} + +auto operator delete[](void * pointer) noexcept -> void +{ + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} + +auto operator delete[](void * pointer, std::size_t size) noexcept -> void +{ + (void)size; + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); +} diff --git a/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp new file mode 100644 index 0000000..00ca366 --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/linked_list_allocator.cpp @@ -0,0 +1,177 @@ +#include "arch/memory/heap/linked_list_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) + : first(nullptr) + , mutex{kstd::mutex{}} + { + auto const heap_size = heap_end - heap_start; + exception_handling::assert( + heap_size > min_allocatable_size(), + "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " + "atleast one memory hole entry"); + first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + + auto linked_list_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + + previous = current; + current = current->next; + } + + exception_handling::panic("[Linked List Allocator] Out of memory"); + } + + auto linked_list_allocator::deallocate(void * pointer) noexcept -> void + { + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) + { + break; + } + + previous = current; + current = current->next; + } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); + } + + auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * + { + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto linked_list_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto linked_list_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean + // that the block has already been deallocated and we therefore attempted a double free. + exception_handling::assert(previous_block == nullptr || + start_address >= + (reinterpret_cast(previous_block) + previous_block->size), + "[Linked List Allocator] Attempted double free detected"); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) + { + first = new_block; + return; + } + previous_block->next = new_block; + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/memory_block.cpp b/arch/x86_64/pre/src/memory/heap/memory_block.cpp new file mode 100644 index 0000000..bc97bd6 --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/memory_block.cpp @@ -0,0 +1,15 @@ +#include "arch/memory/heap/memory_block.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + memory_block::memory_block(std::size_t size, memory_block * next) + { + memset(static_cast(this), 0U, size); + this->size = size; + this->next = next; + } + + memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp new file mode 100644 index 0000000..427a68a --- /dev/null +++ b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp @@ -0,0 +1,200 @@ +#include "arch/memory/heap/user_heap_allocator.hpp" + +#include "arch/context_switching/syscall/main.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) + { + return memory.value(); + } + + previous = current; + current = current->next; + } + + current = expand_heap_if_full(); + + if (current != nullptr) + { + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) + { + return memory.value(); + } + } + + char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; + context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, + {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); + return nullptr; + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + { + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) + { + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) + { + break; + } + + previous = current; + current = current->next; + } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); + } + + auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, + std::size_t total_size) -> std::optional + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + return std::nullopt; + } + + auto user_heap_allocator::expand_heap_if_full() -> memory_block * + { + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); + + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; + } + + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * + { + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean + // that the block has already been deallocated and we therefore attempted a double free. + char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {previous_block == nullptr || + start_address >= (reinterpret_cast(previous_block) + previous_block->size), + reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) + { + first = new_block; + return; + } + previous_block->next = new_block; + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/main.cpp b/arch/x86_64/pre/src/memory/main.cpp new file mode 100644 index 0000000..2746a71 --- /dev/null +++ b/arch/x86_64/pre/src/memory/main.cpp @@ -0,0 +1,77 @@ +#include "arch/memory/main.hpp" + +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/control_register.hpp" +#include "arch/kernel/cpu/msr.hpp" +#include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/memory/paging/active_page_table.hpp" +#include "arch/memory/paging/kernel_mapper.hpp" + +#include + +namespace teachos::arch::memory +{ + namespace + { + static std::optional frame_allocator; + + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::area_frame_allocator & + { + frame_allocator.emplace(memory_information); + return frame_allocator.value(); + } + + auto get_frame_allocator() -> allocator::area_frame_allocator & + { + exception_handling::assert(frame_allocator.has_value(), + "[Initialization] Frame allocator has not been created yet"); + return frame_allocator.value(); + } + } // namespace + + auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void + { + decltype(auto) allocator = get_frame_allocator(); + decltype(auto) active_table = paging::active_page_table::create_or_get(); + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); + + paging::page_container::iterator const begin{start_page}; + paging::page_container::iterator const end{end_page}; + paging::page_container const pages{begin, end}; + + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = base_flags | additional_flags; + + for (auto const & page : pages) + { + active_table.map_page_to_next_free_frame(allocator, page, flags); + } + } + + auto initialize_memory_management() -> void + { + static bool has_been_called = false; + arch::exception_handling::assert(!has_been_called, + "[Initialization] Memory management has already been initialized"); + has_been_called = true; + + auto const memory_information = multiboot::read_multiboot2(); + decltype(auto) allocator = create_frame_allocator(memory_information); + + kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); + + paging::kernel_mapper kernel(allocator, memory_information); + kernel.remap_kernel(); + video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + + remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + } +} // namespace teachos::arch::memory diff --git a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp new file mode 100644 index 0000000..f5d126b --- /dev/null +++ b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp @@ -0,0 +1,13 @@ +#include "arch/memory/multiboot/elf_symbols_section.hpp" + +namespace teachos::arch::memory::multiboot +{ + auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + + auto elf_section_header::is_null() const -> bool + { + return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == elf_section_flags(0U) && + physical_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U && + fixed_table_entry_size == 0U; + } +} // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/pre/src/memory/multiboot/reader.cpp b/arch/x86_64/pre/src/memory/multiboot/reader.cpp new file mode 100644 index 0000000..b05e6b3 --- /dev/null +++ b/arch/x86_64/pre/src/memory/multiboot/reader.cpp @@ -0,0 +1,135 @@ +#include "arch/memory/multiboot/reader.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "multiboot2/information.hpp" +// #include "arch/memory/multiboot/elf_symbols_section.hpp" +// #include "arch/memory/multiboot/info.hpp" + +#include +#include + +// namespace teachos::arch::memory::multiboot +// { +// namespace +// { +// template +// requires std::is_pointer::value +// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T +// { +// return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); +// } + +// auto process_memory_map(memory_map_header * mminfo) -> memory_area_container +// { +// auto const expected_entry_size = mminfo->entry_size; +// auto constexpr actual_entry_size = sizeof(memory_area); +// exception_handling::assert(expected_entry_size == actual_entry_size, +// "[Multiboot Reader] Unexpected memory area entry size"); + +// auto const total_size = mminfo->info.size; +// auto const total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; +// auto const number_of_entries = total_entries_size / actual_entry_size; + +// auto const begin = memory_area_container::iterator{&mminfo->entries}; +// auto const end = begin + number_of_entries; +// return memory_area_container{begin, end}; +// } + +// auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start, std::size_t & +// kernel_end) +// -> elf_section_header_container +// { +// auto const expected_entry_size = symbol->entry_size; +// auto constexpr actual_entry_size = sizeof(elf_section_header); +// exception_handling::assert(expected_entry_size == actual_entry_size, +// "[Multiboot Reader] Unexpected elf section header entry size"); + +// auto const expected_total_size = symbol->info.size; +// auto const actual_total_entry_size = actual_entry_size * symbol->number_of_sections; +// auto constexpr actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); +// auto const actual_total_size = actual_total_entry_size + actual_total_section_size; +// exception_handling::assert(expected_total_size == actual_total_size, +// "[Multiboot Reader] Unexpected elf symbols section header total size"); + +// auto const begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; auto const end = begin + symbol->number_of_sections; +// exception_handling::assert(begin->is_null(), +// "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); + +// elf_section_header_container sections{begin, end}; + +// auto allocated_sections = sections | std::views::filter([](auto const & section) { +// return section.flags.contains_flags(elf_section_flags::OCCUPIES_MEMORY); +// }); + +// auto const elf_section_with_lowest_physical_address = std::ranges::min_element( +// allocated_sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; +// }); + +// auto const elf_section_with_highest_physical_address = +// std::ranges::max_element(allocated_sections, [](auto const & a, auto const & b) { +// auto a_physical_address_end = a.physical_address + a.section_size; +// auto b_physical_address_end = b.physical_address + b.section_size; +// return a_physical_address_end < b_physical_address_end; +// }); + +// auto const symbol_table_section_count = std::ranges::count_if(sections, [](auto const & section) { +// return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == +// elf_section_type::SYMBOL_TABLE; +// }); +// auto const dynamic_section_count = std::ranges::count_if( +// sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; }); + +// exception_handling::assert( +// symbol_table_section_count == 1U, +// "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got more"); +// exception_handling::assert( +// dynamic_section_count <= 1U, +// "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); + +// auto const lowest_elf_section = *elf_section_with_lowest_physical_address; +// kernel_start = lowest_elf_section.physical_address; + +// auto const highest_elf_section = *elf_section_with_highest_physical_address; +// kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size; + +// return sections; +// } +// } // namespace + +// auto read_multiboot2() -> memory_information +// { +// memory_information mem_info{UINT64_MAX, +// 0U, +// elf_section_header_container{}, +// boot::multiboot_information_pointer, +// 0U, +// memory_area_container{}}; + +// auto const multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); +// auto const multiboot_tag = &multiboot_information_pointer->tags; +// mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size; + +// for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size)) +// { +// switch (tag->type) +// { +// case tag_type::ELF_SECTIONS: { +// auto const symbol = reinterpret_cast(tag); +// mem_info.sections = process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); +// break; +// } +// case tag_type::MEMORY_MAP: { +// auto const mminfo = reinterpret_cast(tag); +// mem_info.areas = process_memory_map(mminfo); +// break; +// } +// default: +// // All other cases are not important and can be ignored. +// break; +// } +// } +// return mem_info; +// } +// } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp new file mode 100644 index 0000000..0113869 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp @@ -0,0 +1,98 @@ +#include "arch/memory/paging/active_page_table.hpp" + +namespace teachos::arch::memory::paging +{ + namespace + { + paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + } + + auto active_page_table::create_or_get() -> active_page_table & + { + static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), + page_table_handle::LEVEL4}; + static active_page_table active_page{active_handle}; + return active_page; + } + + auto active_page_table::operator[](std::size_t index) -> entry & { return active_handle[index]; } + + auto active_page_table::translate_address(virtual_address address) -> std::optional + { + auto const offset = address % allocator::PAGE_FRAME_SIZE; + auto const page = virtual_page::containing_address(address); + auto const frame = translate_page(page); + + if (frame.has_value()) + { + return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; + } + + return std::nullopt; + } + + auto active_page_table::translate_page(virtual_page page) -> std::optional + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const next_handle = current_handle.next_table(page.get_level_index(level)); + // If the next table method failed then it is highly likely that it was a huge page and we therefore have to + // parse the table differently. Therefore, we attempt to parse it using the method required by huge pages. + if (!next_handle.has_value()) + { + return translate_huge_page(page); + } + current_handle = next_handle.value(); + } + + auto const level1_index = page.get_level_index(page_table_handle::LEVEL1); + auto const level1_entry = current_handle[level1_index]; + return level1_entry.calculate_pointed_to_frame(); + } + + auto active_page_table::translate_huge_page(virtual_page page) -> std::optional + { + auto current_handle = active_handle; + auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4)); + + if (!level3_handle.has_value()) + { + return std::nullopt; + } + + auto const level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; + auto const level3_frame = level3_entry.calculate_pointed_to_frame(); + if (level3_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE)) + { + exception_handling::assert( + level3_frame.value().frame_number % (PAGE_TABLE_ENTRY_COUNT * PAGE_TABLE_ENTRY_COUNT) == 0U, + "[Page Mapper] Physical address must be 1 GiB aligned"); + return allocator::physical_frame{level3_frame.value().frame_number + + page.get_level_index(page_table_handle::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + + page.get_level_index(page_table_handle::LEVEL1)}; + } + + auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); + if (level2_handle.has_value()) + { + auto const level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; + auto const level2_frame = level2_entry.calculate_pointed_to_frame(); + if (level2_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE)) + { + exception_handling::assert(level2_frame.value().frame_number % PAGE_TABLE_ENTRY_COUNT == 0U, + "[Page Mapper] Physical address must be 2 MiB aligned"); + return allocator::physical_frame{level2_frame.value().frame_number + + page.get_level_index(page_table_handle::LEVEL1)}; + } + } + return std::nullopt; + } + + active_page_table::active_page_table(page_table_handle active_handle) + : active_handle(active_handle) + { + // Nothing to do + } +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp new file mode 100644 index 0000000..4e0610e --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp @@ -0,0 +1,20 @@ +#include "arch/memory/paging/inactive_page_table.hpp" + +namespace teachos::arch::memory::paging +{ + inactive_page_table::inactive_page_table(allocator::physical_frame frame) + : page_table_level_4_frame{frame} + { + // Nothing to do + } + + inactive_page_table::inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table, + temporary_page & temporary_page) + : page_table_level_4_frame{frame} + { + auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); + table.zero_entries(); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + temporary_page.unmap_page(active_page_table); + } +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/page_entry.cpp b/arch/x86_64/pre/src/memory/paging/page_entry.cpp new file mode 100644 index 0000000..57045ca --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/page_entry.cpp @@ -0,0 +1,63 @@ +#include "arch/memory/paging/page_entry.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::paging +{ + namespace + { + std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; + } // namespace + + entry::entry(uint64_t flags) + : flags(flags) + { + // Nothing to do. + } + + entry::entry(multiboot::elf_section_flags elf_flags) + { + if (elf_flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + { + flags |= entry::PRESENT; + } + + if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) + { + flags |= entry::WRITABLE; + } + + if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) + { + flags |= entry::EXECUTING_CODE_FORBIDDEN; + } + } + + auto entry::is_unused() const -> bool { return flags == 0U; } + + auto entry::set_unused() -> void { flags = 0U; } + + auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } + + auto entry::calculate_pointed_to_frame() const -> std::optional + { + if (contains_flags(PRESENT)) + { + auto const address = flags.to_ulong() & PHYSICAL_ADDRESS_MASK; + return allocator::physical_frame::containing_address(address); + } + return std::nullopt; + } + + auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void + { + exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, + "[Paging Entry] Start address is not aligned with page"); + + flags = frame.start_address() | additional_flags.to_ulong(); + } + + auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/page_table.cpp b/arch/x86_64/pre/src/memory/paging/page_table.cpp new file mode 100644 index 0000000..eb11810 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/page_table.cpp @@ -0,0 +1,128 @@ +#include "arch/memory/paging/page_table.hpp" + +#include +#include +#include + +/* + * This is a linker variable reference. This referenc cannot reside inside a namespace, because in + * that case the compiler would try to find arch::memory::paging::_end_of_image inside the ELF file. + */ +extern char _end_of_image; + +namespace teachos::arch::memory::paging +{ + /** + * @brief A Page table containing 512 entries. + */ + struct page_table + { + auto zero_entries() -> void; + + auto is_empty() const -> bool; + + auto next_table(std::size_t table_index) const -> std::optional; + + auto operator[](std::size_t index) -> entry &; + + auto operator[](std::size_t index) const -> entry const &; + + private: + /** + * @brief Calculates the address of the next page table level for the given table index. + * + * @note The next page table address is only valid if the corresponding entry is present and not a huge page. + * Meaning we use an index into a Level 4 page table to get the according Level 3 page table address. + * + * @param table_index Index of this page table in the page table one level higher. + * @return An optional of the address of the next page table or null. + */ + auto next_table_address(std::size_t table_index) const -> std::optional; + + std::array entries = + {}; ///< Entries containing addresses to page tables of a level below or + ///< actual virtual addresses for the level 1 page table. + }; + + auto page_table::zero_entries() -> void + { + std::ranges::for_each(entries, [](auto & entry) { entry.set_unused(); }); + } + + auto page_table::is_empty() const -> bool + { + return std::all_of(entries.begin(), entries.end(), [](entry const & entry) { return entry.is_unused(); }); + } + + auto page_table::next_table(std::size_t table_index) const -> std::optional + { + auto const address = next_table_address(table_index); + if (address.has_value()) + { + return reinterpret_cast(address.value()); + } + return std::nullopt; + } + + auto page_table::operator[](std::size_t index) -> entry & + { + exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); + return entries[index]; + } + + auto page_table::operator[](std::size_t index) const -> entry const & + { + exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); + return entries[index]; + } + + auto page_table::next_table_address(std::size_t table_index) const -> std::optional + { + auto const entry = this->operator[](table_index); + + if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) + { + auto const table_address = reinterpret_cast(this); + return ((table_address << 9) | (table_index << 12)); + } + return std::nullopt; + } + + page_table_handle::page_table_handle(page_table * table, page_table_handle::level table_level) + : table(table) + , table_level(table_level) + { + exception_handling::assert(table != nullptr, + "[Page Table] Attempted to pass nullptr as table to page table table method"); + } + + auto page_table_handle::zero_entries() -> void { table->zero_entries(); } + + auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } + + auto page_table_handle::next_table(std::size_t table_index) const -> std::optional + { + exception_handling::assert(table_level != page_table_handle::LEVEL1, + "[Page Table] Attempted to call next_table on level 1 page table"); + auto const next_table = table->next_table(table_index); + if (next_table.has_value()) + { + auto const new_level = static_cast(table_level - 1); + return page_table_handle{next_table.value(), new_level}; + } + return std::nullopt; + } + + auto page_table_handle::get_level() const -> page_table_handle::level { return table_level; } + + auto page_table_handle::operator[](std::size_t index) -> entry & { return table->operator[](index); } + + auto operator--(page_table_handle::level & value) -> page_table_handle::level & + { + exception_handling::assert(value != page_table_handle::LEVEL1, + "[Page table] Attempted to decrement enum to value outside of range"); + auto new_value = static_cast::type>(value); + value = static_cast(--new_value); + return value; + } +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/temporary_page.cpp b/arch/x86_64/pre/src/memory/paging/temporary_page.cpp new file mode 100644 index 0000000..8e73523 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/temporary_page.cpp @@ -0,0 +1,29 @@ +#include "arch/memory/paging/temporary_page.hpp" + +#include "arch/memory/paging/page_entry.hpp" + +namespace teachos::arch::memory::paging +{ + auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) + -> page_table_handle + { + page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), + page_table_handle::LEVEL1}; + return handle; + } + + auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table) + -> virtual_address + { + exception_handling::assert(!active_table.translate_page(page).has_value(), + "[Temporary page] Page is already mapped"); + + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); + return page.start_address(); + } + + auto temporary_page::unmap_page(active_page_table & active_table) -> void + { + active_table.unmap_page(allocator, page); + } +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp new file mode 100644 index 0000000..d374156 --- /dev/null +++ b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp @@ -0,0 +1,33 @@ +#include "arch/memory/paging/virtual_page.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::paging +{ + auto virtual_page::containing_address(virtual_address address) -> virtual_page + { + exception_handling::assert(address < 0x00008000'00000000 || address >= 0xffff8000'00000000, + "[Virtual Page] Attempted to create virtual page from invalid address"); + return virtual_page{address / allocator::PAGE_FRAME_SIZE}; + } + + auto virtual_page::start_address() const -> virtual_address { return page_number * allocator::PAGE_FRAME_SIZE; } + + auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t + { + return (page_number >> (level * 9U)) & 0x1FF; + } + + auto virtual_page::operator++(int) -> virtual_page + { + virtual_page const old_value = *this; + ++page_number; + return old_value; + } + + auto virtual_page::operator++() -> virtual_page & + { + ++page_number; + return *this; + } +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From b157e2c472d8bd67ac1656404a6a6ee821260f4b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 15:01:43 +0100 Subject: chore: reformat source code --- .../src/memory/allocator/area_frame_allocator.cpp | 5 +++- .../pre/src/memory/heap/global_heap_allocator.cpp | 33 +++++++++++++++------- arch/x86_64/pre/src/memory/heap/memory_block.cpp | 5 +++- .../pre/src/memory/heap/user_heap_allocator.cpp | 4 +-- arch/x86_64/pre/src/memory/main.cpp | 4 +-- .../src/memory/multiboot/elf_symbols_section.cpp | 5 +++- .../pre/src/memory/paging/active_page_table.cpp | 11 +++++--- arch/x86_64/pre/src/memory/paging/page_entry.cpp | 27 ++++++++++++++---- arch/x86_64/pre/src/memory/paging/page_table.cpp | 20 ++++++++++--- arch/x86_64/pre/src/memory/paging/virtual_page.cpp | 7 +++-- 10 files changed, 88 insertions(+), 33 deletions(-) (limited to 'arch/x86_64/pre/src/memory') diff --git a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp index a5a1b49..3105023 100644 --- a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp @@ -81,5 +81,8 @@ namespace teachos::arch::memory::allocator return allocate_frame(); } - auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { (void)physical_frame; } + auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void + { + (void)physical_frame; + } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp index 35cd623..709cda1 100644 --- a/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/pre/src/memory/heap/global_heap_allocator.cpp @@ -27,13 +27,25 @@ namespace teachos::arch::memory::heap heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; - auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } + auto global_heap_allocator::kmalloc(std::size_t size) -> void * + { + return kernel().allocate(size); + } - auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); } + auto global_heap_allocator::kfree(void * pointer) noexcept -> void + { + kernel().deallocate(pointer); + } - auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); } + auto global_heap_allocator::malloc(std::size_t size) -> void * + { + return user().allocate(size); + } - auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); } + auto global_heap_allocator::free(void * pointer) noexcept -> void + { + user().deallocate(pointer); + } auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void { @@ -45,20 +57,21 @@ namespace teachos::arch::memory::heap case heap_allocator_type::NONE: // Nothing to do break; - case heap_allocator_type::BUMP: { - static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + case heap_allocator_type::BUMP: + { + bump_allocator static kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; break; } - case heap_allocator_type::LINKED_LIST: { - static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + case heap_allocator_type::LINKED_LIST: + { + linked_list_allocator static kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; break; } } - [[gnu::section(".user_data")]] - static user_heap_allocator user_allocator{}; + [[gnu::section(".user_data")]] user_heap_allocator static user_allocator{}; user_allocator_instance = &user_allocator; } diff --git a/arch/x86_64/pre/src/memory/heap/memory_block.cpp b/arch/x86_64/pre/src/memory/heap/memory_block.cpp index bc97bd6..4c07454 100644 --- a/arch/x86_64/pre/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/pre/src/memory/heap/memory_block.cpp @@ -11,5 +11,8 @@ namespace teachos::arch::memory::heap this->next = next; } - memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } + memory_block::~memory_block() + { + memset(static_cast(this), 0U, sizeof(memory_block)); + } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp index 427a68a..96de005 100644 --- a/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/pre/src/memory/heap/user_heap_allocator.cpp @@ -39,7 +39,7 @@ namespace teachos::arch::memory::heap } } - char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; + constexpr char OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); return nullptr; @@ -178,7 +178,7 @@ namespace teachos::arch::memory::heap // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean // that the block has already been deallocated and we therefore attempted a double free. - char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; + constexpr char DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; context_switching::syscall::syscall( context_switching::syscall::type::ASSERT, {previous_block == nullptr || diff --git a/arch/x86_64/pre/src/memory/main.cpp b/arch/x86_64/pre/src/memory/main.cpp index 2746a71..b5980db 100644 --- a/arch/x86_64/pre/src/memory/main.cpp +++ b/arch/x86_64/pre/src/memory/main.cpp @@ -15,7 +15,7 @@ namespace teachos::arch::memory { namespace { - static std::optional frame_allocator; + std::optional static frame_allocator; auto create_frame_allocator(multiboot::memory_information const & memory_information) -> allocator::area_frame_allocator & @@ -54,7 +54,7 @@ namespace teachos::arch::memory auto initialize_memory_management() -> void { - static bool has_been_called = false; + bool static has_been_called = false; arch::exception_handling::assert(!has_been_called, "[Initialization] Memory management has already been initialized"); has_been_called = true; diff --git a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp index f5d126b..3105120 100644 --- a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp +++ b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp @@ -2,7 +2,10 @@ namespace teachos::arch::memory::multiboot { - auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool + { + return (flags & other) == other; + } auto elf_section_header::is_null() const -> bool { diff --git a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp index 0113869..930588d 100644 --- a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp @@ -4,18 +4,21 @@ namespace teachos::arch::memory::paging { namespace { - paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + constexpr paging::virtual_address PAGE_TABLE_LEVEL_4_ADDRESS = 0xffff'ffff'ffff'f000; } auto active_page_table::create_or_get() -> active_page_table & { - static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), + page_table_handle static active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), page_table_handle::LEVEL4}; - static active_page_table active_page{active_handle}; + active_page_table static active_page{active_handle}; return active_page; } - auto active_page_table::operator[](std::size_t index) -> entry & { return active_handle[index]; } + auto active_page_table::operator[](std::size_t index) -> entry & + { + return active_handle[index]; + } auto active_page_table::translate_address(virtual_address address) -> std::optional { diff --git a/arch/x86_64/pre/src/memory/paging/page_entry.cpp b/arch/x86_64/pre/src/memory/paging/page_entry.cpp index 57045ca..ec45068 100644 --- a/arch/x86_64/pre/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/pre/src/memory/paging/page_entry.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::memory::paging { namespace { - std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; + constexpr std::size_t PHYSICAL_ADDRESS_MASK = 0x000f'ffff'ffff'f000; } // namespace entry::entry(uint64_t flags) @@ -33,11 +33,20 @@ namespace teachos::arch::memory::paging } } - auto entry::is_unused() const -> bool { return flags == 0U; } + auto entry::is_unused() const -> bool + { + return flags == 0U; + } - auto entry::set_unused() -> void { flags = 0U; } + auto entry::set_unused() -> void + { + flags = 0U; + } - auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_user_accessible() -> void + { + flags |= entry::USER_ACCESSIBLE; + } auto entry::calculate_pointed_to_frame() const -> std::optional { @@ -49,7 +58,10 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + auto entry::contains_flags(std::bitset<64U> other) const -> bool + { + return (flags & other) == other; + } auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void { @@ -59,5 +71,8 @@ namespace teachos::arch::memory::paging flags = frame.start_address() | additional_flags.to_ulong(); } - auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } + auto entry::get_flags() const -> std::bitset<64U> + { + return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; + } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/page_table.cpp b/arch/x86_64/pre/src/memory/paging/page_table.cpp index eb11810..e79c3e5 100644 --- a/arch/x86_64/pre/src/memory/paging/page_table.cpp +++ b/arch/x86_64/pre/src/memory/paging/page_table.cpp @@ -96,9 +96,15 @@ namespace teachos::arch::memory::paging "[Page Table] Attempted to pass nullptr as table to page table table method"); } - auto page_table_handle::zero_entries() -> void { table->zero_entries(); } + auto page_table_handle::zero_entries() -> void + { + table->zero_entries(); + } - auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } + auto page_table_handle::is_empty() const -> bool + { + return table->is_empty(); + } auto page_table_handle::next_table(std::size_t table_index) const -> std::optional { @@ -113,9 +119,15 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto page_table_handle::get_level() const -> page_table_handle::level { return table_level; } + auto page_table_handle::get_level() const -> page_table_handle::level + { + return table_level; + } - auto page_table_handle::operator[](std::size_t index) -> entry & { return table->operator[](index); } + auto page_table_handle::operator[](std::size_t index) -> entry & + { + return table->operator[](index); + } auto operator--(page_table_handle::level & value) -> page_table_handle::level & { diff --git a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp index d374156..8d34918 100644 --- a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp @@ -6,12 +6,15 @@ namespace teachos::arch::memory::paging { auto virtual_page::containing_address(virtual_address address) -> virtual_page { - exception_handling::assert(address < 0x00008000'00000000 || address >= 0xffff8000'00000000, + exception_handling::assert(address < 0x0000'8000'0000'0000 || address >= 0xffff'8000'0000'0000, "[Virtual Page] Attempted to create virtual page from invalid address"); return virtual_page{address / allocator::PAGE_FRAME_SIZE}; } - auto virtual_page::start_address() const -> virtual_address { return page_number * allocator::PAGE_FRAME_SIZE; } + auto virtual_page::start_address() const -> virtual_address + { + return page_number * allocator::PAGE_FRAME_SIZE; + } auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t { -- cgit v1.2.3 From 682f28543be1ef7a315284c932075be1976e2930 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 14:11:07 +0100 Subject: x86_64/pre: remove ported implementation --- .../src/memory/allocator/area_frame_allocator.cpp | 88 ------------- .../src/memory/allocator/tiny_frame_allocator.cpp | 34 ----- arch/x86_64/pre/src/memory/main.cpp | 77 ------------ .../src/memory/multiboot/elf_symbols_section.cpp | 16 --- arch/x86_64/pre/src/memory/multiboot/reader.cpp | 135 -------------------- .../pre/src/memory/paging/active_page_table.cpp | 101 --------------- .../pre/src/memory/paging/inactive_page_table.cpp | 20 --- arch/x86_64/pre/src/memory/paging/page_entry.cpp | 78 ------------ arch/x86_64/pre/src/memory/paging/page_table.cpp | 140 --------------------- .../pre/src/memory/paging/temporary_page.cpp | 29 ----- arch/x86_64/pre/src/memory/paging/virtual_page.cpp | 36 ------ 11 files changed, 754 deletions(-) delete mode 100644 arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp delete mode 100644 arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp delete mode 100644 arch/x86_64/pre/src/memory/main.cpp delete mode 100644 arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp delete mode 100644 arch/x86_64/pre/src/memory/multiboot/reader.cpp delete mode 100644 arch/x86_64/pre/src/memory/paging/active_page_table.cpp delete mode 100644 arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp delete mode 100644 arch/x86_64/pre/src/memory/paging/page_entry.cpp delete mode 100644 arch/x86_64/pre/src/memory/paging/page_table.cpp delete mode 100644 arch/x86_64/pre/src/memory/paging/temporary_page.cpp delete mode 100644 arch/x86_64/pre/src/memory/paging/virtual_page.cpp (limited to 'arch/x86_64/pre/src/memory') diff --git a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp deleted file mode 100644 index 3105023..0000000 --- a/arch/x86_64/pre/src/memory/allocator/area_frame_allocator.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "arch/memory/allocator/area_frame_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::allocator -{ - area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) - : next_free_frame() - , current_area(std::nullopt) - , memory_areas(mem_info.areas) - , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) - , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) - , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) - , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) - { - choose_next_area(); - } - - auto area_frame_allocator::choose_next_area() -> void - { - current_area = std::nullopt; - auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { - auto address = area.base_address + area.area_length - 1; - return physical_frame::containing_address(address) >= next_free_frame; - }); - - auto const lowest_area_with_free_frames = std::ranges::min_element( - next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); - - if (lowest_area_with_free_frames != next_area_with_free_frames.end()) - { - current_area = *lowest_area_with_free_frames; - // Update the `next_free_frame` according to the new memory area - auto const start_frame = physical_frame::containing_address(current_area.value().base_address); - if (next_free_frame < start_frame) - { - next_free_frame = start_frame; - } - } - } - - auto area_frame_allocator::allocate_frame() -> std::optional - { - // Only try to allocate memory if current_area is not null, because - // the current_area is null if there is no more available memory. - if (!current_area.has_value()) - { - return std::nullopt; - } - - auto const address = current_area.value().base_address + current_area.value().area_length - 1; - physical_frame current_area_last_frame = physical_frame::containing_address(address); - - if (next_free_frame > current_area_last_frame) - { - // All frames of current area are used, switch to next area. - choose_next_area(); - } - else if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; - } - else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; - } - else - { - // Frame is unused, increment `next_free_frame` and return it. - next_free_frame.frame_number += 1; - return next_free_frame; - } - - // `physical_frame` was not valid, try it again with the updated `next_free_frame`. - return allocate_frame(); - } - - auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void - { - (void)physical_frame; - } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp deleted file mode 100644 index 3cdf9c7..0000000 --- a/arch/x86_64/pre/src/memory/allocator/tiny_frame_allocator.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "arch/memory/allocator/tiny_frame_allocator.hpp" - -#include "arch/exception_handling/panic.hpp" - -namespace teachos::arch::memory::allocator -{ - auto tiny_frame_allocator::allocate_frame() -> std::optional - { - for (auto & frame_option : frames) - { - if (frame_option.has_value()) - { - auto value = frame_option; - frame_option.reset(); - return value; - } - } - return std::nullopt; - } - - auto tiny_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void - { - for (auto & frame_option : frames) - { - if (!frame_option.has_value()) - { - frame_option.emplace(physical_frame); - return; - } - } - exception_handling::panic( - "[Tiny Frame Allocator] Attempted to deallocate more than the 3 frames, that can be held"); - } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/pre/src/memory/main.cpp b/arch/x86_64/pre/src/memory/main.cpp deleted file mode 100644 index b5980db..0000000 --- a/arch/x86_64/pre/src/memory/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "arch/memory/main.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/control_register.hpp" -#include "arch/kernel/cpu/msr.hpp" -#include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/allocator/concept.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/paging/active_page_table.hpp" -#include "arch/memory/paging/kernel_mapper.hpp" - -#include - -namespace teachos::arch::memory -{ - namespace - { - std::optional static frame_allocator; - - auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::area_frame_allocator & - { - frame_allocator.emplace(memory_information); - return frame_allocator.value(); - } - - auto get_frame_allocator() -> allocator::area_frame_allocator & - { - exception_handling::assert(frame_allocator.has_value(), - "[Initialization] Frame allocator has not been created yet"); - return frame_allocator.value(); - } - } // namespace - - auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void - { - decltype(auto) allocator = get_frame_allocator(); - decltype(auto) active_table = paging::active_page_table::create_or_get(); - auto const start_page = paging::virtual_page::containing_address(heap_start); - auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - - paging::page_container::iterator const begin{start_page}; - paging::page_container::iterator const end{end_page}; - paging::page_container const pages{begin, end}; - - constexpr auto base_flags = paging::entry::WRITABLE; - auto const flags = base_flags | additional_flags; - - for (auto const & page : pages) - { - active_table.map_page_to_next_free_frame(allocator, page, flags); - } - } - - auto initialize_memory_management() -> void - { - bool static has_been_called = false; - arch::exception_handling::assert(!has_been_called, - "[Initialization] Memory management has already been initialized"); - has_been_called = true; - - auto const memory_information = multiboot::read_multiboot2(); - decltype(auto) allocator = create_frame_allocator(memory_information); - - kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); - - paging::kernel_mapper kernel(allocator, memory_information); - kernel.remap_kernel(); - video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - - remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - } -} // namespace teachos::arch::memory diff --git a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp deleted file mode 100644 index 3105120..0000000 --- a/arch/x86_64/pre/src/memory/multiboot/elf_symbols_section.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/memory/multiboot/elf_symbols_section.hpp" - -namespace teachos::arch::memory::multiboot -{ - auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool - { - return (flags & other) == other; - } - - auto elf_section_header::is_null() const -> bool - { - return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == elf_section_flags(0U) && - physical_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U && - fixed_table_entry_size == 0U; - } -} // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/pre/src/memory/multiboot/reader.cpp b/arch/x86_64/pre/src/memory/multiboot/reader.cpp deleted file mode 100644 index b05e6b3..0000000 --- a/arch/x86_64/pre/src/memory/multiboot/reader.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "arch/memory/multiboot/reader.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/exception_handling/assert.hpp" -#include "multiboot2/information.hpp" -// #include "arch/memory/multiboot/elf_symbols_section.hpp" -// #include "arch/memory/multiboot/info.hpp" - -#include -#include - -// namespace teachos::arch::memory::multiboot -// { -// namespace -// { -// template -// requires std::is_pointer::value -// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T -// { -// return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); -// } - -// auto process_memory_map(memory_map_header * mminfo) -> memory_area_container -// { -// auto const expected_entry_size = mminfo->entry_size; -// auto constexpr actual_entry_size = sizeof(memory_area); -// exception_handling::assert(expected_entry_size == actual_entry_size, -// "[Multiboot Reader] Unexpected memory area entry size"); - -// auto const total_size = mminfo->info.size; -// auto const total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; -// auto const number_of_entries = total_entries_size / actual_entry_size; - -// auto const begin = memory_area_container::iterator{&mminfo->entries}; -// auto const end = begin + number_of_entries; -// return memory_area_container{begin, end}; -// } - -// auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start, std::size_t & -// kernel_end) -// -> elf_section_header_container -// { -// auto const expected_entry_size = symbol->entry_size; -// auto constexpr actual_entry_size = sizeof(elf_section_header); -// exception_handling::assert(expected_entry_size == actual_entry_size, -// "[Multiboot Reader] Unexpected elf section header entry size"); - -// auto const expected_total_size = symbol->info.size; -// auto const actual_total_entry_size = actual_entry_size * symbol->number_of_sections; -// auto constexpr actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); -// auto const actual_total_size = actual_total_entry_size + actual_total_section_size; -// exception_handling::assert(expected_total_size == actual_total_size, -// "[Multiboot Reader] Unexpected elf symbols section header total size"); - -// auto const begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; auto const end = begin + symbol->number_of_sections; -// exception_handling::assert(begin->is_null(), -// "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); - -// elf_section_header_container sections{begin, end}; - -// auto allocated_sections = sections | std::views::filter([](auto const & section) { -// return section.flags.contains_flags(elf_section_flags::OCCUPIES_MEMORY); -// }); - -// auto const elf_section_with_lowest_physical_address = std::ranges::min_element( -// allocated_sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; -// }); - -// auto const elf_section_with_highest_physical_address = -// std::ranges::max_element(allocated_sections, [](auto const & a, auto const & b) { -// auto a_physical_address_end = a.physical_address + a.section_size; -// auto b_physical_address_end = b.physical_address + b.section_size; -// return a_physical_address_end < b_physical_address_end; -// }); - -// auto const symbol_table_section_count = std::ranges::count_if(sections, [](auto const & section) { -// return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == -// elf_section_type::SYMBOL_TABLE; -// }); -// auto const dynamic_section_count = std::ranges::count_if( -// sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; }); - -// exception_handling::assert( -// symbol_table_section_count == 1U, -// "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got more"); -// exception_handling::assert( -// dynamic_section_count <= 1U, -// "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); - -// auto const lowest_elf_section = *elf_section_with_lowest_physical_address; -// kernel_start = lowest_elf_section.physical_address; - -// auto const highest_elf_section = *elf_section_with_highest_physical_address; -// kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size; - -// return sections; -// } -// } // namespace - -// auto read_multiboot2() -> memory_information -// { -// memory_information mem_info{UINT64_MAX, -// 0U, -// elf_section_header_container{}, -// boot::multiboot_information_pointer, -// 0U, -// memory_area_container{}}; - -// auto const multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); -// auto const multiboot_tag = &multiboot_information_pointer->tags; -// mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size; - -// for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size)) -// { -// switch (tag->type) -// { -// case tag_type::ELF_SECTIONS: { -// auto const symbol = reinterpret_cast(tag); -// mem_info.sections = process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); -// break; -// } -// case tag_type::MEMORY_MAP: { -// auto const mminfo = reinterpret_cast(tag); -// mem_info.areas = process_memory_map(mminfo); -// break; -// } -// default: -// // All other cases are not important and can be ignored. -// break; -// } -// } -// return mem_info; -// } -// } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp b/arch/x86_64/pre/src/memory/paging/active_page_table.cpp deleted file mode 100644 index 930588d..0000000 --- a/arch/x86_64/pre/src/memory/paging/active_page_table.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "arch/memory/paging/active_page_table.hpp" - -namespace teachos::arch::memory::paging -{ - namespace - { - constexpr paging::virtual_address PAGE_TABLE_LEVEL_4_ADDRESS = 0xffff'ffff'ffff'f000; - } - - auto active_page_table::create_or_get() -> active_page_table & - { - page_table_handle static active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), - page_table_handle::LEVEL4}; - active_page_table static active_page{active_handle}; - return active_page; - } - - auto active_page_table::operator[](std::size_t index) -> entry & - { - return active_handle[index]; - } - - auto active_page_table::translate_address(virtual_address address) -> std::optional - { - auto const offset = address % allocator::PAGE_FRAME_SIZE; - auto const page = virtual_page::containing_address(address); - auto const frame = translate_page(page); - - if (frame.has_value()) - { - return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; - } - - return std::nullopt; - } - - auto active_page_table::translate_page(virtual_page page) -> std::optional - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const next_handle = current_handle.next_table(page.get_level_index(level)); - // If the next table method failed then it is highly likely that it was a huge page and we therefore have to - // parse the table differently. Therefore, we attempt to parse it using the method required by huge pages. - if (!next_handle.has_value()) - { - return translate_huge_page(page); - } - current_handle = next_handle.value(); - } - - auto const level1_index = page.get_level_index(page_table_handle::LEVEL1); - auto const level1_entry = current_handle[level1_index]; - return level1_entry.calculate_pointed_to_frame(); - } - - auto active_page_table::translate_huge_page(virtual_page page) -> std::optional - { - auto current_handle = active_handle; - auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4)); - - if (!level3_handle.has_value()) - { - return std::nullopt; - } - - auto const level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; - auto const level3_frame = level3_entry.calculate_pointed_to_frame(); - if (level3_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE)) - { - exception_handling::assert( - level3_frame.value().frame_number % (PAGE_TABLE_ENTRY_COUNT * PAGE_TABLE_ENTRY_COUNT) == 0U, - "[Page Mapper] Physical address must be 1 GiB aligned"); - return allocator::physical_frame{level3_frame.value().frame_number + - page.get_level_index(page_table_handle::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + - page.get_level_index(page_table_handle::LEVEL1)}; - } - - auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); - if (level2_handle.has_value()) - { - auto const level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; - auto const level2_frame = level2_entry.calculate_pointed_to_frame(); - if (level2_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE)) - { - exception_handling::assert(level2_frame.value().frame_number % PAGE_TABLE_ENTRY_COUNT == 0U, - "[Page Mapper] Physical address must be 2 MiB aligned"); - return allocator::physical_frame{level2_frame.value().frame_number + - page.get_level_index(page_table_handle::LEVEL1)}; - } - } - return std::nullopt; - } - - active_page_table::active_page_table(page_table_handle active_handle) - : active_handle(active_handle) - { - // Nothing to do - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp deleted file mode 100644 index 4e0610e..0000000 --- a/arch/x86_64/pre/src/memory/paging/inactive_page_table.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/memory/paging/inactive_page_table.hpp" - -namespace teachos::arch::memory::paging -{ - inactive_page_table::inactive_page_table(allocator::physical_frame frame) - : page_table_level_4_frame{frame} - { - // Nothing to do - } - - inactive_page_table::inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table, - temporary_page & temporary_page) - : page_table_level_4_frame{frame} - { - auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); - table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - temporary_page.unmap_page(active_page_table); - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/page_entry.cpp b/arch/x86_64/pre/src/memory/paging/page_entry.cpp deleted file mode 100644 index ec45068..0000000 --- a/arch/x86_64/pre/src/memory/paging/page_entry.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "arch/memory/paging/page_entry.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::paging -{ - namespace - { - constexpr std::size_t PHYSICAL_ADDRESS_MASK = 0x000f'ffff'ffff'f000; - } // namespace - - entry::entry(uint64_t flags) - : flags(flags) - { - // Nothing to do. - } - - entry::entry(multiboot::elf_section_flags elf_flags) - { - if (elf_flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) - { - flags |= entry::PRESENT; - } - - if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) - { - flags |= entry::WRITABLE; - } - - if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) - { - flags |= entry::EXECUTING_CODE_FORBIDDEN; - } - } - - auto entry::is_unused() const -> bool - { - return flags == 0U; - } - - auto entry::set_unused() -> void - { - flags = 0U; - } - - auto entry::set_user_accessible() -> void - { - flags |= entry::USER_ACCESSIBLE; - } - - auto entry::calculate_pointed_to_frame() const -> std::optional - { - if (contains_flags(PRESENT)) - { - auto const address = flags.to_ulong() & PHYSICAL_ADDRESS_MASK; - return allocator::physical_frame::containing_address(address); - } - return std::nullopt; - } - - auto entry::contains_flags(std::bitset<64U> other) const -> bool - { - return (flags & other) == other; - } - - auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void - { - exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, - "[Paging Entry] Start address is not aligned with page"); - - flags = frame.start_address() | additional_flags.to_ulong(); - } - - auto entry::get_flags() const -> std::bitset<64U> - { - return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/page_table.cpp b/arch/x86_64/pre/src/memory/paging/page_table.cpp deleted file mode 100644 index e79c3e5..0000000 --- a/arch/x86_64/pre/src/memory/paging/page_table.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "arch/memory/paging/page_table.hpp" - -#include -#include -#include - -/* - * This is a linker variable reference. This referenc cannot reside inside a namespace, because in - * that case the compiler would try to find arch::memory::paging::_end_of_image inside the ELF file. - */ -extern char _end_of_image; - -namespace teachos::arch::memory::paging -{ - /** - * @brief A Page table containing 512 entries. - */ - struct page_table - { - auto zero_entries() -> void; - - auto is_empty() const -> bool; - - auto next_table(std::size_t table_index) const -> std::optional; - - auto operator[](std::size_t index) -> entry &; - - auto operator[](std::size_t index) const -> entry const &; - - private: - /** - * @brief Calculates the address of the next page table level for the given table index. - * - * @note The next page table address is only valid if the corresponding entry is present and not a huge page. - * Meaning we use an index into a Level 4 page table to get the according Level 3 page table address. - * - * @param table_index Index of this page table in the page table one level higher. - * @return An optional of the address of the next page table or null. - */ - auto next_table_address(std::size_t table_index) const -> std::optional; - - std::array entries = - {}; ///< Entries containing addresses to page tables of a level below or - ///< actual virtual addresses for the level 1 page table. - }; - - auto page_table::zero_entries() -> void - { - std::ranges::for_each(entries, [](auto & entry) { entry.set_unused(); }); - } - - auto page_table::is_empty() const -> bool - { - return std::all_of(entries.begin(), entries.end(), [](entry const & entry) { return entry.is_unused(); }); - } - - auto page_table::next_table(std::size_t table_index) const -> std::optional - { - auto const address = next_table_address(table_index); - if (address.has_value()) - { - return reinterpret_cast(address.value()); - } - return std::nullopt; - } - - auto page_table::operator[](std::size_t index) -> entry & - { - exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - return entries[index]; - } - - auto page_table::operator[](std::size_t index) const -> entry const & - { - exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - return entries[index]; - } - - auto page_table::next_table_address(std::size_t table_index) const -> std::optional - { - auto const entry = this->operator[](table_index); - - if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) - { - auto const table_address = reinterpret_cast(this); - return ((table_address << 9) | (table_index << 12)); - } - return std::nullopt; - } - - page_table_handle::page_table_handle(page_table * table, page_table_handle::level table_level) - : table(table) - , table_level(table_level) - { - exception_handling::assert(table != nullptr, - "[Page Table] Attempted to pass nullptr as table to page table table method"); - } - - auto page_table_handle::zero_entries() -> void - { - table->zero_entries(); - } - - auto page_table_handle::is_empty() const -> bool - { - return table->is_empty(); - } - - auto page_table_handle::next_table(std::size_t table_index) const -> std::optional - { - exception_handling::assert(table_level != page_table_handle::LEVEL1, - "[Page Table] Attempted to call next_table on level 1 page table"); - auto const next_table = table->next_table(table_index); - if (next_table.has_value()) - { - auto const new_level = static_cast(table_level - 1); - return page_table_handle{next_table.value(), new_level}; - } - return std::nullopt; - } - - auto page_table_handle::get_level() const -> page_table_handle::level - { - return table_level; - } - - auto page_table_handle::operator[](std::size_t index) -> entry & - { - return table->operator[](index); - } - - auto operator--(page_table_handle::level & value) -> page_table_handle::level & - { - exception_handling::assert(value != page_table_handle::LEVEL1, - "[Page table] Attempted to decrement enum to value outside of range"); - auto new_value = static_cast::type>(value); - value = static_cast(--new_value); - return value; - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/temporary_page.cpp b/arch/x86_64/pre/src/memory/paging/temporary_page.cpp deleted file mode 100644 index 8e73523..0000000 --- a/arch/x86_64/pre/src/memory/paging/temporary_page.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "arch/memory/paging/temporary_page.hpp" - -#include "arch/memory/paging/page_entry.hpp" - -namespace teachos::arch::memory::paging -{ - auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) - -> page_table_handle - { - page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), - page_table_handle::LEVEL1}; - return handle; - } - - auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table) - -> virtual_address - { - exception_handling::assert(!active_table.translate_page(page).has_value(), - "[Temporary page] Page is already mapped"); - - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); - return page.start_address(); - } - - auto temporary_page::unmap_page(active_page_table & active_table) -> void - { - active_table.unmap_page(allocator, page); - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp b/arch/x86_64/pre/src/memory/paging/virtual_page.cpp deleted file mode 100644 index 8d34918..0000000 --- a/arch/x86_64/pre/src/memory/paging/virtual_page.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "arch/memory/paging/virtual_page.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::paging -{ - auto virtual_page::containing_address(virtual_address address) -> virtual_page - { - exception_handling::assert(address < 0x0000'8000'0000'0000 || address >= 0xffff'8000'0000'0000, - "[Virtual Page] Attempted to create virtual page from invalid address"); - return virtual_page{address / allocator::PAGE_FRAME_SIZE}; - } - - auto virtual_page::start_address() const -> virtual_address - { - return page_number * allocator::PAGE_FRAME_SIZE; - } - - auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t - { - return (page_number >> (level * 9U)) & 0x1FF; - } - - auto virtual_page::operator++(int) -> virtual_page - { - virtual_page const old_value = *this; - ++page_number; - return old_value; - } - - auto virtual_page::operator++() -> virtual_page & - { - ++page_number; - return *this; - } -} // namespace teachos::arch::memory::paging -- cgit v1.2.3