diff options
| author | Matteo Gmür <matteo.gmuer1@ost.ch> | 2024-10-19 14:40:25 +0000 |
|---|---|---|
| committer | Matteo Gmür <matteo.gmuer1@ost.ch> | 2024-10-19 14:40:25 +0000 |
| commit | 675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31 (patch) | |
| tree | 0ec4682c3be47e2ee8250b7608d0464d18ca138d /arch/x86_64/include | |
| parent | a2fdcea0d7615f8933401e45e0c64a2f618bb730 (diff) | |
| download | teachos-675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31.tar.xz teachos-675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31.zip | |
Seperate allocation and paging code into multiple files as well
Diffstat (limited to 'arch/x86_64/include')
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp (renamed from arch/x86_64/include/arch/memory/frame_allocator.hpp) | 65 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/physical_frame.hpp | 52 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging.hpp | 220 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/page_entry.hpp | 90 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/page_table.hpp | 100 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 27 |
6 files changed, 276 insertions, 278 deletions
diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index f1096d1..c9d4e7f 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -1,64 +1,13 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP -#include "multiboot/reader.hpp" +#include "arch/memory/multiboot/reader.hpp" -#include <cstddef> +#include "physical_frame.hpp" #include <optional> -#include <type_traits> -namespace teachos::arch::memory +namespace teachos::arch::memory::allocator { - constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. - - /** - * @brief Specific physical_frame containing helper functions to determine if a specific address is in that - * physical_frame or not. - */ - struct physical_frame - { - /** - * @brief Constructor. - * - * @param frame_number Index number that should be assigned to this physical_frame. - */ - explicit physical_frame(std::size_t frame_number); - - /** - * @brief Returns the physical_frame the given address is contained in. - * - * @param address Address we want to get the corresponding physical_frame for. - * @return Frame the given address is contained in. - */ - static auto containing_address(std::size_t address) -> physical_frame; - - /** - * @brief Evaluates the start address of the physical frame. - * - * @return start address of the physical frame. - */ - auto start_address() const -> uint64_t; - - /** - * @brief Defaulted equals operator. - */ - constexpr auto operator==(const physical_frame & other) const -> bool = default; - - /** - * @brief Defaulted three-way comparsion operator. - */ - constexpr auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; - - std::size_t - frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. - }; - - template<typename T> - concept FrameAllocator = requires(T t) { - { t.allocate_frame() } -> std::same_as<std::optional<physical_frame>>; - { t.deallocate_frame() } -> std::same_as<void>; - }; - /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ @@ -121,6 +70,6 @@ namespace teachos::arch::memory physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; -} // namespace teachos::arch::memory +} // namespace teachos::arch::memory::allocator -#endif // TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp new file mode 100644 index 0000000..5e99d10 --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -0,0 +1,52 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP + +#include <compare> +#include <cstdint> + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Specific physical frame containing helper functions to determine if a specific address is in that + * physical frame or not. + */ + struct physical_frame + { + /** + * @brief Constructor. + * + * @param frame_number Index number that should be assigned to this physical_frame. + */ + explicit physical_frame(std::size_t frame_number); + + /** + * @brief Returns the physical_frame the given address is contained in. + * + * @param address Address we want to get the corresponding physical_frame for. + * @return Frame the given address is contained in. + */ + static auto containing_address(std::size_t address) -> physical_frame; + + /** + * @brief Evaluates the start address of the physical frame. + * + * @return start address of the physical frame. + */ + auto start_address() const -> uint64_t; + + /** + * @brief Defaulted equals operator. + */ + constexpr auto operator==(const physical_frame & other) const -> bool = default; + + /** + * @brief Defaulted three-way comparsion operator. + */ + constexpr auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; + + std::size_t + frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp deleted file mode 100644 index 04c2065..0000000 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ /dev/null @@ -1,220 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP - -#include "arch/exception_handling/assert.hpp" - -#include "frame_allocator.hpp" -#include <bitset> - -namespace teachos::arch::memory -{ - constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. - - /** - * @brief Virtual page entry contained in P1 page tables - */ - struct virtual_page - { - std::size_t number; ///< Index number of the current virtual page, used to distinguish it from other pages. - - /** - * @brief Defaulted equals operator. - */ - constexpr auto operator==(const virtual_page & other) const -> bool = default; - - /** - * @brief Defaulted three-way comparsion operator. - */ - constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; - }; - - /** - * @brief Marks a specific entry in an actual page table. - */ - struct entry - { - /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. - */ - enum bitset : uint64_t - { - PRESENT = 1UL << 0UL, ///< Page is in memory and therefore present. - ///< is assumed to be READONLY and only that flag is shown in the objdump. - WRITABLE = 1UL << 1UL, ///< It is possible to write to the page. - USER_ACCESIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code. - WRITE_THROUGH_CACHING = 1UL << 3UL, ///< Write to the page go directly to memory instead of the cache. - DISABLED_CACHING = 1UL << 4UL, ///< Page uses caching. - ACCESSED = 1UL << 5UL, ///< Page is currently in use. - DIRTY = 1UL << 6UL, ///< Page has been writen too. - HUGE_PAGE = 1UL << 7UL, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, - ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. - GLOBAL = 1UL << 8UL, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register - ///< has to be set) - EXECUTING_CODE_FORBIDDEN = - 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) - }; - - /** - * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. - * - * @return Current page is in memory. - */ - auto is_unused() const -> bool; - - /** - * @brief Marks the page as unused, meaning the underlying std::bitset is set to 0. - */ - auto set_unused() -> void; - - /** - * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in - * memory. - * - * @return Calculated physical frame entry is pointing too. - */ - auto calculate_pointed_to_frame() const -> std::optional<physical_frame>; - - /** - * @brief Copies the address from the given physical frame into the underlying std::bitset so future calls to - * calculate_physical_address() will return the new address instead of the old one. - * - * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. - */ - auto set_address(physical_frame frame) -> void; - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset - */ - auto contains_flags(std::bitset<64U> other) const -> bool; - - private: - /** - * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page - * aligned physical address of the frame of the next page table or the pyhscial address of the frame for P1 page - * tables. - * - * @return Extracted physical address of the next page or of the frame for P1 page tables. - */ - auto calculate_physical_address() const -> std::size_t; - - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely - ///< used for additional flags by the operating system. - }; - - enum level : uint8_t; - - /** - * @brief A Page table containing 512 entries. - */ - template<level page_table_level> - struct page_table - { - /** - * @brief Level of the page table, level 1 should 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 - { - LEVEL1, - LEVEL2, - LEVEL3, - LEVEL4 - }; - - /** - * @brief Constructor. - */ - page_table() - : entries() - , p4(reinterpret_cast<page_table *>(0xfffffffffffff000)) - { - // Nothing to do - } - - /** - * @brief Set every entry of the page to unused - */ - 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 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 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 table_index) const -> std::optional<const page_table *> - requires(page_table_level > 0) - { - auto address = next_table_address(table_index); - - if (address.has_value()) - { - return reinterpret_cast<page_table const *>(*address); - } - - return std::nullopt; - } - - /** - * @brief Index operator overload to access specific mutable entry directy - * - * @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 & - { - // 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 - * - * @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 & { return this->operator[](index); } - - 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<std::size_t> - { - 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<std::size_t>(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<page_table::LEVEL4> const * p4; - }; -} // namespace teachos::arch::memory - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp new file mode 100644 index 0000000..a40e764 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -0,0 +1,90 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include <bitset> +#include <optional> + +namespace teachos::arch::memory::paging +{ + /** + * @brief Marks a specific entry in an actual page table. + */ + struct entry + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint64_t + { + PRESENT = 1UL << 0UL, ///< Page is in memory and therefore present. + ///< is assumed to be READONLY and only that flag is shown in the objdump. + WRITABLE = 1UL << 1UL, ///< It is possible to write to the page. + USER_ACCESIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code. + WRITE_THROUGH_CACHING = 1UL << 3UL, ///< Write to the page go directly to memory instead of the cache. + DISABLED_CACHING = 1UL << 4UL, ///< Page uses caching. + ACCESSED = 1UL << 5UL, ///< Page is currently in use. + DIRTY = 1UL << 6UL, ///< Page has been writen too. + HUGE_PAGE = 1UL << 7UL, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, + ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. + GLOBAL = 1UL << 8UL, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register + ///< has to be set) + EXECUTING_CODE_FORBIDDEN = + 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) + }; + + /** + * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. + * + * @return Current page is in memory. + */ + auto is_unused() const -> bool; + + /** + * @brief Marks the page as unused, meaning the underlying std::bitset is set to 0. + */ + auto set_unused() -> void; + + /** + * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in + * memory. + * + * @return Calculated physical frame entry is pointing too. + */ + auto calculate_pointed_to_frame() const -> std::optional<allocator::physical_frame>; + + /** + * @brief Copies the address from the given physical frame into the underlying std::bitset so future calls to + * calculate_physical_address() will return the new address instead of the old one. + * + * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. + */ + auto set_address(allocator::physical_frame frame) -> void; + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + */ + auto contains_flags(std::bitset<64U> other) const -> bool; + + private: + /** + * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page + * aligned physical address of the frame of the next page table or the pyhscial address of the frame for P1 page + * tables. + * + * @return Extracted physical address of the next page or of the frame for P1 page tables. + */ + auto calculate_physical_address() const -> std::size_t; + + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely + ///< used for additional flags by the operating system. + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP
\ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp new file mode 100644 index 0000000..32e49e5 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -0,0 +1,100 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP + +#include "page_entry.hpp" + +namespace teachos::arch::memory::paging +{ + namespace + { + constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. + } + + /** + * @brief Actual data that is contained in every page table, this is the structure we cast a specific address too, + * because it consists of x amount os entries, which is a simple address. + */ + struct table_content + { + 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. + }; + + /** + * @brief A Page table containing 512 entries. + */ + struct page_table + { + /** + * @brief Level of the page table, level 1 should 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 + { + LEVEL1, + LEVEL2, + LEVEL3, + LEVEL4 + }; + + /** + * @brief Constructor. Automatically starts on the fixed address of the Level 4 page table. + */ + page_table(); + + /** + * @brief Set every entry of the page to unused. + */ + auto zero_entries() -> void; + + /** + * @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. When using this on an a level 1 page table it will + * cause an assertion. + * + * @param table_index Index of this page table in the page table one level higher. + */ + auto next_table(std::size_t table_index) -> void; + + /** + * @brief Index operator overload to access specific mutable entry directy. + * + * @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 &; + + /** + * @brief Index operator overload to access specific immutable entry directy. + * + * @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 &; + + private: + /** + * @brief Constructor. Used internally to create new page tables. + * + * @param new_level New level of the page table. + * @param new_table New table data contained in the page table. + */ + page_table(level new_level, table_content * new_table); + + /** + * @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<std::size_t>; + + level current_level; ///< Current level of the page table, used to ensure next_table() is never called with a level + ///< 1 page table + table_content * current_table; ///< Current table we are accessing and indexing. + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP
\ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp new file mode 100644 index 0000000..12af510 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP + +#include <compare> + +namespace teachos::arch::memory::paging +{ + /** + * @brief Virtual page entry contained in P1 page tables + */ + struct virtual_page + { + std::size_t number; ///< Index number of the current virtual page, used to distinguish it from other pages. + + /** + * @brief Defaulted equals operator. + */ + constexpr auto operator==(const virtual_page & other) const -> bool = default; + + /** + * @brief Defaulted three-way comparsion operator. + */ + constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP
\ No newline at end of file |
