diff options
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 21 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging/page_mapper.cpp | 44 |
2 files changed, 55 insertions, 10 deletions
diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index b151a7f..ad9db52 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -8,18 +8,27 @@ namespace teachos::arch::memory::paging { /** - * @brief Translate page into physical_frame + * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if it + * failed attempt to parse using huge pages. * - * @param page Page to translate into physical_frame - * @return Physical frame corresponding to the provided page_table + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. */ auto translate_page(virtual_page page) -> std::optional<allocator::physical_frame>; /** - * @brief Translate virtual into phyical address + * @brief Translates huge page into actual physical frame. * - * @param virtual_address Address to translate into physical - * @return Physical address + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. + */ + auto translate_huge_page(virtual_page page) -> std::optional<allocator::physical_frame>; + + /** + * @brief Translate virtual into phyical address. + * + * @param virtual_address Address to translate into physical. + * @return Physical address. */ auto translate_address(std::size_t virtual_address) -> std::optional<std::size_t>; diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 5372561..e68bc68 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -8,7 +8,8 @@ namespace teachos::arch::memory::paging { page_table page_table{}; bool is_valid = false; - auto huge_page = []() -> std::optional<allocator::physical_frame> { return std::nullopt; }; + + auto huge_page = [&]() -> std::optional<allocator::physical_frame> {}; for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { @@ -22,11 +23,46 @@ namespace teachos::arch::memory::paging if (is_valid) { auto level1_index = page.get_level_index(page_table::LEVEL1); - auto frame = page_table[level1_index].calculate_pointed_to_frame(); - return frame; + auto level1_frame = page_table[level1_index].calculate_pointed_to_frame(); + return level1_frame; } - return huge_page(); + return translate_huge_page(page); + } + + auto translate_huge_page(virtual_page page) -> std::optional<allocator::physical_frame> + { + page_table page_table{}; + bool is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); + + if (is_valid) + { + auto level3_entry = page_table[page.get_level_index(page_table::LEVEL3)]; + auto level3_optional_frame = level3_entry.calculate_pointed_to_frame(); + if (level3_optional_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE)) + { + auto level3_frame = level3_optional_frame.value(); + exception_handling::assert(level3_frame.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.frame_number + + page.get_level_index(page_table::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + + page.get_level_index(page_table::LEVEL1)}; + } + } + is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); + if (is_valid) + { + auto level2_entry = page_table[page.get_level_index(page_table::LEVEL2)]; + auto level2_optional_frame = level2_entry.calculate_pointed_to_frame(); + if (level2_optional_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE)) + { + auto level2_frame = level2_optional_frame.value(); + exception_handling::assert(level2_frame.frame_number % PAGE_TABLE_ENTRY_COUNT == 0U, + "[Page Mapper] Physical address must be 2 MiB aligned"); + return allocator::physical_frame{level2_frame.frame_number + page.get_level_index(page_table::LEVEL1)}; + } + } + return std::nullopt; } auto translate_address(std::size_t virtual_address) -> std::optional<std::size_t> |
