aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64
diff options
context:
space:
mode:
authorMatteo Gmür <matteo.gmuer1@ost.ch>2024-10-19 14:40:25 +0000
committerMatteo Gmür <matteo.gmuer1@ost.ch>2024-10-19 14:40:25 +0000
commit675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31 (patch)
tree0ec4682c3be47e2ee8250b7608d0464d18ca138d /arch/x86_64
parenta2fdcea0d7615f8933401e45e0c64a2f618bb730 (diff)
downloadteachos-675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31.tar.xz
teachos-675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31.zip
Seperate allocation and paging code into multiple files as well
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/CMakeLists.txt6
-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.hpp52
-rw-r--r--arch/x86_64/include/arch/memory/paging.hpp220
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_entry.hpp90
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_table.hpp100
-rw-r--r--arch/x86_64/include/arch/memory/paging/virtual_page.hpp27
-rw-r--r--arch/x86_64/src/kernel/main.cpp4
-rw-r--r--arch/x86_64/src/memory/allocator/area_frame_allocator.cpp (renamed from arch/x86_64/src/memory/frame_allocator.cpp)21
-rw-r--r--arch/x86_64/src/memory/allocator/physical_frame.cpp22
-rw-r--r--arch/x86_64/src/memory/paging/page_entry.cpp (renamed from arch/x86_64/src/memory/paging.cpp)12
-rw-r--r--arch/x86_64/src/memory/paging/page_table.cpp65
12 files changed, 379 insertions, 305 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt
index 7ddf303..016215b 100644
--- a/arch/x86_64/CMakeLists.txt
+++ b/arch/x86_64/CMakeLists.txt
@@ -44,8 +44,10 @@ target_sources("_memory" PRIVATE
"src/memory/multiboot/elf_symbols_section.cpp"
"src/memory/multiboot/memory_map.cpp"
"src/memory/multiboot/reader.cpp"
- "src/memory/frame_allocator.cpp"
- "src/memory/paging.cpp"
+ "src/memory/allocator/area_frame_allocator.cpp"
+ "src/memory/allocator/physical_frame.cpp"
+ "src/memory/paging/page_entry.cpp"
+ "src/memory/paging/page_table.cpp"
)
#[============================================================================[
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
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp
index c0d4aed..09fc2a2 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/src/kernel/main.cpp
@@ -1,7 +1,7 @@
#include "arch/kernel/main.hpp"
#include "arch/exception_handling/assert.hpp"
-#include "arch/memory/frame_allocator.hpp"
+#include "arch/memory/allocator/area_frame_allocator.hpp"
#include "arch/memory/multiboot/reader.hpp"
#include "arch/video/vga/text.hpp"
@@ -18,7 +18,7 @@ namespace teachos::arch::kernel
text::write("TeachOS is starting up...", text::common_attributes::green_on_black);
auto memory_information = memory::multiboot::read_multiboot2();
- auto allocator = memory::area_frame_allocator(memory_information);
+ memory::allocator::area_frame_allocator allocator(memory_information);
auto last_allocated = allocator.allocate_frame();
auto allocated = last_allocated;
diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
index 7776082..9c344d8 100644
--- a/arch/x86_64/src/memory/frame_allocator.cpp
+++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
@@ -1,22 +1,9 @@
-#include "arch/memory/frame_allocator.hpp"
+#include "arch/memory/allocator/area_frame_allocator.hpp"
#include "arch/exception_handling/assert.hpp"
-namespace teachos::arch::memory
+namespace teachos::arch::memory::allocator
{
- physical_frame::physical_frame(std::size_t frame_number)
- : frame_number(frame_number)
- {
- // Nothing to do
- }
-
- auto physical_frame::containing_address(std::size_t address) -> physical_frame
- {
- return physical_frame{address / PAGE_FRAME_SIZE};
- }
-
- auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; }
-
area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info)
: next_free_frame(0)
, current_area(std::nullopt)
@@ -81,7 +68,7 @@ namespace teachos::arch::memory
else if (physical_frame >= multiboot_start && physical_frame <= kernel_end)
{
// `physical_frame` is used by the kernel or multiboot information structure
- next_free_frame = arch::memory::physical_frame{kernel_end.frame_number + 1};
+ next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1};
}
else
{
@@ -107,4 +94,4 @@ namespace teachos::arch::memory
auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; }
auto area_frame_allocator::end() -> multiboot::memory_area_iterator { return area_end; }
-} // namespace teachos::arch::memory
+} // namespace teachos::arch::memory::allocator
diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp
new file mode 100644
index 0000000..03ec193
--- /dev/null
+++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp
@@ -0,0 +1,22 @@
+#include "arch/memory/allocator/physical_frame.hpp"
+
+namespace teachos::arch::memory::allocator
+{
+ namespace
+ {
+ constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB.
+ }
+
+ physical_frame::physical_frame(std::size_t frame_number)
+ : frame_number(frame_number)
+ {
+ // Nothing to do
+ }
+
+ auto physical_frame::containing_address(std::size_t address) -> physical_frame
+ {
+ return physical_frame{address / PAGE_FRAME_SIZE};
+ }
+
+ auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; }
+} // namespace teachos::arch::memory::allocator
diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp
index 9774132..43c0b71 100644
--- a/arch/x86_64/src/memory/paging.cpp
+++ b/arch/x86_64/src/memory/paging/page_entry.cpp
@@ -1,19 +1,19 @@
-#include "arch/memory/paging.hpp"
+#include "arch/memory/paging/page_entry.hpp"
#include "arch/exception_handling/assert.hpp"
-namespace teachos::arch::memory
+namespace teachos::arch::memory::paging
{
auto entry::is_unused() const -> bool { return flags == 0U; }
auto entry::set_unused() -> void { flags = 0U; }
- auto entry::calculate_pointed_to_frame() const -> std::optional<physical_frame>
+ auto entry::calculate_pointed_to_frame() const -> std::optional<allocator::physical_frame>
{
if (contains_flags(PRESENT))
{
auto physical_address = calculate_physical_address();
- return physical_frame::containing_address(physical_address);
+ return allocator::physical_frame::containing_address(physical_address);
}
return std::nullopt;
}
@@ -33,10 +33,10 @@ namespace teachos::arch::memory
auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; }
- auto entry::set_address(physical_frame frame) -> void
+ auto entry::set_address(allocator::physical_frame frame) -> void
{
arch::exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0,
"Start address is not aligned with Page");
flags = std::bitset<64U>(frame.start_address()) | flags;
}
-} // namespace teachos::arch::memory
+} // namespace teachos::arch::memory::paging
diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp
new file mode 100644
index 0000000..a1cbc72
--- /dev/null
+++ b/arch/x86_64/src/memory/paging/page_table.cpp
@@ -0,0 +1,65 @@
+#include "arch/memory/paging/page_table.hpp"
+
+#include "arch/exception_handling/assert.hpp"
+
+namespace teachos::arch::memory::paging
+{
+ page_table::page_table()
+ : current_level(LEVEL4)
+ , current_table(reinterpret_cast<table_content *>(0xfffffffffffff000))
+ {
+ // Nothing to do
+ }
+
+ auto page_table::zero_entries() -> void
+ {
+ constexpr size_t entry_amount = sizeof(current_table->entries) / sizeof(current_table->entries[0]);
+ for (size_t i = 0; i < entry_amount; ++i)
+ {
+ auto entry = this->operator[](i);
+ entry.set_unused();
+ }
+ }
+
+ auto page_table::next_table(std::size_t table_index) -> void
+ {
+ arch::exception_handling::assert(current_level != LEVEL1,
+ "[Page Table] Attempted to call next_table on level 1 page table");
+ auto address = next_table_address(table_index);
+
+ if (address.has_value())
+ {
+ current_table = reinterpret_cast<table_content *>(*address);
+ current_level = static_cast<level>(current_level - 1U);
+ }
+ }
+
+ auto page_table::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 current_table->entries[index];
+ }
+
+ auto page_table::operator[](std::size_t index) const -> entry const &
+ {
+ // 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 current_table->entries[index];
+ }
+
+ auto page_table::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;
+ }
+} // namespace teachos::arch::memory::paging