diff options
Diffstat (limited to 'arch/x86_64')
14 files changed, 237 insertions, 267 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 7f3a203..1444054 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,7 +52,6 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" - "src/memory/paging/kernel_mapper.cpp" "src/memory/cpu/tlb.cpp" "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" 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 f1a3a64..adba4f1 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,7 +1,6 @@ #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/frame_allocator.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/multiboot/reader.hpp" @@ -12,7 +11,7 @@ namespace teachos::arch::memory::allocator /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ - struct area_frame_allocator : frame_allocator + struct area_frame_allocator { /** * @brief Constructor @@ -33,7 +32,7 @@ namespace teachos::arch::memory::allocator * * @return next free physical frame or nullopt if none was found. */ - auto allocate_frame() -> std::optional<physical_frame> override; + auto allocate_frame() -> std::optional<physical_frame>; /** * @brief Deallocates a previously allocated physical frame. @@ -44,7 +43,7 @@ namespace teachos::arch::memory::allocator * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(physical_frame const & physical_frame) -> void override; + auto deallocate_frame(physical_frame const & physical_frame) -> void; private: /** diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp new file mode 100644 index 0000000..9d58fad --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/concept.hpp @@ -0,0 +1,22 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include <optional> + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Frame allocator concept + * + * @tparam T + */ + template<typename T> + concept FrameAllocator = requires(T t, physical_frame const & a) { + { t.allocate_frame() } -> std::same_as<std::optional<physical_frame>>; + { t.deallocate_frame(a) } -> std::same_as<void>; + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp deleted file mode 100644 index 9316ca9..0000000 --- a/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_FRAME_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_FRAME_ALLOCATOR_HPP - -#include "arch/memory/allocator/physical_frame.hpp" - -#include <optional> - -namespace teachos::arch::memory::allocator -{ - - struct frame_allocator - { - auto virtual allocate_frame() -> std::optional<physical_frame> = 0; - auto virtual deallocate_frame(physical_frame const & frame) -> void = 0; - }; // namespace teachos::arch::memory::allocator - -} // namespace teachos::arch::memory::allocator - -#endif
\ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index c449ac8..8124442 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP -#include "arch/memory/allocator/frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include <array> @@ -16,17 +16,33 @@ namespace teachos::arch::memory::allocator /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ - struct tiny_frame_allocator : frame_allocator + struct tiny_frame_allocator { /** * @brief Constructor. * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. + * @tparam T Contract the allocator that should be used to actually allocate and deallocate, the underlying three + * frames has to follow. + * * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries *when a new page table is required. + * entries when the underlying frames are created. */ - tiny_frame_allocator(frame_allocator & allocator); + template<allocator::FrameAllocator T> + tiny_frame_allocator(T & allocator) + : frames{} + { + // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(), + // does not work because it would set the value correctly but because we pass it as an std::optional it would not + // set the engaged flag. Meaning the has_value() method would still return false. + for (auto & frame : frames) + { + auto allocated = allocator.allocate_frame(); + if (allocated.has_value()) + { + frame.emplace(allocated.value()); + } + } + } /** * @brief Allocate memory by finding and returning one of the three free physical frames. @@ -34,7 +50,7 @@ namespace teachos::arch::memory::allocator * @return First free physical frames of the three frames held by this allocator or nullopt if we used up all three * frames already. */ - auto allocate_frame() -> std::optional<physical_frame> override; + auto allocate_frame() -> std::optional<physical_frame>; /** * @brief Deallocates one of the three previously allocated physical frames. @@ -44,7 +60,7 @@ namespace teachos::arch::memory::allocator * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(physical_frame const & physical_frame) -> void override; + auto deallocate_frame(physical_frame const & physical_frame) -> void; private: std::array<std::optional<physical_frame>, TINY_ALLOCATOR_FRAMES_COUNT> frames = diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index e558fa5..88c1c82 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP -#include "arch/memory/allocator/frame_allocator.hpp" -#include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/paging/page_table.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/cpu/tlb.hpp" #include "arch/memory/paging/virtual_page.hpp" #include <array> @@ -66,21 +66,44 @@ namespace teachos::arch::memory::paging * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 * page table already exists it halts execution instead. * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries when a new page table is required. * @param page Virtual page that is being mapped. * @param frame Physical frame that the virtual page will be mapped to. * @param flags A bitset of flags that configure the page table entry for this mapping. */ - auto map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void; + template<allocator::FrameAllocator T> + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); + } + + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::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"); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); + } + /** * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. * * @see map_page_to_frame */ - auto map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, - std::bitset<64U> flags) -> void; + template<allocator::FrameAllocator T> + auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + { + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } /** * @brief Gets the corresponding page the given frame has to be contained in and uses that to call @@ -88,8 +111,12 @@ namespace teachos::arch::memory::paging * * @see map_page_to_frame */ - auto identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame, - std::bitset<64U> flags) -> void; + template<allocator::FrameAllocator T> + auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto const page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } /** * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. @@ -103,7 +130,27 @@ namespace teachos::arch::memory::paging * entries when a new page table is required. * @param page Virtual page that is being unmapped. */ - auto unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void; + template<allocator::FrameAllocator T> + auto unmap_page(T & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not + // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + } + + unmap_page_table_entry(allocator, page, current_handle); + cpu::tlb_flush(page.start_address()); + } private: /** @@ -127,13 +174,24 @@ namespace teachos::arch::memory::paging /** * @brief Unmaps specific page at the current internal handle level. * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries *when a new page table is required. * @param page Virtual page that is being unmapped. * @param handle Page Table handle we want to access the entry that should be cleared on. */ - static auto unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page, - page_table_handle & handle) -> void; + template<allocator::FrameAllocator T> + static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + { + auto level_index = page.get_level_index(handle.get_level()); + auto & entry = handle[level_index]; + auto const frame = entry.calculate_pointed_to_frame(); + exception_handling::assert(frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + entry.set_unused(); + allocator.deallocate_frame(frame.value()); + } public: page_table_handle active_handle; ///< Underlying active level 4 page table diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 2f55a13..f980451 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP -#include "arch/memory/allocator/frame_allocator.hpp" -#include "arch/memory/multiboot/reader.hpp" +#include "arch/memory/cpu/control_register.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" +#include "arch/video/vga/text.hpp" namespace teachos::arch::memory::paging { @@ -14,6 +14,7 @@ namespace teachos::arch::memory::paging * * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. */ + template<allocator::FrameAllocator T> struct kernel_mapper { /** @@ -22,7 +23,12 @@ namespace teachos::arch::memory::paging * @param allocator Allocator that should be used to allocate frames for the remapping process. * @param mem_info Information about elf kernel sections required for remapping process. */ - kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info); + kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) + : allocator(allocator) + , mem_info(mem_info) + { + // Nothing to do + } /** * @brief Remap the kernel, meaning we map the entire kernel and all of it's elf sections with the correct flags @@ -32,7 +38,21 @@ namespace teachos::arch::memory::paging * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because * remapping active kernel memory in the kernel wouldn't work. */ - auto remap_kernel() -> active_page_table &; + auto remap_kernel() -> active_page_table & + { + temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; + auto & active_table = active_page_table::create_or_get(); + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), + "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); + inactive_page_table new_table{frame.value(), active_table, temporary_page}; + remap_elf_kernel_sections(new_table, temporary_page, active_table); + auto const old_table = switch_active_page_table(new_table); + auto const old_level_4_page = + virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); + active_table.unmap_page(allocator, old_level_4_page); + return active_table; + } private: /** @@ -43,8 +63,8 @@ namespace teachos::arch::memory::paging * Once the remapping process is done we can restore the original recursive mapping with the complete remapped * kernel. * - * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before - * we map the entries. + * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before we + * map the entries. * * @param inactive_table Level 4 page table we temporarily map the kernel into. * @param temporary_page Temporary page that should be used for the mapping process and then @@ -53,7 +73,20 @@ namespace teachos::arch::memory::paging * restored once the process is finished. */ auto remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, - active_page_table & active_table) -> void; + active_page_table & active_table) -> void + { + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); + + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + cpu::tlb_flush_all(); + map_elf_kernel_sections(active_table); + + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + cpu::tlb_flush_all(); + temporary_page.unmap_page(active_table); + } /** * @brief Switches the current active table pointed to by the CR3 register with another page table that is currently @@ -62,7 +95,16 @@ namespace teachos::arch::memory::paging * @param new_table Inactive page table that should now be made active and replace the current active one. * @return The previous active page table. */ - auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table; + auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table + { + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + auto const old_table = inactive_page_table{backup}; + + auto const new_address = new_table.page_table_level_4_frame.start_address(); + cpu::write_control_register(cpu::control_register::CR3, new_address); + return old_table; + } /** * @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of @@ -71,9 +113,41 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that should be used to map the required elf sections into entries. * Has had its recursive mapping temporarily replaced and points to unmapped place in memory. */ - auto map_elf_kernel_sections(active_page_table & active_table) -> void; + auto map_elf_kernel_sections(active_page_table & active_table) -> void + { + exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); + for (auto const & section : mem_info.sections) + { + if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + { + continue; + } + exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, + "[Kernel Mapper] Section must be page aligned"); + auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); + // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this + // section). But end frame would now point to the actual last frame and not one past the last frame, therefore + // we increment by one to get one past the last frame of this section. + auto const end_frame = + ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); + + allocator::frame_container::iterator const begin{start_frame}; + allocator::frame_container::iterator const end{end_frame}; + allocator::frame_container const frames{begin, end}; + entry const entry{section.flags}; + + for (auto const & frame : frames) + { + active_table.identity_map(allocator, frame, entry.get_flags()); + } + } + + auto const vga_buffer_frame = + allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); + active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); + } - allocator::frame_allocator & allocator; + T & allocator; multiboot::memory_information const & mem_info; ///< Information about elf kernel sections required for remapping process. }; 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 24ff8f4..7a15875 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/paging/page_entry.hpp" namespace teachos::arch::memory::paging @@ -82,7 +82,26 @@ namespace teachos::arch::memory::paging * entries when a new page table is required. * @param table_index Index of this page table in the page table one level lower. */ - auto next_table_or_create(allocator::frame_allocator & allocator, std::size_t table_index) -> page_table_handle; + template<allocator::FrameAllocator T> + auto next_table_or_create(T & allocator, std::size_t table_index) -> page_table_handle + { + auto next_handle = next_table(table_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_handle.has_value()) + { + auto const allocated_frame = allocator.allocate_frame(); + exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); + this->operator[](table_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_handle = next_table(table_index); + exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); + next_handle.value().zero_entries(); + } + return next_handle.value(); + } /** * @brief Index operator overload to access specific mutable entry directy. diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 3c4301a..02cb545 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -14,13 +14,20 @@ namespace teachos::arch::memory::paging struct temporary_page { /** - * @brief Construct a new temporary page object + * @brief Construct a new temporary page object. * - * @tparam FrameAllocator concept - * @param page Page to turn into temporary page - * @param allocator Frame allocator used to fill page + * @tparam Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param page Page to turn into temporary page. + * @param allocator Frame allocator used to fill page. */ - temporary_page(virtual_page page, allocator::frame_allocator & allocator); + template<allocator::FrameAllocator T> + temporary_page(virtual_page page, T & allocator) + : page{page} + , allocator{allocator} + { + // Nothing to do + } /** * @brief Unmap the current page. diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp index ed000a0..3cdf9c7 100644 --- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp @@ -4,22 +4,6 @@ namespace teachos::arch::memory::allocator { - tiny_frame_allocator::tiny_frame_allocator(frame_allocator & allocator) - : frames{} - { - // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(), - // does not work because it would set the value correctly but because we pass it as an std::optional it would not - // set the engaged flag. Meaning the has_value() method would still return false. - for (auto & frame : frames) - { - auto allocated = allocator.allocate_frame(); - if (allocated.has_value()) - { - frame.emplace(allocated.value()); - } - } - } - auto tiny_frame_allocator::allocate_frame() -> std::optional<physical_frame> { for (auto & frame_option : frames) diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index d2bf683..0113869 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -1,7 +1,5 @@ #include "arch/memory/paging/active_page_table.hpp" -#include "arch/memory/cpu/tlb.hpp" - namespace teachos::arch::memory::paging { namespace @@ -17,71 +15,6 @@ namespace teachos::arch::memory::paging return active_page; } - auto active_page_table::map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, - allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); - } - - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::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"); - level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); - } - - auto active_page_table::identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame, - std::bitset<64U> flags) -> void - { - auto const page = virtual_page::containing_address(frame.start_address()); - map_page_to_frame(allocator, page, frame, flags); - } - - auto active_page_table::map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, - std::bitset<64U> flags) -> void - { - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); - map_page_to_frame(allocator, page, frame.value(), flags); - } - - auto active_page_table::unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void - { - exception_handling::assert(translate_page(page).has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const level_index = page.get_level_index(level); - auto const next_handle = current_handle.next_table(level_index); - // The next table method failed even tough the page has to be mapped already, because translate_page did not - // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. - exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); - current_handle = next_handle.value(); - } - - unmap_page_table_entry(allocator, page, current_handle); - cpu::tlb_flush(page.start_address()); - } - - auto active_page_table::unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page, - page_table_handle & handle) -> void - { - auto level_index = page.get_level_index(handle.get_level()); - auto & entry = handle[level_index]; - auto const frame = entry.calculate_pointed_to_frame(); - exception_handling::assert(frame.has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - entry.set_unused(); - allocator.deallocate_frame(frame.value()); - } - auto active_page_table::operator[](std::size_t index) -> entry & { return active_handle[index]; } auto active_page_table::translate_address(virtual_address address) -> std::optional<allocator::physical_address> diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp deleted file mode 100644 index f938cb3..0000000 --- a/arch/x86_64/src/memory/paging/kernel_mapper.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "arch/memory/paging/kernel_mapper.hpp" - -#include "arch/memory/cpu/control_register.hpp" -#include "arch/memory/cpu/tlb.hpp" -#include "arch/memory/paging/temporary_page.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::memory::paging -{ - - kernel_mapper::kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info) - : allocator(allocator) - , mem_info(mem_info) - { - // Nothing to do - } - - auto kernel_mapper::remap_kernel() -> active_page_table & - { - temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; - auto & active_table = active_page_table::create_or_get(); - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), - "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - inactive_page_table new_table{frame.value(), active_table, temporary_page}; - remap_elf_kernel_sections(new_table, temporary_page, active_table); - auto const old_table = switch_active_page_table(new_table); - auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); - active_table.unmap_page(allocator, old_level_4_page); - return active_table; - } - - auto kernel_mapper::remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, - active_page_table & active_table) -> void - { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - - active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); - map_elf_kernel_sections(active_table); - - page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); - temporary_page.unmap_page(active_table); - } - - auto kernel_mapper::switch_active_page_table(inactive_page_table new_table) -> inactive_page_table - { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - auto const old_table = inactive_page_table{backup}; - - auto const new_address = new_table.page_table_level_4_frame.start_address(); - cpu::write_control_register(cpu::control_register::CR3, new_address); - return old_table; - } - - auto kernel_mapper::map_elf_kernel_sections(active_page_table & active_table) -> void - { - exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); - for (auto const & section : mem_info.sections) - { - if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) - { - continue; - } - exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, - "[Kernel Mapper] Section must be page aligned"); - auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); - // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this - // section). But end frame would now point to the actual last frame and not one past the last frame, therefore - // we increment by one to get one past the last frame of this section. - auto const end_frame =< |
