diff options
Diffstat (limited to 'arch')
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 |
