aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/include/arch/exception_handling/assert.hpp2
-rw-r--r--arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp6
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_mapper.hpp29
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_table.hpp65
-rw-r--r--arch/x86_64/include/arch/memory/paging/virtual_page.hpp2
-rw-r--r--arch/x86_64/src/exception_handling/assert.cpp2
-rw-r--r--arch/x86_64/src/kernel/main.cpp8
-rw-r--r--arch/x86_64/src/memory/paging/page_mapper.cpp37
-rw-r--r--arch/x86_64/src/memory/paging/page_table.cpp34
9 files changed, 114 insertions, 71 deletions
diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp
index bfc205c..58c1f33 100644
--- a/arch/x86_64/include/arch/exception_handling/assert.hpp
+++ b/arch/x86_64/include/arch/exception_handling/assert.hpp
@@ -1,8 +1,6 @@
#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP
#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP
-#include "arch/exception_handling/panic.hpp"
-
namespace teachos::arch::exception_handling
{
/**
diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
index f99b7c8..7b1bb16 100644
--- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
+++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
@@ -1,17 +1,17 @@
#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP
#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP
+#include "arch/memory/allocator/physical_frame.hpp"
#include "arch/memory/multiboot/reader.hpp"
-#include "physical_frame.hpp"
#include <optional>
namespace teachos::arch::memory::allocator
{
template<typename T>
- concept FrameAllocator = requires(T t) {
+ concept FrameAllocator = requires(T t, physical_frame a) {
{ t.allocate_frame() } -> std::same_as<std::optional<physical_frame>>;
- { t.deallocate_frame() } -> std::same_as<void>;
+ { t.deallocate_frame(a) } -> std::same_as<void>;
};
/**
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 ebd044a..a874f75 100644
--- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp
+++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp
@@ -10,13 +10,13 @@
namespace teachos::arch::memory::paging
{
/**
- * @brief Creates a single instance of the level 4 page table table and returns it or alternatively returns the
- * previously created instance. The instance is owned by this method and is static, meaning it lives on for the
- * complete lifetime of the program.
+ * @brief Creates a single instance of the level 4 page table table and returns handle to it or alternatively returns
+ * the previously created handle instead. The instance is owned by this method and is static, meaning it lives on for
+ * the complete lifetime of the program.
*
- * @return Single unique instance of the level 4 page table.
+ * @return Handle to the single unique instance of the level 4 page table.
*/
- auto create_or_get() -> page_table *;
+ auto create_or_get() -> page_table_handle;
/**
* @brief Translates page into physical frame, will first attempt to parse normally using default page size and if it
@@ -58,32 +58,31 @@ namespace teachos::arch::memory::paging
auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame,
std::bitset<64U> flags) -> void
{
- page_table * current_page_table = create_or_get();
+ auto current_handle = create_or_get();
for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--)
{
auto level_index = page.get_level_index(level);
- auto next_page_table = current_page_table->next_table(level_index);
+ auto next_handle = current_handle.next_table(level_index);
// If the next table method failed then it means that the page level of the frame we want allocate has not yet
// been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done
// for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a
// page table one level below.
- if (!next_page_table)
+ if (!next_handle)
{
auto allocated_frame = allocator.allocate_frame();
exception_handling::assert(!allocated_frame.has_value(), "[Page mapper] Unable to allocate frame");
- current_page_table->operator[](level_index)
- .set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE);
+ current_handle[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE);
// There should now be an entry at the previously not existent index, therefore we can simply access it again.
- next_page_table = current_page_table->next_table(page.get_level_index(level));
- exception_handling::assert(!next_page_table.has_value(),
+ next_handle = current_handle.next_table(page.get_level_index(level));
+ exception_handling::assert(!next_handle.has_value(),
"[Page mapper] Unable to create new entry into page table");
- next_page_table.value()->zero_entries();
+ next_handle.value().zero_entries();
}
- current_page_table = next_page_table.value();
+ current_handle = next_handle.value();
}
- auto level1_entry = current_page_table->operator[](page.get_level_index(page_table::LEVEL1));
+ auto level1_entry = current_handle[page.get_level_index(page_table::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 3439127..a1c8abe 100644
--- a/arch/x86_64/include/arch/memory/paging/page_table.hpp
+++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp
@@ -1,7 +1,7 @@
#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP
#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP
-#include "page_entry.hpp"
+#include "arch/memory/paging/page_entry.hpp"
namespace teachos::arch::memory::paging
{
@@ -41,27 +41,20 @@ namespace teachos::arch::memory::paging
/**
* @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 or it will return invalid addresses and cause hard to debug issues.
+ * 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 higher.
+ * @param table_index Index of this page table in the page table one level lower.
*/
- auto next_table(std::size_t table_index) -> std::optional<page_table *>;
+ auto next_table(std::size_t table_index) const -> std::optional<page_table *>;
/**
- * @brief Index operator overload to access specific mutable entry directy.
+ * @brief Index operator overload to access specific entries directy.
*
- * @param index Index of the entry we want to access and change.
+ * @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) -> 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 &;
+ auto operator[](std::size_t index) const -> entry;
private:
/**
@@ -72,13 +65,53 @@ namespace teachos::arch::memory::paging
* @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) -> std::optional<std::size_t>;
+ auto next_table_address(std::size_t table_index) const -> std::optional<std::size_t>;
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.
+ */
+ page_table_handle(page_table * handle, page_table::level handle_level);
+
+ /**
+ * @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. If this method is called with a
+ * Level 1 page table it will instead assert and halt execution, 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<page_table_handle>;
+
+ /**
+ * @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;
+
+ 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.
+ };
} // 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 6b9a641..f8dfbf0 100644
--- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp
+++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp
@@ -2,8 +2,8 @@
#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP
#include "arch/memory/allocator/physical_frame.hpp"
+#include "arch/memory/paging/page_table.hpp"
-#include "page_table.hpp"
#include <compare>
#include <cstdint>
#include <optional>
diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/src/exception_handling/assert.cpp
index b36f52d..b2963de 100644
--- a/arch/x86_64/src/exception_handling/assert.cpp
+++ b/arch/x86_64/src/exception_handling/assert.cpp
@@ -1,5 +1,7 @@
#include "arch/exception_handling/assert.hpp"
+#include "arch/exception_handling/panic.hpp"
+
namespace teachos::arch::exception_handling
{
auto assert(bool condition, char const * message) -> void
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp
index db0a9ef..88f6329 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/src/kernel/main.cpp
@@ -11,11 +11,9 @@ namespace teachos::arch::kernel
{
auto main() -> void
{
- using namespace video::vga;
-
- text::clear();
- text::cursor(false);
- text::write("TeachOS is starting up...", text::common_attributes::green_on_black);
+ video::vga::text::clear();
+ video::vga::text::cursor(false);
+ video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black);
auto memory_information = memory::multiboot::read_multiboot2();
memory::allocator::area_frame_allocator allocator(memory_information);
diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp
index cedda54..01c39ca 100644
--- a/arch/x86_64/src/memory/paging/page_mapper.cpp
+++ b/arch/x86_64/src/memory/paging/page_mapper.cpp
@@ -7,53 +7,46 @@ namespace teachos::arch::memory::paging
constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000;
}
- auto create_or_get() -> page_table *
+ auto create_or_get() -> page_table_handle
{
- static bool instantiated = false;
- static page_table * active_page = nullptr;
+ static page_table_handle active_page{reinterpret_cast<page_table *>(PAGE_TABLE_LEVEL_4_ADDRESS),
+ page_table::LEVEL4};
- if (instantiated)
- {
- return active_page;
- }
-
- instantiated = true;
- active_page = reinterpret_cast<page_table *>(PAGE_TABLE_LEVEL_4_ADDRESS);
return active_page;
}
auto translate_page(virtual_page page) -> std::optional<allocator::physical_frame>
{
- page_table * current_page_table = create_or_get();
+ auto current_handle = create_or_get();
for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--)
{
- auto next_page_table = current_page_table->next_table(page.get_level_index(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
// the table differently. Therefore, we attempt to parse it using the method required by huge pages.
- if (!next_page_table)
+ if (!next_handle)
{
return translate_huge_page(page);
}
- current_page_table = next_page_table.value();
+ current_handle = next_handle.value();
}
auto level1_index = page.get_level_index(page_table::LEVEL1);
- auto level1_frame = current_page_table->operator[](level1_index).calculate_pointed_to_frame();
+ auto level1_frame = current_handle[level1_index].calculate_pointed_to_frame();
return level1_frame;
}
auto translate_huge_page(virtual_page page) -> std::optional<allocator::physical_frame>
{
- page_table * current_page_table = create_or_get();
- auto level3_page_table = current_page_table->next_table(page.get_level_index(page_table::LEVEL4));
+ auto current_handle = create_or_get();
+ auto level3_handle = current_handle.next_table(page.get_level_index(page_table::LEVEL4));
- if (!level3_page_table)
+ if (!level3_handle)
{
return std::nullopt;
}
- auto level3_entry = level3_page_table.value()->operator[](page.get_level_index(page_table::LEVEL3));
+ auto level3_entry = level3_handle.value()[page.get_level_index(page_table::LEVEL3)];
auto level3_frame = level3_entry.calculate_pointed_to_frame();
if (level3_frame && level3_entry.contains_flags(entry::HUGE_PAGE))
{
@@ -65,10 +58,10 @@ namespace teachos::arch::memory::paging
page.get_level_index(page_table::LEVEL1)};
}
- auto level2_page_table = level3_page_table.value()->next_table(page.get_level_index(page_table::LEVEL3));
- if (level2_page_table)
+ auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table::LEVEL3));
+ if (level2_handle)
{
- auto level2_entry = level2_page_table.value()->operator[](page.get_level_index(page_table::LEVEL2));
+ auto level2_entry = level2_handle.value()[page.get_level_index(page_table::LEVEL2)];
auto level2_frame = level2_entry.calculate_pointed_to_frame();
if (level2_frame && level2_entry.contains_flags(entry::HUGE_PAGE))
{
diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp
index 5daf8bb..907b64f 100644
--- a/arch/x86_64/src/memory/paging/page_table.cpp
+++ b/arch/x86_64/src/memory/paging/page_table.cpp
@@ -14,11 +14,8 @@ namespace teachos::arch::memory::paging
}
}
- auto page_table::next_table(std::size_t table_index) -> std::optional<page_table *>
+ auto page_table::next_table(std::size_t table_index) const -> std::optional<page_table *>
{
- // TODO: Find another way to ensure the current page table is not LEVEL1
- // 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)
{
@@ -27,7 +24,7 @@ namespace teachos::arch::memory::paging
return std::nullopt;
}
- auto page_table::operator[](std::size_t index) -> entry &
+ auto page_table::operator[](std::size_t index) const -> 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.
@@ -35,7 +32,7 @@ namespace teachos::arch::memory::paging
return entries[index];
}
- auto page_table::next_table_address(std::size_t table_index) -> std::optional<std::size_t>
+ auto page_table::next_table_address(std::size_t table_index) const -> std::optional<std::size_t>
{
auto entry = this->operator[](table_index);
@@ -47,11 +44,34 @@ namespace teachos::arch::memory::paging
return std::nullopt;
}
- auto operator--(page_table::level & level, int) -> page_table::level
+ 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<std::underlying_type<page_table::level>::type>(level);
return static_cast<page_table::level>(--value);
}
+
+ page_table_handle::page_table_handle(page_table * handle, page_table::level handle_level)
+ : handle(handle)
+ , handle_level(handle_level)
+ {
+ exception_handling::assert(handle, "[Page table] Attemptd to pass nullptr as handle to page table handle method");
+ }
+
+ auto page_table_handle::zero_entries() -> void { handle->zero_entries(); }
+
+ auto page_table_handle::next_table(std::size_t table_index) const -> std::optional<page_table_handle>
+ {
+ exception_handling::assert(handle_level != page_table::LEVEL1,
+ "[Page Table] Attempted to call next_table on level 1 page table");
+ auto next_table = handle->next_table(table_index);
+ if (next_table)
+ {
+ return page_table_handle{next_table.value(), handle_level--};
+ }
+ return std::nullopt;
+ }
+
+ auto page_table_handle::operator[](std::size_t index) const -> entry { return handle->operator[](index); }
} // namespace teachos::arch::memory::paging