From 31e1ac359eb4b84bdd81f768b2de327193976a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 13:22:02 +0000 Subject: Remove static page mapper and replace with unique active and inactive page table classes. --- arch/x86_64/CMakeLists.txt | 3 +- .../arch/memory/allocator/tiny_frame_allocator.hpp | 10 +- .../arch/memory/paging/active_page_table.hpp | 218 ++++++++++++++++++++ .../arch/memory/paging/inactive_page_table.hpp | 15 ++ .../include/arch/memory/paging/page_mapper.hpp | 219 --------------------- .../include/arch/memory/paging/temporary_page.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 2 +- .../x86_64/src/memory/paging/active_page_table.cpp | 96 +++++++++ .../src/memory/paging/inactive_page_table.cpp | 5 + arch/x86_64/src/memory/paging/page_mapper.cpp | 96 --------- arch/x86_64/src/memory/paging/temporary_page.cpp | 2 +- 11 files changed, 340 insertions(+), 328 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging/active_page_table.hpp create mode 100644 arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/page_mapper.hpp create mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp create mode 100644 arch/x86_64/src/memory/paging/inactive_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8d64985..a97abaa 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -50,7 +50,8 @@ target_sources("_memory" PRIVATE "src/memory/paging/page_table.cpp" "src/memory/paging/temporary_page.cpp" "src/memory/paging/virtual_page.cpp" - "src/memory/paging/page_mapper.cpp" + "src/memory/paging/active_page_table.cpp" + "src/memory/paging/inactive_page_table.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index 4bcec1c..e55b376 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -23,16 +23,8 @@ namespace teachos::arch::memory::allocator * entries *when a new page table is required. */ tiny_frame_allocator(area_frame_allocator & allocator) - : frames{} + : frames{allocator.allocate_frame(), allocator.allocate_frame(), allocator.allocate_frame()} { - for (auto & frame : frames) - { - auto temp_frame = allocator.allocate_frame(); - if (temp_frame.has_value()) - { - frame.emplace(temp_frame.value()); - } - } // Nothing to do } diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp new file mode 100644 index 0000000..8011ee0 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -0,0 +1,218 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP + +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/paging/virtual_page.hpp" + +#include +#include + +namespace teachos::arch::memory::paging +{ + /** + * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot + * be copied or constructed again. + */ + struct active_page_table + { + /** + * @brief Creates a single instance of an active level 4 page table table and returns the created instance or + * alternatively returns the previously created instance instead. The instance is owned by this method and is + * static, meaning it lives on for the complete lifetime of the program. + * + * @return Active single unique instance of the level 4 page table. + */ + static auto create_or_get() -> active_page_table &; + + /** + * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. + * + * @param address Virtual address we want to translate into physical one. + * @return Physical address corresponding to the provided virtual address. + */ + auto translate_address(virtual_address address) -> std::optional; + + /** + * @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 virtual page. + */ + auto translate_page(virtual_page page) -> std::optional; + + /** + * @brief Translates huge page into actual physical frame. + * + * @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; + + /** + * @brief Maps a virtual page to a physical frame in the page table with the specified flags. + * + * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 + * page table already exists it halts execution instead. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param page Virtual page that is being mapped. + * @param frame Physical frame that the virtual page will be mapped to. + * @param flags A bitset of flags that configure the page table entry for this mapping. + */ + template + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); + } + + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper] Unable to map huge pages"); + arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); + } + + /** + * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. + * + * @see map_page_to_frame + */ + template + auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + { + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } + + /** + * @brief Gets the corresponding page the given frame has to be contained in and uses that to call + * map_page_to_frame. + * + * @see map_page_to_frame + */ + template + auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto const page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } + + /** + * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. + * + * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and + * ensures to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param page Virtual page that is being unmapped. + */ + template + auto unmap_page(T & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = active_handle; + std::array handles{current_handle, current_handle, current_handle, current_handle}; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not + // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + // The level is used as the index, because it ensures the first level is the lowest one and then the remaining + // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check + // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 + // page is empty and clear the Level 3 page entry and so on. + handles.at(level - 1U) = current_handle; + } + + // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the + // last one. We check if it was the last one using is empty on the page table handle, when we have removed the + // page to be unmapped. + for (auto & handle : handles) + { + unmap_page_table_entry(allocator, page, handle); + if (!handle.is_empty()) + { + break; + } + } + invalidate_page_cache(page.start_address()); + } + + private: + /** + * @brief Private constructor should only be used by create or get method, which ensures to create only ever one + * instance. + * + * @param active_handle Handle to the underlying currently active level 4 page table. + */ + active_page_table(page_table_handle active_handle); + + /** + * @brief Deleted copy constructor. + */ + active_page_table(active_page_table const &) = delete; + + /** + * @brief Deleted copy assignment operator. + */ + active_page_table & operator=(active_page_table const &) = delete; + + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + static auto invalidate_page_cache(virtual_address address) -> void + { + asm volatile("invlpg (%0)" ::"r"(address) : "memory"); + } + + /** + * @brief Unmaps specific page at the current internal handle level. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries *when a new page table is required. + * @param page Virtual page that is being unmapped. + * @param handle Page Table handle we want to access the entry that should be cleared on. + */ + template + static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + { + auto level_index = page.get_level_index(handle.get_level()); + auto & entry = handle[level_index]; + auto const frame = entry.calculate_pointed_to_frame(); + exception_handling::assert(frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + entry.set_unused(); + allocator.deallocate_frame(frame.value()); + } + + page_table_handle active_handle; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp new file mode 100644 index 0000000..4285fc2 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -0,0 +1,15 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +namespace teachos::arch::memory::paging +{ + struct inactive_page_table + { + private: + allocator::physical_frame page_table_level_4_frame; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp deleted file mode 100644 index 20d9afc..0000000 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP - -#include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/concept.hpp" -#include "arch/memory/paging/virtual_page.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::paging -{ - /** - * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot - * be copied or constructed again. - */ - struct active_page_table - { - /** - * @brief Creates a single instance of an active level 4 page table table and returns the created instance or - * alternatively returns the previously created instance instead. The instance is owned by this method and is - * static, meaning it lives on for the complete lifetime of the program. - * - * @return Active single unique instance of the level 4 page table. - */ - static auto create_or_get() -> active_page_table &; - - /** - * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. - * - * @param address Virtual address we want to translate into physical one. - * @return Physical address corresponding to the provided virtual address. - */ - auto translate_address(virtual_address address) -> std::optional; - - /** - * @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 virtual page. - */ - auto translate_page(virtual_page page) -> std::optional; - - /** - * @brief Translates huge page into actual physical frame. - * - * @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; - - /** - * @brief Maps a virtual page to a physical frame in the page table with the specified flags. - * - * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 - * page table already exists it halts execution instead. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries when a new page table is required. - * @param page Virtual page that is being mapped. - * @param frame Physical frame that the virtual page will be mapped to. - * @param flags A bitset of flags that configure the page table entry for this mapping. - */ - template - auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); - } - - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper] Unable to map huge pages"); - arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); - level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); - } - - /** - * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. - * - * @see map_page_to_frame - */ - template - auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void - { - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); - map_page_to_frame(allocator, page, frame.value(), flags); - } - - /** - * @brief Gets the corresponding page the given frame has to be contained in and uses that to call - * map_page_to_frame. - * - * @see map_page_to_frame - */ - template - auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - auto const page = virtual_page::containing_address(frame.start_address()); - map_page_to_frame(allocator, page, frame, flags); - } - - /** - * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. - * - * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and - * ensures to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries when a new page table is required. - * @param page Virtual page that is being unmapped. - */ - template - auto unmap_page(T & allocator, virtual_page page) -> void - { - exception_handling::assert(translate_page(page).has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - - auto current_handle = active_handle; - std::array handles{current_handle, current_handle, current_handle, current_handle}; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const level_index = page.get_level_index(level); - auto const next_handle = current_handle.next_table(level_index); - // The next table method failed even tough the page has to be mapped already, because translate_page did not - // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. - exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); - current_handle = next_handle.value(); - // The level is used as the index, because it ensures the first level is the lowest one and then the remaining - // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check - // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 - // page is empty and clear the Level 3 page entry and so on. - handles.at(level - 1U) = current_handle; - } - - // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the - // last one. We check if it was the last one using is empty on the page table handle, when we have removed the - // page to be unmapped. - for (auto & handle : handles) - { - unmap_page_table_entry(allocator, page, handle); - if (!handle.is_empty()) - { - break; - } - } - invalidate_page_cache(page.start_address()); - } - - private: - /** - * @brief Private constructor should only be used by create or get method, which ensures to create only ever one - * instance. - * - * @param active_handle Handle to the underlying currently active level 4 page table. - */ - active_page_table(page_table_handle active_handle); - - /** - * @brief Deleted copy constructor. - */ - active_page_table(active_page_table const &) = delete; - - /** - * @brief Deleted copy assignment operator. - */ - active_page_table & operator=(active_page_table const &) = delete; - - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - static auto invalidate_page_cache(virtual_address address) -> void - { - asm volatile("invlpg (%0)" ::"r"(address) : "memory"); - } - - /** - * @brief Unmaps specific page at the current internal handle level. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries *when a new page table is required. - * @param page Virtual page that is being unmapped. - * @param handle Page Table handle we want to access the entry that should be cleared on. - */ - template - static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void - { - auto level_index = page.get_level_index(handle.get_level()); - auto & entry = handle[level_index]; - auto const frame = entry.calculate_pointed_to_frame(); - exception_handling::assert(frame.has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - entry.set_unused(); - allocator.deallocate_frame(frame.value()); - } - - page_table_handle active_handle; - }; -} // namespace teachos::arch::memory::paging - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index c42745a..b658f7a 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -3,7 +3,7 @@ #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/allocator/tiny_frame_allocator.hpp" -#include "arch/memory/paging/page_mapper.hpp" +#include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/page_table.hpp" #include "arch/memory/paging/virtual_page.hpp" diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 22335d1..f1d6496 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -3,7 +3,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" -#include "arch/memory/paging/page_mapper.hpp" +#include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" #include "arch/video/vga/text.hpp" diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp new file mode 100644 index 0000000..38696f8 --- /dev/null +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -0,0 +1,96 @@ +#include "arch/memory/paging/active_page_table.hpp" + +namespace teachos::arch::memory::paging +{ + namespace + { + std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + } // namespace + + 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::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 new file mode 100644 index 0000000..1f36aa3 --- /dev/null +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -0,0 +1,5 @@ +#include "arch/memory/paging/inactive_page_table.hpp" + +namespace teachos::arch::memory::paging +{ +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp deleted file mode 100644 index 30055e8..0000000 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "arch/memory/paging/page_mapper.hpp" - -namespace teachos::arch::memory::paging -{ - namespace - { - std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - } // namespace - - 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::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/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 4a8f4da..180b4a8 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -27,7 +27,7 @@ namespace teachos::arch::memory::paging auto temporary_page::zero_entries(active_page_table & active_table) -> void { auto frame = allocator.allocate_frame(); - exception_handling::assert(!frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); + exception_handling::assert(frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); page_table_handle handle = map_table_frame(frame.value(), active_table); handle.zero_entries(); -- cgit v1.2.3