From d539ed1f4f26a42959bcae6ea3050b7f99f5f872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 16 Oct 2024 14:30:04 +0000 Subject: Attempt to implement page table checks using templates --- arch/x86_64/include/arch/memory/paging.hpp | 83 ++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 16 deletions(-) (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index d55835e..4bbb0e0 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -105,28 +105,63 @@ namespace teachos::arch::memory ///< used for additional flags by the operating system. }; + enum level : uint8_t; + /** - * @brief A Page table containing 512 entries + * @brief A Page table containing 512 entries. */ + template struct page_table { + enum level : uint8_t + { + LEVEL1, + LEVEL2, + LEVEL3, + LEVEL4 + }; + /** * @brief Constructor. */ - page_table(); + page_table() + : entries() + , p4(reinterpret_cast(0xfffffffffffff000)) + { + // Nothing to do + } /** * @brief Set every entry of the page to unused */ - auto zero_entries() -> void; + auto zero_entries() -> void + { + constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); + for (size_t i = 0; i < entry_amount; ++i) + { + auto entry = entry.set_unused(); + } + } /** - * @brief Convert the address of a page_table into a page_table + * @brief Gets the complete 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. * - * @param index Index of the entry we want to access - * @return An optional of the next page table or null + * @param table_index Index of this page table in the page table one level higher. + * @return Entire page table of the next level. */ - auto next_table(std::size_t index) const -> std::optional; + auto next_table(std::size_t table_index) const -> std::optional + requires(page_table_level > 0) + { + auto address = next_table_address(table_index); + + if (address.has_value()) + { + return reinterpret_cast(*address); + } + + return std::nullopt; + } /** * @brief Index operator overload to access specific mutable entry directy @@ -134,7 +169,13 @@ namespace teachos::arch::memory * @param index Index of the entry we want to access and change * @return Entry at the given table index */ - auto operator[](std::size_t index) -> entry &; + auto operator[](std::size_t index) -> entry & + { + // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which + // could be incredibly hard to debug later. + arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + return entries[index]; + } /** * @brief Index operator overload to access specific immutable entry directy @@ -142,22 +183,32 @@ namespace teachos::arch::memory * @param index Index of the entry we want to access and only read * @return Entry at the given table index */ - auto operator[](std::size_t index) const -> entry const &; + auto operator[](std::size_t index) const -> entry const & { return this->operator[](index); } private: /** - * @brief Find and return the next table address + * @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. * - * The next table address is only valid if the corresponding entry is present - * and does not create a huge page - * - * @param index + * @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 index) const -> std::optional; + auto next_table_address(std::size_t table_index) const -> std::optional + { + auto entry = this->operator[](table_index); + + if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) + { + std::size_t const table_address = reinterpret_cast(this); + return (table_address << 9) | (table_index << 12); + } + // TODO: Implement behaviour for huge pages currently not done + return std::nullopt; + } entry entries[PAGE_TABLE_ENTRY_COUNT]; - page_table const * p4; + page_table const * p4; }; } // namespace teachos::arch::memory -- cgit v1.2.3