From 552477a12a1163f0f80801b4055dcb5ab3f79e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 12:53:23 +0000 Subject: Use forward declaration to hide actual page_table --- .../include/arch/memory/paging/page_mapper.hpp | 4 +- .../include/arch/memory/paging/page_table.hpp | 77 ++++++---------------- .../include/arch/memory/paging/virtual_page.hpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 21 +++--- arch/x86_64/src/memory/paging/page_table.cpp | 63 +++++++++++++++--- arch/x86_64/src/memory/paging/virtual_page.cpp | 2 +- 6 files changed, 87 insertions(+), 82 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 a874f75..0806f58 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -60,7 +60,7 @@ namespace teachos::arch::memory::paging { auto current_handle = create_or_get(); - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) { auto level_index = page.get_level_index(level); auto next_handle = current_handle.next_table(level_index); @@ -82,7 +82,7 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto level1_entry = current_handle[page.get_level_index(page_table::LEVEL1)]; + 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"); diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index a1c8abe..91ce81c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -11,12 +11,20 @@ namespace teachos::arch::memory::paging } /** - * @brief A Page table containing 512 entries. + * @brief Forward delcaration of the page_table, because it should only be accessible over the handle, the actual + * methods or constructor are not defined meaning they are not callable from outside. Instead the struct is only fully + * defined in the implementation (.cpp) file of the page table, and therefore also only accesible in that file. */ - struct page_table + struct page_table; + + /** + * @brief Handle that ensures accessing the page table is safe because it adds additional checks to the next_table + * method and ensures it can only be called if the table level is not LEVEL1. + */ + struct page_table_handle { /** - * @brief Level of the page table, level 1 should not be able to call next_table anymore, because it would result in + * @brief Level of the page table, level 1 will not be able to call next_table anymore, because it would result in * attempting to access memory that it should not. */ enum level : uint8_t @@ -27,62 +35,13 @@ namespace teachos::arch::memory::paging LEVEL4 }; - /** - * @brief Deleted constructor. Object can only be created by casting from the fixed Level 4 - * page table address `reinterpret_cast(0xfffffffffffff000)`. - */ - page_table() = delete; - - /** - * @brief Set every entry of the page to unused. - */ - auto zero_entries() -> void; - - /** - * @brief Returns the next page table level from the given page table index. Meaning we - * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called - * on a Level 1 page table, because there is no furthere page table and mangeling up and returning the physical - * address would cause hard to debug issues. - * - * @param table_index Index of this page table in the page table one level lower. - */ - auto next_table(std::size_t table_index) const -> std::optional; - - /** - * @brief Index operator overload to access specific entries directy. - * - * @param index Index of the entry we want to access and read or write too. - * @return Entry at the given table index. - */ - auto operator[](std::size_t index) const -> entry; - - private: - /** - * @brief Calculates the address of the next page table level for the given table index. 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; - - entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual - ///< virtual addresses for the level 1 page table. - }; - - auto operator--(page_table::level & level, int) -> page_table::level; - - /** - * @brief Handle that ensures accessing the page table is safe because it adds additional checks to the next_table - * method and ensures it can only be called if the table level is not LEVEL1. - */ - struct page_table_handle - { /** * @brief Constructor. + * + * @param handle Underlying page table the handle should point to. + * @param handle_level Level the underlying page table is on, used to ensure safety. */ - page_table_handle(page_table * handle, page_table::level handle_level); + page_table_handle(page_table * handle, level handle_level); /** * @brief Set every entry of the page to unused. @@ -109,9 +68,11 @@ namespace teachos::arch::memory::paging private: page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) - page_table::level handle_level; ///< Level page table is currently on, depends on how often next_level was - ///< called successfully. + level handle_level; ///< Level page table is currently on, depends on how often next_level was + ///< called successfully. }; + + auto operator--(page_table_handle::level & level, int) -> page_table_handle::level; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index f8dfbf0..ca11b3c 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -43,7 +43,7 @@ namespace teachos::arch::memory::paging * @param level Level of the page table we want to calculate the index for. * @return Index into the page table with the given level. */ - auto get_level_index(page_table::level level) const -> uint64_t; + auto get_level_index(page_table_handle::level level) const -> uint64_t; /** * @brief Defaulted equals operator. diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 28e248b..b8f6b89 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -11,14 +11,14 @@ namespace teachos::arch::memory::paging { static page_table * const active_page{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS)}; // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{active_page, page_table::LEVEL4}; + return page_table_handle{active_page, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) { auto 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 @@ -30,7 +30,7 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto level1_index = page.get_level_index(page_table::LEVEL1); + auto level1_index = page.get_level_index(page_table_handle::LEVEL1); auto level1_frame = current_handle[level1_index].calculate_pointed_to_frame(); return level1_frame; } @@ -38,14 +38,14 @@ namespace teachos::arch::memory::paging auto translate_huge_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); - auto level3_handle = current_handle.next_table(page.get_level_index(page_table::LEVEL4)); + auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4)); if (!level3_handle) { return std::nullopt; } - auto level3_entry = level3_handle.value()[page.get_level_index(page_table::LEVEL3)]; + auto level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; auto level3_frame = level3_entry.calculate_pointed_to_frame(); if (level3_frame && level3_entry.contains_flags(entry::HUGE_PAGE)) { @@ -53,20 +53,21 @@ namespace teachos::arch::memory::paging 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::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + - page.get_level_index(page_table::LEVEL1)}; + 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::LEVEL3)); + auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); if (level2_handle) { - auto level2_entry = level2_handle.value()[page.get_level_index(page_table::LEVEL2)]; + auto level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; auto level2_frame = level2_entry.calculate_pointed_to_frame(); if (level2_frame && 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::LEVEL1)}; + return allocator::physical_frame{level2_frame.value().frame_number + + page.get_level_index(page_table_handle::LEVEL1)}; } } return std::nullopt; diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 907b64f..852bbd5 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -4,6 +4,57 @@ namespace teachos::arch::memory::paging { + /** + * @brief A Page table containing 512 entries. + */ + struct page_table + { + /** + * @brief Set every entry of the page to unused. + */ + auto zero_entries() -> void; + + /** + * @brief Returns the next page table level from the given page table index. Meaning we + * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called + * on a Level 1 page table, because there is no furthere page table and mangeling up and returning the physical + * address would cause hard to debug issues. + * + * @param table_index Index of this page table in the page table one level lower. + */ + auto next_table(std::size_t table_index) const -> std::optional; + + /** + * @brief Index operator overload to access specific entries directy. + * + * @param index Index of the entry we want to access and read or write too. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) const -> entry; + + private: + /** + * @brief Calculates the address of the next page table level for the given table index. 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; + + entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual + ///< virtual addresses for the level 1 page table. + }; + + auto operator--(page_table_handle::level level, int) -> page_table_handle::level + { + exception_handling::assert(level != page_table_handle::LEVEL1, + "[Page table] Attemptd to decrement enum to value outside of range"); + auto value = static_cast::type>(level); + return static_cast(--value); + } + auto page_table::zero_entries() -> void { constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); @@ -44,15 +95,7 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto operator--(page_table::level level, int) -> page_table::level - { - exception_handling::assert(level != page_table::LEVEL1, - "[Page table] Attemptd to decrement enum to value outside of range"); - auto value = static_cast::type>(level); - return static_cast(--value); - } - - page_table_handle::page_table_handle(page_table * handle, page_table::level handle_level) + page_table_handle::page_table_handle(page_table * handle, page_table_handle::level handle_level) : handle(handle) , handle_level(handle_level) { @@ -63,7 +106,7 @@ namespace teachos::arch::memory::paging auto page_table_handle::next_table(std::size_t table_index) const -> std::optional { - exception_handling::assert(handle_level != page_table::LEVEL1, + exception_handling::assert(handle_level != page_table_handle::LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); auto next_table = handle->next_table(table_index); if (next_table) diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index 9b803d2..fd2085b 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -19,7 +19,7 @@ namespace teachos::arch::memory::paging auto virtual_page::start_address() const -> uint64_t { return page_number * allocator::PAGE_FRAME_SIZE; } - auto virtual_page::get_level_index(page_table::level level) const -> uint64_t + auto virtual_page::get_level_index(page_table_handle::level level) const -> uint64_t { return (start_address() >> (level * 9U)) & 0x1FF; } -- cgit v1.2.3