From e7eedd234954509f4f5ec52b2d62cbc4a1723936 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:39:09 +0000 Subject: libs: begin extraction of kernel std --- .../src/memory/heap/linked_list_allocator.cpp | 2 +- arch/x86_64/src/memory/multiboot/reader.cpp | 250 +++++++++++---------- 2 files changed, 128 insertions(+), 124 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index 63a6111..00ca366 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) : first(nullptr) - , mutex{stl::mutex{}} + , mutex{kstd::mutex{}} { auto const heap_size = heap_end - heap_start; exception_handling::assert( diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 2bf5b25..b05e6b3 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -2,130 +2,134 @@ #include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" -#include "arch/memory/multiboot/elf_symbols_section.hpp" -#include "arch/memory/multiboot/info.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 +// 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 -- cgit v1.2.3 From 14ed096fc5de6844cb116f3319c0d03043d26ea2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 17 Jul 2025 21:09:02 +0000 Subject: x86-64: prepare new architecture --- .../x86_64/src/memory/allocator/physical_frame.cpp | 24 ------ arch/x86_64/src/memory/region_allocator.cpp | 95 ++++++++++++++++++++++ 2 files changed, 95 insertions(+), 24 deletions(-) delete mode 100644 arch/x86_64/src/memory/allocator/physical_frame.cpp create mode 100644 arch/x86_64/src/memory/region_allocator.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp deleted file mode 100644 index ec387a1..0000000 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/memory/allocator/physical_frame.hpp" - -namespace teachos::arch::memory::allocator -{ - auto physical_frame::containing_address(physical_address address) -> physical_frame - { - return physical_frame{address / PAGE_FRAME_SIZE}; - } - - auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; } - - auto physical_frame::operator++(int) -> physical_frame - { - physical_frame const old_value = *this; - ++frame_number; - return old_value; - } - - auto physical_frame::operator++() -> physical_frame & - { - ++frame_number; - return *this; - } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp new file mode 100644 index 0000000..c9a98b4 --- /dev/null +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -0,0 +1,95 @@ +// #include "arch/memory/allocator/region_allocator.hpp" + +// #include "arch/exception_handling/assert.hpp" + +// #include +// #include +// #include + +#include "x86_64/memory/region_allocator.hpp" + +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/frame.hpp" + +#include + +#include +#include + +namespace teachos::x86_64::memory +{ + namespace + { + auto constexpr last_frame(multiboot2::memory_map::region const & region) + { + return frame::containing(physical_address{region.base + region.size_in_B - 1}); + } + } // namespace + + region_allocator::region_allocator(memory_information const & mem_info) + : m_next_frame{} + , m_current_region{} + , m_memory_map{} + , m_kernel_start(frame::containing(mem_info.image_range.first)) + , m_kernel_end(frame::containing(mem_info.image_range.second)) + , m_multiboot_start(frame::containing(mem_info.mbi_range.first)) + , m_multiboot_end(frame::containing(mem_info.mbi_range.second)) + { + choose_next_area(); + } + + auto region_allocator::choose_next_area() -> void + { + m_current_region.reset(); + auto next_area_with_free_frames = + m_memory_map | std::views::filter(&multiboot2::memory_map::region::available) | + std::views::filter([next = m_next_frame](auto const & region) { return last_frame(region) >= next; }); + + auto lowest_region_with_free_frames = + std::ranges::min_element(next_area_with_free_frames, [](auto lhs, auto rhs) { return lhs.base < rhs.base; }); + + if (lowest_region_with_free_frames != next_area_with_free_frames.end()) + { + m_current_region = *lowest_region_with_free_frames; + auto start_frame = frame::containing(physical_address{m_current_region->base}); + if (m_next_frame < start_frame) + { + m_next_frame = start_frame; + } + } + } + + auto region_allocator::allocate_frame() -> std::optional + { + if (!m_current_region) + { + return {}; + } + + auto const end_address = physical_address{m_current_region->base + m_current_region->size_in_B - 1}; + auto end_frame = frame::containing(end_address); + + if (m_next_frame > end_frame) + { + choose_next_area(); + } + else if (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + { + m_next_frame = m_kernel_end + 1; + } + else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + { + m_next_frame = m_multiboot_end + 1; + } + else + { + auto allocated = m_next_frame; + ++m_next_frame; + return allocated; + } + + return allocate_frame(); + } + + auto region_allocator::deallocate_frame(frame const &) -> void {} +} // namespace teachos::x86_64::memory -- cgit v1.2.3 From 1b65136a11453fe7e89320dfe6170a0cd75e60dd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:33:10 +0000 Subject: x86_64: clean up hw details --- arch/x86_64/src/memory/mmu.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 arch/x86_64/src/memory/mmu.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp new file mode 100644 index 0000000..31783fe --- /dev/null +++ b/arch/x86_64/src/memory/mmu.cpp @@ -0,0 +1,17 @@ +#include "x86_64/memory/mmu.hpp" + +#include "x86_64/cpu/registers.hpp" + +namespace teachos::x86_64::memory +{ + auto tlb_flush(linear_address address) -> void + { + asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); + } + + auto tlb_flush_all() -> void + { + auto current_value = cpu::read_control_register(cpu::control_register::cr3); + cpu::write_control_register(cpu::control_register::cr3, current_value); + } +} // namespace teachos::x86_64::memory -- cgit v1.2.3 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/src/memory/heap/bump_allocator.cpp | 54 ------ .../src/memory/heap/global_heap_allocator.cpp | 135 -------------- .../src/memory/heap/linked_list_allocator.cpp | 177 ------------------ arch/x86_64/src/memory/heap/memory_block.cpp | 15 -- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 200 --------------------- arch/x86_64/src/memory/main.cpp | 77 -------- .../src/memory/multiboot/elf_symbols_section.cpp | 13 -- arch/x86_64/src/memory/multiboot/reader.cpp | 135 -------------- .../x86_64/src/memory/paging/active_page_table.cpp | 98 ---------- .../src/memory/paging/inactive_page_table.cpp | 20 --- arch/x86_64/src/memory/paging/page_entry.cpp | 63 ------- arch/x86_64/src/memory/paging/page_table.cpp | 128 ------------- arch/x86_64/src/memory/paging/temporary_page.cpp | 29 --- arch/x86_64/src/memory/paging/virtual_page.cpp | 33 ---- 16 files changed, 1296 deletions(-) delete mode 100644 arch/x86_64/src/memory/allocator/area_frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/bump_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/global_heap_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/linked_list_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/memory_block.cpp delete mode 100644 arch/x86_64/src/memory/heap/user_heap_allocator.cpp delete mode 100644 arch/x86_64/src/memory/main.cpp delete mode 100644 arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp delete mode 100644 arch/x86_64/src/memory/multiboot/reader.cpp delete mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/inactive_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_entry.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/temporary_page.cpp delete mode 100644 arch/x86_64/src/memory/paging/virtual_page.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp deleted file mode 100644 index a5a1b49..0000000 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ /dev/null @@ -1,85 +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/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp deleted file mode 100644 index 3cdf9c7..0000000 --- a/arch/x86_64/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/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp deleted file mode 100644 index 525f45c..0000000 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#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/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp deleted file mode 100644 index 35cd623..0000000 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#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/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp deleted file mode 100644 index 00ca366..0000000 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#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/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp deleted file mode 100644 index bc97bd6..0000000 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#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/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp deleted file mode 100644 index 427a68a..0000000 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#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/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp deleted file mode 100644 index 2746a71..0000000 --- a/arch/x86_64/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 - { - 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/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp deleted file mode 100644 index f5d126b..0000000 --- a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp +++ /dev/null @@ -1,13 +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/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp deleted file mode 100644 index b05e6b3..0000000 --- a/arch/x86_64/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/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp deleted file mode 100644 index 0113869..0000000 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#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/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp deleted file mode 100644 index 4e0610e..0000000 --- a/arch/x86_64/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/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp deleted file mode 100644 index 57045ca..0000000 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#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/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp deleted file mode 100644 index eb11810..0000000 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ /dev/null @@ -1,128 +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/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp deleted file mode 100644 index 8e73523..0000000 --- a/arch/x86_64/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/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp deleted file mode 100644 index d374156..0000000 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ /dev/null @@ -1,33 +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 < 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 6434de8ff75a9143847ef529bc209790ac4909b3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:09:42 +0100 Subject: kapi: move frame and address to KAPI --- arch/x86_64/src/memory/mmu.cpp | 6 ++++-- arch/x86_64/src/memory/region_allocator.cpp | 16 ++++------------ 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index 31783fe..e573b4e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -2,8 +2,10 @@ #include "x86_64/cpu/registers.hpp" -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { + namespace cpu = cpu::x86_64; + auto tlb_flush(linear_address address) -> void { asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); @@ -14,4 +16,4 @@ namespace teachos::x86_64::memory auto current_value = cpu::read_control_register(cpu::control_register::cr3); cpu::write_control_register(cpu::control_register::cr3, current_value); } -} // namespace teachos::x86_64::memory +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index c9a98b4..91a5d49 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -1,22 +1,14 @@ -// #include "arch/memory/allocator/region_allocator.hpp" - -// #include "arch/exception_handling/assert.hpp" - -// #include -// #include -// #include - #include "x86_64/memory/region_allocator.hpp" -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/frame.hpp" +#include "kapi/memory/address.hpp" +#include "kapi/memory/frame.hpp" #include #include #include -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { namespace { @@ -92,4 +84,4 @@ namespace teachos::x86_64::memory } auto region_allocator::deallocate_frame(frame const &) -> void {} -} // namespace teachos::x86_64::memory +} // namespace teachos::memory::x86_64 -- cgit v1.2.3 From 845a96f5e6bfbbbeba19bf3df07f0e9de53d9a88 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:40:49 +0100 Subject: kapi: export frame_allocator interface --- arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 91a5d49..11ffce2 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -51,7 +51,7 @@ namespace teachos::memory::x86_64 } } - auto region_allocator::allocate_frame() -> std::optional + auto region_allocator::allocate() -> std::optional { if (!m_current_region) { @@ -80,8 +80,8 @@ namespace teachos::memory::x86_64 return allocated; } - return allocate_frame(); + return allocate(); } - auto region_allocator::deallocate_frame(frame const &) -> void {} + auto region_allocator::release(frame) -> void {} } // namespace teachos::memory::x86_64 -- cgit v1.2.3 From f06fc25b9a54a800c5301eec7320903380da947c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:11:09 +0100 Subject: x86_64/memory: simplify region allocator --- arch/x86_64/src/memory/region_allocator.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 11ffce2..d94e810 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -16,6 +16,11 @@ namespace teachos::memory::x86_64 { return frame::containing(physical_address{region.base + region.size_in_B - 1}); } + + auto constexpr falls_within(frame const & candidate, frame const & start, frame const & end) + { + return candidate >= start && candidate <= end; + } } // namespace region_allocator::region_allocator(memory_information const & mem_info) @@ -65,19 +70,17 @@ namespace teachos::memory::x86_64 { choose_next_area(); } - else if (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + else if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) { m_next_frame = m_kernel_end + 1; } - else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + else if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) { m_next_frame = m_multiboot_end + 1; } else { - auto allocated = m_next_frame; - ++m_next_frame; - return allocated; + return m_next_frame++; } return allocate(); -- cgit v1.2.3 From 40e67a6dba7837c562613016bdc8bad17d069e57 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:24:41 +0100 Subject: x86_64/memory: fix region allocator initialization During construction, the memory map was not extracted from the supplied memory information. This lead to a situation in which the allocator would never allocate any frames since it believed that there was no memory in the system. --- arch/x86_64/src/memory/region_allocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index d94e810..13103c7 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -26,7 +26,7 @@ namespace teachos::memory::x86_64 region_allocator::region_allocator(memory_information const & mem_info) : m_next_frame{} , m_current_region{} - , m_memory_map{} + , m_memory_map{mem_info.memory_map} , m_kernel_start(frame::containing(mem_info.image_range.first)) , m_kernel_end(frame::containing(mem_info.image_range.second)) , m_multiboot_start(frame::containing(mem_info.mbi_range.first)) -- 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 --- arch/x86_64/src/memory/region_allocator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 13103c7..a0579a3 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -12,12 +12,12 @@ namespace teachos::memory::x86_64 { namespace { - auto constexpr last_frame(multiboot2::memory_map::region const & region) + constexpr auto last_frame(multiboot2::memory_map::region const & region) { return frame::containing(physical_address{region.base + region.size_in_B - 1}); } - auto constexpr falls_within(frame const & candidate, frame const & start, frame const & end) + constexpr auto falls_within(frame const & candidate, frame const & start, frame const & end) { return candidate >= start && candidate <= end; } -- cgit v1.2.3 From b1143bde71bb029ac2bf7d08ba422fcdaedd56a6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 31 Oct 2025 07:19:16 +0100 Subject: build: enable linting --- arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index a0579a3..8ea76c6 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -40,10 +40,10 @@ namespace teachos::memory::x86_64 m_current_region.reset(); auto next_area_with_free_frames = m_memory_map | std::views::filter(&multiboot2::memory_map::region::available) | - std::views::filter([next = m_next_frame](auto const & region) { return last_frame(region) >= next; }); + std::views::filter([next = m_next_frame](auto const & region) -> bool { return last_frame(region) >= next; }); - auto lowest_region_with_free_frames = - std::ranges::min_element(next_area_with_free_frames, [](auto lhs, auto rhs) { return lhs.base < rhs.base; }); + auto lowest_region_with_free_frames = std::ranges::min_element( + next_area_with_free_frames, [](auto lhs, auto rhs) -> bool { return lhs.base < rhs.base; }); if (lowest_region_with_free_frames != next_area_with_free_frames.end()) { -- cgit v1.2.3 From a5ca21e45e9c8ead0b5895771c0b2f3fe3baf96b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Nov 2025 14:53:37 +0100 Subject: x86_64: rework control register access --- arch/x86_64/src/memory/mmu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index e573b4e..8ec8a2e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -13,7 +13,7 @@ namespace teachos::memory::x86_64 auto tlb_flush_all() -> void { - auto current_value = cpu::read_control_register(cpu::control_register::cr3); - cpu::write_control_register(cpu::control_register::cr3, current_value); + auto paging_root = cpu::cr3::read(); + cpu::cr3::write(paging_root); } } // namespace teachos::memory::x86_64 -- cgit v1.2.3 From 1db039ca1c67e8daba8b5ec6d5158cb2110e1410 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Nov 2025 16:06:15 +0100 Subject: x86_64: port basic page and page table abstractions --- arch/x86_64/src/memory/page_table.cpp | 57 ++++++++++++++++++++++++++++++++++ arch/x86_64/src/memory/paging_root.cpp | 19 ++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 arch/x86_64/src/memory/page_table.cpp create mode 100644 arch/x86_64/src/memory/paging_root.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp new file mode 100644 index 0000000..c716c5c --- /dev/null +++ b/arch/x86_64/src/memory/page_table.cpp @@ -0,0 +1,57 @@ +#include "x86_64/memory/page_table.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + auto page_table::entry::clear() -> void + { + m_raw = 0; + } + + auto page_table::entry::present() const -> bool + { + return (flags() & flags::present) != flags::empty; + } + + auto page_table::entry::huge() const -> bool + { + return (flags() & flags::huge_page) != flags::empty; + } + + auto page_table::entry::all_flags() const -> flags + { + return std::bit_cast(m_raw & ~frame_number_mask); + } + + auto page_table::entry::frame() const -> std::optional + { + if (present()) + { + return frame::containing(physical_address{m_raw & frame_number_mask}); + } + return std::nullopt; + } + + auto page_table::entry::frame(struct frame frame, flags flags) -> void + { + m_raw = (frame.start_address().raw() | static_cast(flags)); + }; + + auto page_table::operator[](std::size_t index) -> entry & + { + return m_entries.at(index); + } + + auto page_table::operator[](std::size_t index) const -> entry const & + { + return m_entries.at(index); + } + + auto page_table::clear() -> void + { + std::ranges::for_each(m_entries, &page_table::entry::clear); + } + +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp new file mode 100644 index 0000000..1234308 --- /dev/null +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -0,0 +1,19 @@ +#include "x86_64/memory/paging_root.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + namespace + { + constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; + } + + auto paging_root::get() -> paging_root & + { + auto pml4_address = std::bit_cast(PML_RECURSIVE_BASE); + return *pml4_address; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 57d140f41b462483b8f32a883cbb0b599b9feaed Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 30 Nov 2025 16:59:17 +0100 Subject: x86_64/memory: fix entry checks --- arch/x86_64/src/memory/page_table.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index c716c5c..1273676 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -12,12 +12,12 @@ namespace teachos::memory::x86_64 auto page_table::entry::present() const -> bool { - return (flags() & flags::present) != flags::empty; + return (all_flags() & flags::present) != flags::empty; } auto page_table::entry::huge() const -> bool { - return (flags() & flags::huge_page) != flags::empty; + return (all_flags() & flags::huge_page) != flags::empty; } auto page_table::entry::all_flags() const -> flags -- cgit v1.2.3 From 203355e51690073e571d4906d53f2494c3dad41b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 19:32:19 +0100 Subject: x86_64/memory: prepare scoped_mapping extraction --- arch/x86_64/src/memory/scoped_mapping.cpp | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 arch/x86_64/src/memory/scoped_mapping.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp new file mode 100644 index 0000000..c436ee5 --- /dev/null +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -0,0 +1,73 @@ +#include "x86_64/memory/scoped_mapping.hpp" + +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include "x86_64/memory/mmu.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + scoped_mapping::scoped_mapping(scoped_mapping && other) + : m_address{std::exchange(other.m_address, linear_address{})} + , m_allocator{std::exchange(other.m_allocator, nullptr)} + , m_mapped{std::exchange(other.m_mapped, false)} + {} + + scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) + : m_address{address} + , m_allocator{&allocator} + , m_mapped{false} + {} + + scoped_mapping::~scoped_mapping() + { + if (m_mapped) + { + unmap(); + x86_64::tlb_flush(m_address); + } + } + + auto scoped_mapping::operator=(scoped_mapping && other) -> scoped_mapping & + { + if (&other == this) + { + return *this; + } + + using std::swap; + + swap(m_address, other.m_address); + swap(m_allocator, other.m_allocator); + swap(m_mapped, other.m_mapped); + + return *this; + } + + auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * + { + static_cast(frame); + static_cast(flags); + + m_mapped = true; + + return nullptr; + } + + auto scoped_mapping::unmap() -> void + { + if (!m_mapped) + { + system::panic("[MEM] Tried to release an unmapped temporary mapping!"); + } + + // TODO: scan pages + // TODO: remove mapping + // TODO: release temporary table frames + m_mapped = false; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From be86be1facfce8fe3f376153b9c582f2c5c026aa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 12:31:53 +0100 Subject: x86_64/memory: extend scoped_mapping --- arch/x86_64/src/memory/paging_root.cpp | 41 +++++++++++++++++++++++++++++++ arch/x86_64/src/memory/scoped_mapping.cpp | 8 +++++- 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 1234308..6b65f60 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,6 +1,11 @@ #include "x86_64/memory/paging_root.hpp" +#include "kapi/memory.hpp" + +#include "x86_64/memory/page_utilities.hpp" + #include +#include namespace teachos::memory::x86_64 { @@ -16,4 +21,40 @@ namespace teachos::memory::x86_64 return *pml4_address; } + auto paging_root::translate(linear_address address) const -> std::optional + { + auto offset = address.raw() % PLATFORM_PAGE_SIZE; + return translate(page::containing(address)).transform([offset](auto frame) -> auto { + return physical_address{frame.start_address().raw() + offset}; + }); + } + + auto paging_root::translate(page page) const -> std::optional + { + auto pml3 = next(pml_index<4>(page)); + + if (!pml3) + { + return std::nullopt; + } + + auto handle_huge_page = [&] -> std::optional { + auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); + if (pml3_entry && pml3_entry->huge()) + { + auto pml3_entry_frame = *pml3_entry->frame(); + return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; + } + + // auto pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + + return std::nullopt; + }; + + return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); }) + .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); }) + .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); }) + .or_else(handle_huge_page); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index c436ee5..27c4785 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,6 +4,7 @@ #include "kapi/system.hpp" #include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/paging_root.hpp" #include @@ -20,7 +21,12 @@ namespace teachos::memory::x86_64 : m_address{address} , m_allocator{&allocator} , m_mapped{false} - {} + { + if (paging_root::get().translate(address)) + { + system::panic("[MEM] Tried to map a page that is already mapped!"); + } + } scoped_mapping::~scoped_mapping() { -- cgit v1.2.3 From a96b1b4b43a1ed962b412c3d28db0fe00661d96f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:40:10 +0100 Subject: x86_64/memory: extract PML4 injection --- arch/x86_64/src/memory/page_table.cpp | 6 +++ arch/x86_64/src/memory/paging_root.cpp | 18 +++++++- arch/x86_64/src/memory/scoped_mapping.cpp | 77 +++++++++++++++++++++++++------ 3 files changed, 86 insertions(+), 15 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 1273676..60bf94d 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -54,4 +54,10 @@ namespace teachos::memory::x86_64 std::ranges::for_each(m_entries, &page_table::entry::clear); } + auto page_table::empty() const noexcept -> bool + { + return std::ranges::all_of(m_entries, + [](auto const & entry) -> auto { return entry.all_flags() == entry::flags::empty; }); + } + } // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b65f60..a29304e 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -40,13 +40,27 @@ namespace teachos::memory::x86_64 auto handle_huge_page = [&] -> std::optional { auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (pml3_entry && pml3_entry->huge()) + if (!pml3_entry) + { + return std::nullopt; + } + else if (pml3_entry->huge()) { auto pml3_entry_frame = *pml3_entry->frame(); return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; } - // auto pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + auto pml2 = (*pml3)->next(pml_index<3>(page)); + auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; }); + if (!pml2_entry) + { + return std::nullopt; + } + else if (pml2_entry->huge()) + { + auto pml2_entry_frame = *pml2_entry->frame(); + return frame{pml2_entry_frame.number() + pml_index<1>(page)}; + } return std::nullopt; }; diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 27c4785..602198e 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,25 +4,28 @@ #include "kapi/system.hpp" #include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include #include namespace teachos::memory::x86_64 { scoped_mapping::scoped_mapping(scoped_mapping && other) - : m_address{std::exchange(other.m_address, linear_address{})} + : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} {} - scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) - : m_address{address} + scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + : m_page{page} , m_allocator{&allocator} , m_mapped{false} { - if (paging_root::get().translate(address)) + if (paging_root::get().translate(page)) { system::panic("[MEM] Tried to map a page that is already mapped!"); } @@ -33,7 +36,7 @@ namespace teachos::memory::x86_64 if (m_mapped) { unmap(); - x86_64::tlb_flush(m_address); + x86_64::tlb_flush(m_page.start_address()); } } @@ -46,7 +49,7 @@ namespace teachos::memory::x86_64 using std::swap; - swap(m_address, other.m_address); + swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); @@ -55,12 +58,38 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - static_cast(frame); - static_cast(flags); + auto & pml4 = paging_root::get(); + auto pml4_index = pml_index<4>(m_page); + if (!pml4[pml4_index].present()) + { + auto new_frame = m_allocator->allocate(); + pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at(pml4.next(pml4_index).value()); + } - m_mapped = true; + auto pml3 = pml4.next(pml4_index).value(); + auto pml3_index = pml_index<3>(m_page); + if (!(*pml3)[pml3_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml3).next(pml3_index).value()); + } - return nullptr; + auto pml2 = (*pml3).next(pml3_index).value(); + auto pml2_index = pml_index<2>(m_page); + if (!(*pml2)[pml2_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml2).next(pml2_index).value()); + } + + auto pml1 = (*pml2).next(pml2_index).value(); + auto pml1_index = pml_index<1>(m_page); + (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + + return static_cast(frame.start_address()); } auto scoped_mapping::unmap() -> void @@ -70,9 +99,31 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - // TODO: scan pages - // TODO: remove mapping - // TODO: release temporary table frames + auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml2 = pml3->next(pml_index<3>(m_page)).value(); + auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } + + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } + + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } + m_mapped = false; } -- cgit v1.2.3 From 331c070547634a2096c5e2165559fb0f11ee6330 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:49:36 +0100 Subject: kapi: make PLATFORM_*_SIZE constexpr --- arch/x86_64/src/memory/paging_root.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index a29304e..6b8e1ab 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -23,7 +23,7 @@ namespace teachos::memory::x86_64 auto paging_root::translate(linear_address address) const -> std::optional { - auto offset = address.raw() % PLATFORM_PAGE_SIZE; + auto offset = address.raw() % page::size; return translate(page::containing(address)).transform([offset](auto frame) -> auto { return physical_address{frame.start_address().raw() + offset}; }); -- cgit v1.2.3 From 9331afdcbbe95bc1bd79d657f0d7c5b91a19a375 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 19:39:03 +0100 Subject: x86_64/memory: fix temporary page unmapping --- arch/x86_64/src/memory/scoped_mapping.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 602198e..191a7ad 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -89,6 +89,8 @@ namespace teachos::memory::x86_64 auto pml1_index = pml_index<1>(m_page); (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + m_mapped = true; + return static_cast(frame.start_address()); } -- cgit v1.2.3 From 9907cb6c0108b89b846fee52de56a9c335caaedc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 17:08:44 +0100 Subject: x86_64/memory: fix return in scoped_mapping::map Previously, scoped_mapping::map returned the start address of the frame. Unfortunately, the initial mapping performed in the bootstrap code maps physical memory starting at 0x0000'0000'0000'0000, which means no fault was triggered. The map function now correctly return the start address of the scoped_mapping's page, which must alway work by definition. --- arch/x86_64/src/memory/scoped_mapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 191a7ad..5446b2a 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -91,7 +91,7 @@ namespace teachos::memory::x86_64 m_mapped = true; - return static_cast(frame.start_address()); + return static_cast(m_page.start_address()); } auto scoped_mapping::unmap() -> void -- cgit v1.2.3 From 448632c3c9c919e8eda44e8a83082f60983057b7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:16:36 +0100 Subject: x86_64/memory: add missing noexcept specifiers --- arch/x86_64/src/memory/scoped_mapping.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 5446b2a..6e2328d 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -14,7 +14,7 @@ namespace teachos::memory::x86_64 { - scoped_mapping::scoped_mapping(scoped_mapping && other) + scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} @@ -40,7 +40,7 @@ namespace teachos::memory::x86_64 } } - auto scoped_mapping::operator=(scoped_mapping && other) -> scoped_mapping & + auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { if (&other == this) { -- cgit v1.2.3 From f3dd2b2f5bd1b5dd4d4309a30db3c7733b8f63bb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:40:54 +0100 Subject: x86_64/memory: only deallocate allocated frames --- arch/x86_64/src/memory/scoped_mapping.cpp | 39 +++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 6e2328d..be15330 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -18,12 +18,14 @@ namespace teachos::memory::x86_64 : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} + , m_allocated{std::exchange(other.m_allocated, 0)} {} scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) : m_page{page} , m_allocator{&allocator} , m_mapped{false} + , m_allocated{} { if (paging_root::get().translate(page)) { @@ -52,6 +54,7 @@ namespace teachos::memory::x86_64 swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); + swap(m_allocated, other.m_allocated); return *this; } @@ -65,6 +68,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at(pml4.next(pml4_index).value()); + m_allocated |= 1uz << 2; } auto pml3 = pml4.next(pml4_index).value(); @@ -74,6 +78,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at((*pml3).next(pml3_index).value()); + m_allocated |= 1uz << 1; } auto pml2 = (*pml3).next(pml3_index).value(); @@ -83,6 +88,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at((*pml2).next(pml2_index).value()); + m_allocated |= 1uz << 0; } auto pml1 = (*pml2).next(pml2_index).value(); @@ -105,25 +111,34 @@ namespace teachos::memory::x86_64 auto pml2 = pml3->next(pml_index<3>(m_page)).value(); auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; - (*pml1)[pml_index<1>(m_page)].clear(); - if (pml1->empty()) + if (m_allocated & 1uz << 0) { - m_allocator->release(pml1_entry.frame().value()); + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } } - auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; - (*pml2)[pml_index<2>(m_page)].clear(); - if (pml2->empty()) + if (m_allocated & 1uz << 1) { - m_allocator->release(pml2_entry.frame().value()); + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } } - auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; - (*pml3)[pml_index<3>(m_page)].clear(); - if (pml3->empty()) + if (m_allocated & 1uz << 2) { - m_allocator->release(pml3_entry.frame().value()); + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } } m_mapped = false; -- cgit v1.2.3 From fc26187d9ace9798d9494341f3513eb0840b006d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:45:30 +0100 Subject: x86_64/memory: make scoped_mapping swappable --- arch/x86_64/src/memory/scoped_mapping.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index be15330..c9c6459 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -44,18 +44,7 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - if (&other == this) - { - return *this; - } - - using std::swap; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - + this->swap(other); return *this; } @@ -144,4 +133,22 @@ namespace teachos::memory::x86_64 m_mapped = false; } + auto scoped_mapping::swap(scoped_mapping & other) -> void + { + using std::swap; + + if (&other == this) + return; + + swap(m_page, other.m_page); + swap(m_allocator, other.m_allocator); + swap(m_mapped, other.m_mapped); + swap(m_allocated, other.m_allocated); + } + + auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void + { + lhs.swap(rhs); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 448a79328544e3ecb72d0b3b95c0b9b0d49faafc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 12:27:37 +0100 Subject: x86_64/memory: fix scoped_mapping unmap logic --- arch/x86_64/src/memory/scoped_mapping.cpp | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index c9c6459..44dbf45 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -96,38 +96,32 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml4 = &paging_root::get(); + auto pml3 = pml4->next(pml_index<4>(m_page)).value(); auto pml2 = pml3->next(pml_index<3>(m_page)).value(); auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + (*pml1)[pml_index<1>(m_page)].clear(); + if (m_allocated & 1uz << 0) { - auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; - (*pml1)[pml_index<1>(m_page)].clear(); - if (pml1->empty()) - { - m_allocator->release(pml1_entry.frame().value()); - } + auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); + m_allocator->release(pml1_frame); + (*pml2)[pml_index<2>(m_page)].clear(); } if (m_allocated & 1uz << 1) { - auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; - (*pml2)[pml_index<2>(m_page)].clear(); - if (pml2->empty()) - { - m_allocator->release(pml2_entry.frame().value()); - } + auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); + m_allocator->release(pml2_frame); + (*pml3)[pml_index<3>(m_page)].clear(); } if (m_allocated & 1uz << 2) { - auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; - (*pml3)[pml_index<3>(m_page)].clear(); - if (pml3->empty()) - { - m_allocator->release(pml3_entry.frame().value()); - } + auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); + m_allocator->release(pml3_frame); + (*pml4)[pml_index<4>(m_page)].clear(); } m_mapped = false; -- cgit v1.2.3 From b9d445bf92725d79269becf978059e040519c00a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 16:51:44 +0100 Subject: x86_64/memory: implement simple kernel remapper --- arch/x86_64/src/memory/kernel_mapper.cpp | 107 +++++++++++++++++++++++++++++++ arch/x86_64/src/memory/page_table.cpp | 13 ++++ arch/x86_64/src/memory/paging_root.cpp | 55 +++++++++++++++- 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/src/memory/kernel_mapper.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp new file mode 100644 index 0000000..b1d12a4 --- /dev/null +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -0,0 +1,107 @@ +#include "x86_64/memory/kernel_mapper.hpp" + +#include "kapi/cio.hpp" +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +#include +#include + +#include +#include + +namespace teachos::memory::x86_64 +{ + + inline namespace + { + using namespace std::string_view_literals; + + constexpr auto static ignored_section_prefixes = std::array{ + ".boot_"sv, + }; + + constexpr auto static user_accessible_prefixes = std::array{ + ".user"sv, + ".stl"sv, + }; + + } // namespace + + kernel_mapper::kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi) + : m_allocator{&allocator} + , m_mbi(std::move(mbi)) + , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} + {} + + auto kernel_mapper::remap_kernel() -> void + { + auto elf_information = m_mbi->maybe_elf_symbols(); + if (!elf_information) + { + system::panic("[x86_64:MEM] ELF section information is not available."); + } + + auto sections = *elf_information; + auto allocated_sections = + std::views::all(sections) | std::views::filter(&elf::section_header::allocated) | + std::views::filter([&](auto const & section) -> auto { + auto name = sections.name(section); + return !std::ranges::any_of(ignored_section_prefixes, + [&](auto const & prefix) -> auto { return name.starts_with(prefix); }); + }); + + if (allocated_sections.empty()) + { + system::panic("[x86_64:MEM] No allocated ELF sections were found."); + } + + std::ranges::for_each(allocated_sections, + [&](auto const & section) -> auto { map_section(section, sections.name(section)); }); + } + + auto kernel_mapper::map_section(section_header_type const & section, std::string_view name) -> void + { + cio::print("[x86_64:MEM] mapping "); + cio::println(name); + + auto number_of_pages = (section.size + (PLATFORM_PAGE_SIZE - 1)) / PLATFORM_PAGE_SIZE; + + auto linear_start_address = linear_address{section.virtual_load_address}; + auto physical_start_address = physical_address{section.virtual_load_address & ~m_kernel_load_base}; + + auto first_page = page::containing(linear_start_address); + auto first_frame = frame::containing(physical_start_address); + + auto page_flags = page_table::entry::flags::empty; + + if (section.writable()) + { + page_flags |= page_table::entry::flags::writable; + } + + if (!section.executable()) + { + page_flags |= page_table::entry::flags::no_execute; + } + + auto is_prefix_of_name = [=](auto prefix) -> bool { + return name.starts_with(prefix); + }; + + if (std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name)) + { + page_flags |= page_table::entry::flags::user_accessible; + } + + for (auto i = 0uz; i < number_of_pages; ++i) + { + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + } + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 60bf94d..e797b22 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -1,6 +1,7 @@ #include "x86_64/memory/page_table.hpp" #include +#include namespace teachos::memory::x86_64 { @@ -25,6 +26,18 @@ namespace teachos::memory::x86_64 return std::bit_cast(m_raw & ~frame_number_mask); } + auto page_table::entry::all_flags(flags flags) -> void + { + m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags); + } + + auto page_table::entry::operator|=(flags rhs) -> page_table::entry & + { + auto raw_flags = std::to_underlying(rhs) & ~frame_number_mask; + m_raw |= raw_flags; + return *this; + } + auto page_table::entry::frame() const -> std::optional { if (present()) diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b8e1ab..5ca2bf0 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,10 +1,15 @@ #include "x86_64/memory/paging_root.hpp" #include "kapi/memory.hpp" +#include "kapi/system.hpp" +#include "x86_64/memory/page_table.hpp" #include "x86_64/memory/page_utilities.hpp" +#include "x86_64/memory/scoped_mapping.hpp" +#include #include +#include #include namespace teachos::memory::x86_64 @@ -13,7 +18,45 @@ namespace teachos::memory::x86_64 namespace { constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; - } + + //! Perform the actual mapping of the page, via the recursive page map. + //! + //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries + //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When + //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit added, thus + //! still enforcing non-writability and non-execution of the affected page. + template + requires(Level > 1uz && Level < 5uz) + auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags, + frame_allocator & allocator) + { + auto index = pml_index(page); + flags = flags & ~page_table::entry::flags::no_execute; + flags = flags | page_table::entry::flags::writable; + if (!(*pml)[index].present()) + { + auto new_table_frame = allocator.allocate(); + auto mapping = scoped_mapping{page, allocator}; + (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); + auto new_table = std::optional{std::construct_at(*pml->next(index))}; + return new_table; + } + (*pml)[index] |= flags; + return pml->next(index); + } + + //! Perform the actual PML1 update. + auto do_map(page_table * pml, page page, frame frame, page_table::entry::flags flags) -> std::optional + { + auto index = pml_index<1>(page); + if ((*pml)[index].present()) + { + system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); + } + (*pml)[index].frame(frame, page_table::entry::flags::present | flags); + return std::optional{static_cast(page.start_address())}; + } + } // namespace auto paging_root::get() -> paging_root & { @@ -71,4 +114,14 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } + auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) + -> std::optional + { + return std::optional{this} + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From eafbf588760c289b7f54a4771b39af0ccfe8cf59 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 21:55:42 +0100 Subject: kapi: extract page_mapper interface --- arch/x86_64/src/memory/kernel_mapper.cpp | 7 +- arch/x86_64/src/memory/paging_root.cpp | 52 ++++++++++--- arch/x86_64/src/memory/recursive_page_mapper.cpp | 38 +++++++++ arch/x86_64/src/memory/scoped_mapping.cpp | 99 ++---------------------- 4 files changed, 92 insertions(+), 104 deletions(-) create mode 100644 arch/x86_64/src/memory/recursive_page_mapper.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index b1d12a4..f46b5b5 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -32,9 +32,8 @@ namespace teachos::memory::x86_64 } // namespace - kernel_mapper::kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi) - : m_allocator{&allocator} - , m_mbi(std::move(mbi)) + kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi) + : m_mbi{std::move(mbi)} , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} {} @@ -100,7 +99,7 @@ namespace teachos::memory::x86_64 for (auto i = 0uz; i < number_of_pages; ++i) { - paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags); } } diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 5ca2bf0..c458093 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -27,16 +27,15 @@ namespace teachos::memory::x86_64 //! still enforcing non-writability and non-execution of the affected page. template requires(Level > 1uz && Level < 5uz) - auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags, - frame_allocator & allocator) + auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags) { auto index = pml_index(page); flags = flags & ~page_table::entry::flags::no_execute; flags = flags | page_table::entry::flags::writable; if (!(*pml)[index].present()) { - auto new_table_frame = allocator.allocate(); - auto mapping = scoped_mapping{page, allocator}; + auto new_table_frame = active_allocator().allocate(); + auto mapping = scoped_mapping{page}; (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); auto new_table = std::optional{std::construct_at(*pml->next(index))}; return new_table; @@ -114,14 +113,49 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } - auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) - -> std::optional + auto paging_root::map(page page, frame frame, page_table::entry::flags flags) -> std::optional { return std::optional{this} - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); } + auto paging_root::unmap(page page) -> void + { + if (!this->translate(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + + auto pml4 = this; + auto pml3 = pml4->next(pml_index<4>(page)).value(); + auto pml2 = pml3->next(pml_index<3>(page)).value(); + auto pml1 = pml2->next(pml_index<2>(page)).value(); + + (*pml1)[pml_index<1>(page)].clear(); + + if (pml1->empty()) + { + auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); + active_allocator().release(pml1_frame); + (*pml2)[pml_index<2>(page)].clear(); + } + + if (pml2->empty()) + { + auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); + active_allocator().release(pml2_frame); + (*pml3)[pml_index<3>(page)].clear(); + } + + if (pml3->empty()) + { + auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); + active_allocator().release(pml3_frame); + (*pml4)[pml_index<4>(page)].clear(); + } + } + } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp new file mode 100644 index 0000000..ea89f38 --- /dev/null +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -0,0 +1,38 @@ +#include "x86_64/memory/recursive_page_mapper.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +namespace teachos::memory::x86_64 +{ + recursive_page_mapper::recursive_page_mapper(frame_allocator & allocator) + : m_allocator{&allocator} + {} + + auto recursive_page_mapper::map(page page, frame frame, flags flags) -> std::byte * + { + return paging_root::get().map(page, frame, to_table_flags(flags)).value_or(nullptr); + } + + auto recursive_page_mapper::unmap(page page) -> void + { + if (!try_unmap(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + } + + auto recursive_page_mapper::try_unmap(page page) -> bool + { + auto & root = paging_root::get(); + if (!root.translate(page)) + { + return false; + } + root.unmap(page); + return true; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 44dbf45..6f3461c 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -5,10 +5,8 @@ #include "x86_64/memory/mmu.hpp" #include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" -#include #include namespace teachos::memory::x86_64 @@ -16,16 +14,12 @@ namespace teachos::memory::x86_64 scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} - , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} - , m_allocated{std::exchange(other.m_allocated, 0)} {} - scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + scoped_mapping::scoped_mapping(page page) : m_page{page} - , m_allocator{&allocator} , m_mapped{false} - , m_allocated{} { if (paging_root::get().translate(page)) { @@ -44,105 +38,28 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - this->swap(other); + swap(*this, other); return *this; } auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto & pml4 = paging_root::get(); - auto pml4_index = pml_index<4>(m_page); - if (!pml4[pml4_index].present()) - { - auto new_frame = m_allocator->allocate(); - pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at(pml4.next(pml4_index).value()); - m_allocated |= 1uz << 2; - } - - auto pml3 = pml4.next(pml4_index).value(); - auto pml3_index = pml_index<3>(m_page); - if (!(*pml3)[pml3_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml3).next(pml3_index).value()); - m_allocated |= 1uz << 1; - } - - auto pml2 = (*pml3).next(pml3_index).value(); - auto pml2_index = pml_index<2>(m_page); - if (!(*pml2)[pml2_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml2).next(pml2_index).value()); - m_allocated |= 1uz << 0; - } - - auto pml1 = (*pml2).next(pml2_index).value(); - auto pml1_index = pml_index<1>(m_page); - (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); - + auto result = active_mapper().map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; - - return static_cast(m_page.start_address()); + return result; } auto scoped_mapping::unmap() -> void { - if (!m_mapped) - { - system::panic("[MEM] Tried to release an unmapped temporary mapping!"); - } - - auto pml4 = &paging_root::get(); - auto pml3 = pml4->next(pml_index<4>(m_page)).value(); - auto pml2 = pml3->next(pml_index<3>(m_page)).value(); - auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - - (*pml1)[pml_index<1>(m_page)].clear(); - - if (m_allocated & 1uz << 0) - { - auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); - m_allocator->release(pml1_frame); - (*pml2)[pml_index<2>(m_page)].clear(); - } - - if (m_allocated & 1uz << 1) - { - auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); - m_allocator->release(pml2_frame); - (*pml3)[pml_index<3>(m_page)].clear(); - } - - if (m_allocated & 1uz << 2) - { - auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); - m_allocator->release(pml3_frame); - (*pml4)[pml_index<4>(m_page)].clear(); - } - + active_mapper().unmap(m_page); m_mapped = false; } - auto scoped_mapping::swap(scoped_mapping & other) -> void - { - using std::swap; - - if (&other == this) - return; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - } - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void { - lhs.swap(rhs); + using std::swap; + swap(lhs.m_page, rhs.m_page); + swap(lhs.m_mapped, rhs.m_mapped); } } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 998a001fc621ca0e7560ca09a8acd29469ae3373 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 17:46:02 +0100 Subject: docs: improve documentation --- arch/x86_64/src/memory/page_table.cpp | 18 +++++++++--------- arch/x86_64/src/memory/region_allocator.cpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index e797b22..0e404e5 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -6,39 +6,39 @@ namespace teachos::memory::x86_64 { - auto page_table::entry::clear() -> void + auto page_table::entry::clear() noexcept -> void { m_raw = 0; } - auto page_table::entry::present() const -> bool + auto page_table::entry::present() const noexcept -> bool { return (all_flags() & flags::present) != flags::empty; } - auto page_table::entry::huge() const -> bool + auto page_table::entry::huge() const noexcept -> bool { return (all_flags() & flags::huge_page) != flags::empty; } - auto page_table::entry::all_flags() const -> flags + auto page_table::entry::all_flags() const noexcept -> flags { return std::bit_cast(m_raw & ~frame_number_mask); } - auto page_table::entry::all_flags(flags flags) -> void + auto page_table::entry::all_flags(flags flags) noexcept -> void { m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags); } - auto page_table::entry::operator|=(flags rhs) -> page_table::entry & + auto page_table::entry::operator|=(flags rhs) noexcept -> page_table::entry & { auto raw_flags = std::to_underlying(rhs) & ~frame_number_mask; m_raw |= raw_flags; return *this; } - auto page_table::entry::frame() const -> std::optional + auto page_table::entry::frame() const noexcept -> std::optional { if (present()) { @@ -47,7 +47,7 @@ namespace teachos::memory::x86_64 return std::nullopt; } - auto page_table::entry::frame(struct frame frame, flags flags) -> void + auto page_table::entry::frame(struct frame frame, flags flags) noexcept -> void { m_raw = (frame.start_address().raw() | static_cast(flags)); }; @@ -62,7 +62,7 @@ namespace teachos::memory::x86_64 return m_entries.at(index); } - auto page_table::clear() -> void + auto page_table::clear() noexcept -> void { std::ranges::for_each(m_entries, &page_table::entry::clear); } diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 8ea76c6..e477ec0 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -56,7 +56,7 @@ namespace teachos::memory::x86_64 } } - auto region_allocator::allocate() -> std::optional + auto region_allocator::allocate() noexcept -> std::optional { if (!m_current_region) { -- cgit v1.2.3 From cf8d0d899ee17db734ce8ab7ee618333eb1767f2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 18:36:23 +0100 Subject: kapi: finish documentation --- arch/x86_64/src/memory/paging_root.cpp | 8 ++++---- arch/x86_64/src/memory/recursive_page_mapper.cpp | 2 +- arch/x86_64/src/memory/scoped_mapping.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index c458093..078686b 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -34,7 +34,7 @@ namespace teachos::memory::x86_64 flags = flags | page_table::entry::flags::writable; if (!(*pml)[index].present()) { - auto new_table_frame = active_allocator().allocate(); + auto new_table_frame = active_frame_allocator().allocate(); auto mapping = scoped_mapping{page}; (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); auto new_table = std::optional{std::construct_at(*pml->next(index))}; @@ -139,21 +139,21 @@ namespace teachos::memory::x86_64 if (pml1->empty()) { auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); - active_allocator().release(pml1_frame); + active_frame_allocator().release(pml1_frame); (*pml2)[pml_index<2>(page)].clear(); } if (pml2->empty()) { auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); - active_allocator().release(pml2_frame); + active_frame_allocator().release(pml2_frame); (*pml3)[pml_index<3>(page)].clear(); } if (pml3->empty()) { auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); - active_allocator().release(pml3_frame); + active_frame_allocator().release(pml3_frame); (*pml4)[pml_index<4>(page)].clear(); } } diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index ea89f38..47148f0 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -24,7 +24,7 @@ namespace teachos::memory::x86_64 } } - auto recursive_page_mapper::try_unmap(page page) -> bool + auto recursive_page_mapper::try_unmap(page page) noexcept -> bool { auto & root = paging_root::get(); if (!root.translate(page)) diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 6f3461c..e243dc9 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -44,14 +44,14 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto result = active_mapper().map(m_page, frame, to_mapper_flags(flags)); + auto result = active_page_mapper().map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; return result; } auto scoped_mapping::unmap() -> void { - active_mapper().unmap(m_page); + active_page_mapper().unmap(m_page); m_mapped = false; } -- cgit v1.2.3 From 50c9c9a1d963e66f7658ab31e9ecd65bf227cfff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 14:07:28 +0100 Subject: x86_64/memory: clean up dependencies --- arch/x86_64/src/memory/kernel_mapper.cpp | 25 ++-- arch/x86_64/src/memory/paging_root.cpp | 149 +---------------------- arch/x86_64/src/memory/recursive_page_mapper.cpp | 85 ++++++++++++- arch/x86_64/src/memory/scoped_mapping.cpp | 11 +- 4 files changed, 103 insertions(+), 167 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index f46b5b5..a28cf00 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -5,8 +5,6 @@ #include "kapi/system.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/paging_root.hpp" #include #include @@ -17,7 +15,7 @@ namespace teachos::memory::x86_64 { - inline namespace + namespace { using namespace std::string_view_literals; @@ -37,7 +35,7 @@ namespace teachos::memory::x86_64 , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} {} - auto kernel_mapper::remap_kernel() -> void + auto kernel_mapper::remap_kernel(page_mapper & mapper) -> void { auto elf_information = m_mbi->maybe_elf_symbols(); if (!elf_information) @@ -60,10 +58,11 @@ namespace teachos::memory::x86_64 } std::ranges::for_each(allocated_sections, - [&](auto const & section) -> auto { map_section(section, sections.name(section)); }); + [&](auto const & section) -> auto { map_section(section, sections.name(section), mapper); }); } - auto kernel_mapper::map_section(section_header_type const & section, std::string_view name) -> void + auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, page_mapper & mapper) + -> void { cio::print("[x86_64:MEM] mapping "); cio::println(name); @@ -76,30 +75,30 @@ namespace teachos::memory::x86_64 auto first_page = page::containing(linear_start_address); auto first_frame = frame::containing(physical_start_address); - auto page_flags = page_table::entry::flags::empty; + auto page_flags = page_mapper::flags::empty; if (section.writable()) { - page_flags |= page_table::entry::flags::writable; + page_flags |= page_mapper::flags::writable; } - if (!section.executable()) + if (section.executable()) { - page_flags |= page_table::entry::flags::no_execute; + page_flags |= page_mapper::flags::executable; } auto is_prefix_of_name = [=](auto prefix) -> bool { return name.starts_with(prefix); }; - if (std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name)) + if (!std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name)) { - page_flags |= page_table::entry::flags::user_accessible; + page_flags |= page_mapper::flags::supervisor_only; } for (auto i = 0uz; i < number_of_pages; ++i) { - paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags); + mapper.map(first_page + i, first_frame + i, page_flags); } } diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 078686b..4f88657 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,161 +1,18 @@ #include "x86_64/memory/paging_root.hpp" -#include "kapi/memory.hpp" -#include "kapi/system.hpp" - -#include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/page_utilities.hpp" -#include "x86_64/memory/scoped_mapping.hpp" - -#include #include -#include -#include namespace teachos::memory::x86_64 { namespace { - constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; - - //! Perform the actual mapping of the page, via the recursive page map. - //! - //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries - //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When - //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit added, thus - //! still enforcing non-writability and non-execution of the affected page. - template - requires(Level > 1uz && Level < 5uz) - auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags) - { - auto index = pml_index(page); - flags = flags & ~page_table::entry::flags::no_execute; - flags = flags | page_table::entry::flags::writable; - if (!(*pml)[index].present()) - { - auto new_table_frame = active_frame_allocator().allocate(); - auto mapping = scoped_mapping{page}; - (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); - auto new_table = std::optional{std::construct_at(*pml->next(index))}; - return new_table; - } - (*pml)[index] |= flags; - return pml->next(index); - } - - //! Perform the actual PML1 update. - auto do_map(page_table * pml, page page, frame frame, page_table::entry::flags flags) -> std::optional - { - auto index = pml_index<1>(page); - if ((*pml)[index].present()) - { - system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); - } - (*pml)[index].frame(frame, page_table::entry::flags::present | flags); - return std::optional{static_cast(page.start_address())}; - } + constexpr auto recursive_base = std::uintptr_t{0177777'776'776'776'776'0000uz}; } // namespace - auto paging_root::get() -> paging_root & - { - auto pml4_address = std::bit_cast(PML_RECURSIVE_BASE); - return *pml4_address; - } - - auto paging_root::translate(linear_address address) const -> std::optional - { - auto offset = address.raw() % page::size; - return translate(page::containing(address)).transform([offset](auto frame) -> auto { - return physical_address{frame.start_address().raw() + offset}; - }); - } - - auto paging_root::translate(page page) const -> std::optional - { - auto pml3 = next(pml_index<4>(page)); - - if (!pml3) - { - return std::nullopt; - } - - auto handle_huge_page = [&] -> std::optional { - auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (!pml3_entry) - { - return std::nullopt; - } - else if (pml3_entry->huge()) - { - auto pml3_entry_frame = *pml3_entry->frame(); - return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; - } - - auto pml2 = (*pml3)->next(pml_index<3>(page)); - auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; }); - if (!pml2_entry) - { - return std::nullopt; - } - else if (pml2_entry->huge()) - { - auto pml2_entry_frame = *pml2_entry->frame(); - return frame{pml2_entry_frame.number() + pml_index<1>(page)}; - } - - return std::nullopt; - }; - - return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); }) - .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); }) - .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); }) - .or_else(handle_huge_page); - } - - auto paging_root::map(page page, frame frame, page_table::entry::flags flags) -> std::optional + auto paging_root::get() -> paging_root * { - return std::optional{this} - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); - } - - auto paging_root::unmap(page page) -> void - { - if (!this->translate(page)) - { - system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); - } - - auto pml4 = this; - auto pml3 = pml4->next(pml_index<4>(page)).value(); - auto pml2 = pml3->next(pml_index<3>(page)).value(); - auto pml1 = pml2->next(pml_index<2>(page)).value(); - - (*pml1)[pml_index<1>(page)].clear(); - - if (pml1->empty()) - { - auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); - active_frame_allocator().release(pml1_frame); - (*pml2)[pml_index<2>(page)].clear(); - } - - if (pml2->empty()) - { - auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); - active_frame_allocator().release(pml2_frame); - (*pml3)[pml_index<3>(page)].clear(); - } - - if (pml3->empty()) - { - auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); - active_frame_allocator().release(pml3_frame); - (*pml4)[pml_index<4>(page)].clear(); - } + return std::bit_cast(recursive_base); } } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index 47148f0..fe4fd50 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -7,13 +7,63 @@ namespace teachos::memory::x86_64 { + namespace + { + //! Perform the actual mapping of the page, via the recursive page map. + //! + //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries + //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When + //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit + //! added, thus + //! still enforcing non-writability and non-execution of the affected page. + template + requires(Level > 1uz && Level < 5uz) + auto do_map(recursive_page_table * pml, page page, frame_allocator & allocator, page_mapper::flags flags) + { + auto index = pml_index(page); + auto entry_flags = to_table_flags(flags); + + entry_flags = entry_flags & ~page_table::entry::flags::no_execute; + entry_flags = entry_flags | page_table::entry::flags::writable; + if (!(*pml)[index].present()) + { + auto new_table_frame = allocator.allocate(); + (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | entry_flags); + auto new_table = std::optional{std::construct_at(*pml->next(index))}; + return new_table; + } + (*pml)[index] |= entry_flags; + return pml->next(index); + } + + //! Perform the actual PML1 update. + auto do_map(page_table * pml, page page, frame frame, page_mapper::flags flags) -> std::optional + { + auto index = pml_index<1>(page); + if ((*pml)[index].present()) + { + system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); + } + (*pml)[index].frame(frame, page_table::entry::flags::present | to_table_flags(flags)); + return std::optional{static_cast(page.start_address())}; + } + + } // namespace + recursive_page_mapper::recursive_page_mapper(frame_allocator & allocator) : m_allocator{&allocator} {} auto recursive_page_mapper::map(page page, frame frame, flags flags) -> std::byte * { - return paging_root::get().map(page, frame, to_table_flags(flags)).value_or(nullptr); + auto pml4 = static_cast *>((paging_root::get())); + + return std::optional{pml4} + .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }) + .value_or(nullptr); } auto recursive_page_mapper::unmap(page page) -> void @@ -26,12 +76,39 @@ namespace teachos::memory::x86_64 auto recursive_page_mapper::try_unmap(page page) noexcept -> bool { - auto & root = paging_root::get(); - if (!root.translate(page)) + if (!paging_root::get()->translate(page)) { return false; } - root.unmap(page); + + auto pml4 = paging_root::get(); + auto pml3 = pml4->next(pml_index<4>(page)).value(); + auto pml2 = pml3->next(pml_index<3>(page)).value(); + auto pml1 = pml2->next(pml_index<2>(page)).value(); + + (*pml1)[pml_index<1>(page)].clear(); + + if (pml1->empty()) + { + auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); + m_allocator->release(pml1_frame); + (*pml2)[pml_index<2>(page)].clear(); + } + + if (pml2->empty()) + { + auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); + m_allocator->release(pml2_frame); + (*pml3)[pml_index<3>(page)].clear(); + } + + if (pml3->empty()) + { + auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); + m_allocator->release(pml3_frame); + (*pml4)[pml_index<4>(page)].clear(); + } + return true; } diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index e243dc9..fa68387 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -14,14 +14,16 @@ namespace teachos::memory::x86_64 scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} + , m_mapper{std::exchange(other.m_mapper, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} {} - scoped_mapping::scoped_mapping(page page) + scoped_mapping::scoped_mapping(page page, page_mapper & mapper) : m_page{page} + , m_mapper{&mapper} , m_mapped{false} { - if (paging_root::get().translate(page)) + if (paging_root::get()->translate(page)) { system::panic("[MEM] Tried to map a page that is already mapped!"); } @@ -44,14 +46,14 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto result = active_page_mapper().map(m_page, frame, to_mapper_flags(flags)); + auto result = m_mapper->map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; return result; } auto scoped_mapping::unmap() -> void { - active_page_mapper().unmap(m_page); + m_mapper->unmap(m_page); m_mapped = false; } @@ -59,6 +61,7 @@ namespace teachos::memory::x86_64 { using std::swap; swap(lhs.m_page, rhs.m_page); + swap(lhs.m_mapper, rhs.m_mapper); swap(lhs.m_mapped, rhs.m_mapped); } -- cgit v1.2.3 From 5f695cd3519d8a09a53485c08971f49ed92969ff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 14:11:25 +0100 Subject: x86_64/memory: silence linter warning --- arch/x86_64/src/memory/recursive_page_mapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index fe4fd50..798233a 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -17,7 +17,7 @@ namespace teachos::memory::x86_64 //! added, thus //! still enforcing non-writability and non-execution of the affected page. template - requires(Level > 1uz && Level < 5uz) + requires(Level > 1uz && Level <= PLATFORM_PAGING_LEVELS) auto do_map(recursive_page_table * pml, page page, frame_allocator & allocator, page_mapper::flags flags) { auto index = pml_index(page); -- cgit v1.2.3 From 40804526a58ddf2cc0df0750550c8dcfa7b7c57c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 11:34:30 +0100 Subject: x86_64/boot: use high-mem address of MBI --- arch/x86_64/src/memory/recursive_page_mapper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index 798233a..ef234ad 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -14,8 +14,7 @@ namespace teachos::memory::x86_64 //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit - //! added, thus - //! still enforcing non-writability and non-execution of the affected page. + //! added, thus still enforcing non-writability and non-execution of the affected page. template requires(Level > 1uz && Level <= PLATFORM_PAGING_LEVELS) auto do_map(recursive_page_table * pml, page page, frame_allocator & allocator, page_mapper::flags flags) -- cgit v1.2.3 From 1945dd16716392e70e74efacd19e779f121bd1da Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 16:46:51 +0100 Subject: chore: fix missing includes --- arch/x86_64/src/memory/kernel_mapper.cpp | 6 ++++++ arch/x86_64/src/memory/mmu.cpp | 2 ++ arch/x86_64/src/memory/page_table.cpp | 6 ++++++ arch/x86_64/src/memory/paging_root.cpp | 1 + arch/x86_64/src/memory/recursive_page_mapper.cpp | 5 +++++ arch/x86_64/src/memory/region_allocator.cpp | 1 + arch/x86_64/src/memory/scoped_mapping.cpp | 1 + 7 files changed, 22 insertions(+) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index a28cf00..4781d64 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -8,9 +8,15 @@ #include #include +#include #include +#include +#include +#include #include +#include +#include namespace teachos::memory::x86_64 { diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index 8ec8a2e..e15d94e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -1,5 +1,7 @@ #include "x86_64/memory/mmu.hpp" +#include "kapi/memory.hpp" + #include "x86_64/cpu/registers.hpp" namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 0e404e5..2de099d 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -1,6 +1,12 @@ #include "x86_64/memory/page_table.hpp" +#include "kapi/memory.hpp" + #include +#include +#include +#include +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 4f88657..d849a82 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,5 +1,6 @@ #include "x86_64/memory/paging_root.hpp" +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index ef234ad..c5aabcb 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -1,10 +1,15 @@ #include "x86_64/memory/recursive_page_mapper.hpp" +#include "kapi/memory.hpp" #include "kapi/system.hpp" #include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include +#include + namespace teachos::memory::x86_64 { namespace diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index e477ec0..dbe14cd 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index fa68387..a86aaed 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -7,6 +7,7 @@ #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/paging_root.hpp" +#include #include namespace teachos::memory::x86_64 -- cgit v1.2.3 From a9eeec745e29d89afd48ee43d09432eb6fc35be7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 17:04:15 +0100 Subject: kapi/memory: initialize memory subsystem --- arch/x86_64/src/memory/region_allocator.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index dbe14cd..0f65b3a 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace teachos::memory::x86_64 { -- cgit v1.2.3