diff options
| -rw-r--r-- | arch/x86_64/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/cpu/control_register.hpp | 3 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/page_table.hpp | 127 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/paging_root.hpp | 27 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/recursive_page_mapper.hpp | 22 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/scoped_mapping.hpp | 68 | ||||
| -rw-r--r-- | arch/x86_64/kapi/memory.cpp | 147 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/boot32.S | 4 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging_root.cpp | 19 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/recursive_page_mapper.cpp | 121 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/scoped_mapping.cpp | 69 |
11 files changed, 63 insertions, 547 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9ea10e9..7bcf7c2 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -30,10 +30,7 @@ target_sources("x86_64" PRIVATE "src/memory/kernel_mapper.cpp" "src/memory/mmu.cpp" "src/memory/page_table.cpp" - "src/memory/paging_root.cpp" - "src/memory/recursive_page_mapper.cpp" "src/memory/region_allocator.cpp" - "src/memory/scoped_mapping.cpp" # VGA text mode "src/vga/text/buffer.cpp" diff --git a/arch/x86_64/include/arch/cpu/control_register.hpp b/arch/x86_64/include/arch/cpu/control_register.hpp index 681dc5f..fafbfc7 100644 --- a/arch/x86_64/include/arch/cpu/control_register.hpp +++ b/arch/x86_64/include/arch/cpu/control_register.hpp @@ -183,7 +183,8 @@ namespace arch::cpu //! @return The physical address of the root page map. [[nodiscard]] constexpr auto address() const -> kapi::memory::physical_address { - return kapi::memory::physical_address{m_address}; + constexpr auto address_shift = 12uz; + return kapi::memory::physical_address{m_address << address_shift}; } //! Encode the frame aligned physical address of the root page map into this value. diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp index e00e0a4..2889d38 100644 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ b/arch/x86_64/include/arch/memory/page_table.hpp @@ -3,17 +3,13 @@ #include "kapi/memory.hpp" -#include "arch/memory/page_utilities.hpp" - #include <kstd/ext/bitfield_enum> #include <array> -#include <bit> #include <cstddef> #include <cstdint> #include <optional> #include <type_traits> -#include <utility> namespace arch::memory { @@ -22,8 +18,9 @@ namespace arch::memory //! //! Page tables exist in a multi-level hierarchy and are used to map pages (virtual memory) onto frames (physical //! memory). Conceptually, pages represent the data found in a virtual address space, while frames represent their - //! storage. Only a level 1 page table maps an actual page onto a frame. All other page tables on higher levels do not - //! map payload pages, but rather their subordinate page tables. + //! storage. In most cases, only a level 1 page table maps an actual page onto a frame. All other page tables on + //! higher levels do not map payload pages, but rather their subordinate page tables. The only exception to that rule + //! is the use of huge pages. struct page_table { //! An entry in a page table. @@ -146,124 +143,6 @@ namespace arch::memory std::array<entry, entry_count> m_entries{}; }; - //! A recursively mapped page table. - //! - //! A page table in which at least one entry maps the same table. Recursive page tables allow for easy access to other - //! tables within the page mapping hierarchy, without having to map them prior to access, through careful construction - //! of linear addresses that pass through the same index multiple times. - template<std::size_t Level> - requires(Level > 0uz && Level < 5uz) - struct recursive_page_table : page_table - { - constexpr auto static next_level = Level - 1uz; - constexpr auto static recursive_index = 0776uz; - - //! Get the next lower lever table. - //! - //! @param self The object type of this object. - //! @param index The index corresponding to the desired page map. - //! @return An engaged std::optional holding a pointer to the next lower page table iff. the next lower page table - //! at the desired index is present, std::nullopt otherwise. - [[nodiscard]] auto next(this auto && self, std::size_t index) noexcept - requires(next_level > 1) - { - return self.next_address(index).transform([](auto address) -> auto { - auto table_pointer = std::bit_cast<recursive_page_table<next_level> *>(address); - return &std::forward_like<decltype(self)>(*table_pointer); - }); - } - - //! @copydoc recursive_page_table::next - //! - //! @note This overload returns a non-hierarchical, or leaf, page table - [[nodiscard]] auto next(this auto && self, std::size_t index) noexcept - requires(next_level == 1) - { - return self.next_address(index).transform([](auto address) -> auto { - auto table_pointer = std::bit_cast<page_table *>(address); - return &std::forward_like<decltype(self)>(*table_pointer); - }); - } - - [[nodiscard]] auto translate(kapi::memory::linear_address address) const - -> std::optional<kapi::memory::physical_address> - requires(Level == 4) - { - auto offset = address % kapi::memory::page::size; - return translate(kapi::memory::page::containing(address)).transform([offset](auto frame) -> auto { - return frame.start_address() + offset; - }); - } - - [[nodiscard]] auto translate(kapi::memory::page page) const -> std::optional<kapi::memory::frame> - requires(Level == 4) - { - auto pml3 = next(pml_index<4>(page)); - - if (!pml3) - { - return std::nullopt; - } - - auto handle_huge_page = [&] -> std::optional<kapi::memory::frame> { - auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (!pml3_entry) - { - return std::nullopt; - } - else if (pml3_entry->huge()) - { - auto pml3_entry_frame = *pml3_entry->frame(); - return kapi::memory::frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; - } - - auto pml2 = (*pml3)->next(pml_index<3>(page)); - auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; }); - if (!pml2_entry) - { - return std::nullopt; - } - else if (pml2_entry->huge()) - { - auto pml2_entry_frame = *pml2_entry->frame(); - return kapi::memory::frame{pml2_entry_frame.number() + pml_index<1>(page)}; - } - - return std::nullopt; - }; - - return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); }) - .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); }) - .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); }) - .or_else(handle_huge_page); - } - - private: - //! The number of address bits used to represent the page index per level. - constexpr auto static level_bits = 9; - //! The highest address bit. - constexpr auto static high_bit = 48; - //! The number of bits representing the offset into a page. - constexpr auto static offset_bits = 12; - - //! Calculate the recursive address of the next lower page table. - //! - //! @param index The index of the desired page table. - //! @return An engaged std::optional holding the address of the new lower page table iff. the next lower page table - //! at the desired index is present, std::nullopt otherwise. - [[nodiscard]] auto next_address(std::size_t index) const noexcept -> std::optional<std::uintptr_t> - { - if (auto entry = (*this)[index]; entry.present() && !entry.huge()) - { - auto this_address = std::bit_cast<std::uintptr_t>(this); - auto next_address = (this_address << level_bits) | 1uz << high_bit | (index << offset_bits); - return next_address; - } - - return std::nullopt; - } - }; - } // namespace arch::memory namespace kstd::ext diff --git a/arch/x86_64/include/arch/memory/paging_root.hpp b/arch/x86_64/include/arch/memory/paging_root.hpp deleted file mode 100644 index febbb11..0000000 --- a/arch/x86_64/include/arch/memory/paging_root.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_X86_64_PAGING_ROOT_HPP -#define TEACHOS_X86_64_PAGING_ROOT_HPP - -#include "arch/memory/page_table.hpp" - -namespace arch::memory -{ - - //! The active, recursively mapped, root map (e.g. PML4) - struct paging_root : recursive_page_table<4> - { - auto static get() -> paging_root *; - - paging_root(paging_root const &) = delete; - paging_root(paging_root &&) = delete; - auto operator=(paging_root const &) -> paging_root & = delete; - auto operator=(paging_root &&) -> paging_root & = delete; - - ~paging_root() = delete; - - private: - paging_root() = default; - }; - -} // namespace arch::memory - -#endif
\ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/recursive_page_mapper.hpp b/arch/x86_64/include/arch/memory/recursive_page_mapper.hpp deleted file mode 100644 index a0c290a..0000000 --- a/arch/x86_64/include/arch/memory/recursive_page_mapper.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TEACHOS_X86_64_RECURSIVE_PAGE_MAPPER_HPP -#define TEACHOS_X86_64_RECURSIVE_PAGE_MAPPER_HPP - -#include "kapi/memory.hpp" - -#include <cstddef> - -namespace arch::memory -{ - - struct recursive_page_mapper : kapi::memory::page_mapper - { - explicit recursive_page_mapper(); - - auto map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte * override; - auto unmap(kapi::memory::page page) -> void override; - auto try_unmap(kapi::memory::page page) noexcept -> bool override; - }; - -} // namespace arch::memory - -#endif
\ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/scoped_mapping.hpp b/arch/x86_64/include/arch/memory/scoped_mapping.hpp deleted file mode 100644 index c713e03..0000000 --- a/arch/x86_64/include/arch/memory/scoped_mapping.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef TEACHOS_X86_64_SCOPED_MAPPING_HPP -#define TEACHOS_X86_64_SCOPED_MAPPING_HPP - -#include "kapi/memory.hpp" - -#include "arch/memory/page_table.hpp" - -#include <cstddef> - -namespace arch::memory -{ - - //! A page mapping that, if established, maps a given frame to a given unused page, unmapping it on destruction. It - //! allows for an easy way to quickly map a page that is not required to be mapped forever. When mapping a frame, new - //! page tables may be allocated. On destruction, these pages tables, or rather their respective frames, will be - //! released again. - struct scoped_mapping - { - //! Copying a scoped mapping would be meaningless. - scoped_mapping(scoped_mapping const &) noexcept = delete; - - //! Adopt an existing scoped mapping, transferring mapping ownership to this new object. - scoped_mapping(scoped_mapping &&) noexcept; - - //! Construct a new scoped mapping, which can be used to map a frame to the given unused page. - //! @param page An unused page. If the page is already mapped, this constructor will panic. - //! @param mapper The page mapper to use for mapping and unmapping of the page. - explicit scoped_mapping(kapi::memory::page page, kapi::memory::page_mapper & mapper); - - //! Unmap the mapped frame if one was mapped. - //! @note Any page tables that were allocated to support the mapping will be released. - ~scoped_mapping() noexcept; - - //! Copying a scoped mapping would be meaningless. - auto operator=(scoped_mapping const &) -> scoped_mapping = delete; - - //! Adopt an existing scoped mapping, swapping mapping ownerships between the objects. - auto operator=(scoped_mapping &&) noexcept -> scoped_mapping &; - - //! Map the given frame with the given flags. - //! @note If a mapping has already been established, this function will panic - //! @param frame A frame to map. - //! @param flags The flags, besides the present flag, to apply to the mapping. - //! @return A pointer to the first byte of the mapped frame. - auto map(kapi::memory::frame frame, page_table::entry::flags flags) -> std::byte *; - - //! Map the given frame, returning a typed pointer. - template<typename DataType> - auto map_as(kapi::memory::frame frame, page_table::entry::flags flags) -> DataType * - { - return std::bit_cast<DataType *>(map(frame, flags)); - } - - //! Unmap the mapped frame. - //! @note If no frame was ever mapped, this function will panic. - auto unmap() -> void; - - friend auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void; - - private: - kapi::memory::page m_page; - kapi::memory::page_mapper * m_mapper; - bool m_mapped; - }; - -} // namespace arch::memory - -#endif
\ No newline at end of file diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 11bc69c..f74eea6 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -1,7 +1,6 @@ #include "kapi/memory.hpp" #include "kapi/boot.hpp" -#include "kapi/memory/buffered_allocator.hpp" #include "kapi/system.hpp" #include "arch/boot/boot.hpp" @@ -10,11 +9,7 @@ #include "arch/memory/kernel_mapper.hpp" #include "arch/memory/mmu.hpp" #include "arch/memory/page_table.hpp" -#include "arch/memory/page_utilities.hpp" -#include "arch/memory/paging_root.hpp" -#include "arch/memory/recursive_page_mapper.hpp" #include "arch/memory/region_allocator.hpp" -#include "arch/memory/scoped_mapping.hpp" #include <kstd/print> @@ -26,7 +21,6 @@ #include <bit> #include <cstddef> #include <cstdint> -#include <memory> #include <optional> #include <ranges> #include <span> @@ -37,12 +31,7 @@ namespace kapi::memory namespace { - constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; - constexpr auto static recursive_page_map_index = arch::memory::page_table::entry_count - 2; - auto constinit region_based_allocator = std::optional<arch::memory::region_allocator>{}; - auto constinit allocation_buffer = std::optional<buffered_allocator<4>>{}; - auto constinit recursive_page_mapper = std::optional<arch::memory::recursive_page_mapper>{}; //! Instantiate a basic, memory region based, early frame allocator for remapping. auto collect_memory_information() @@ -71,65 +60,13 @@ namespace kapi::memory arch::cpu::i32_efer::set(arch::cpu::i32_efer::flags::execute_disable_bit_enable); } - //! Inject, or graft, a faux recursive PML4 into the active page mapping structure. - auto inject_faux_pml4(frame_allocator & allocator, page_mapper & mapper) - { - using arch::memory::page_table; - using arch::memory::paging_root; - using arch::memory::pml_index; - using entry_flags = arch::memory::page_table::entry::flags; - - auto page = page::containing(unused_page_address); - - auto temporary_mapper = arch::memory::scoped_mapping{page, mapper}; - auto new_pml4_frame = allocator.allocate(); - - auto pml4 = std::construct_at(temporary_mapper.map_as<page_table>(*new_pml4_frame, entry_flags::writable)); - (*pml4)[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable); - - auto pml4_index = pml_index<4>(page); - auto old_pml4 = paging_root::get(); - auto pml4_entry = (*old_pml4)[pml4_index]; - - auto pml3_index = pml_index<3>(page); - auto old_pml3 = old_pml4->next(pml4_index); - auto pml3_entry = (**old_pml3)[pml3_index]; - - auto pml2_index = pml_index<2>(page); - auto old_pml2 = (**old_pml3).next(pml3_index); - auto pml2_entry = (**old_pml2)[pml2_index]; - - auto pml1_index = pml_index<1>(page); - auto old_pml1 = (**old_pml2).next(pml2_index); - auto pml1_entry = (**old_pml1)[pml1_index]; - - (*paging_root::get())[recursive_page_map_index].frame(new_pml4_frame.value(), - entry_flags::present | entry_flags::writable); - - arch::memory::tlb_flush_all(); - - auto new_pml4 = paging_root::get(); - (*new_pml4)[pml4_index] = pml4_entry; - - auto new_pml3 = new_pml4->next(pml4_index); - (**new_pml3)[pml3_index] = pml3_entry; - - auto new_pml2 = (**new_pml3).next(pml3_index); - (**new_pml2)[pml2_index] = pml2_entry; - - auto new_pml1 = (**new_pml2).next(pml2_index); - (**new_pml1)[pml1_index] = pml1_entry; - - return *new_pml4_frame; - } - - auto remap_kernel(page_mapper & mapper) -> void + [[maybe_unused]] auto remap_kernel(page_mapper & mapper) -> void { auto kernel_mapper = arch::memory::kernel_mapper{boot::bootstrap_information.mbi}; kernel_mapper.remap_kernel(mapper); } - auto remap_vga_text_mode_buffer(page_mapper & mapper) -> void + [[maybe_unused]] auto remap_vga_text_mode_buffer(page_mapper & mapper) -> void { constexpr auto vga_base = std::uintptr_t{0xb8000}; auto vga_physical_start = physical_address{vga_base}; @@ -141,7 +78,7 @@ namespace kapi::memory mapper.map(page, frame, page_mapper::flags::writable | page_mapper::flags::supervisor_only); } - auto remap_multiboot_information(page_mapper & mapper) -> void + [[maybe_unused]] auto remap_multiboot_information(page_mapper & mapper) -> void { auto mbi_base = std::bit_cast<std::uintptr_t>(boot::bootstrap_information.mbi); auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); @@ -157,7 +94,7 @@ namespace kapi::memory } } - auto handoff_to_kernel_pmm(frame_allocator & new_allocator) -> void + [[maybe_unused]] auto handoff_to_kernel_pmm(frame_allocator & new_allocator) -> void { auto memory_map = boot::bootstrap_information.mbi->memory_map(); @@ -196,6 +133,39 @@ namespace kapi::memory std::ranges::for_each(std::views::iota(mbi_start, mbi_end), [&](auto frame) { new_allocator.mark_used(frame); }); } + auto establish_higher_half_direct_mapping() -> void + { + auto hhdm_frame = kapi::memory::allocate_frame(); + auto hhdm_pml3 = static_cast<arch::memory::page_table *>(hhdm_frame->start_address()); + hhdm_pml3->clear(); + + std::ranges::for_each(std::views::iota(0uz, 512uz), [&](auto index) { + auto frame = kapi::memory::frame{(1024uz * 1024uz * 1024uz * index)}; + auto & entry = (*hhdm_pml3)[index]; + entry.frame(frame, arch::memory::page_table::entry::flags::present | + arch::memory::page_table::entry::flags::writable | + arch::memory::page_table::entry::flags::huge_page); + }); + + auto current_cr3 = arch::cpu::cr3::read(); + auto pml4_address = linear_address{current_cr3.address().raw()}; + auto pml4 = static_cast<arch::memory::page_table *>(pml4_address); + (*pml4)[256].frame(*hhdm_frame, arch::memory::page_table::entry::flags::present | + arch::memory::page_table::entry::flags::writable | + arch::memory::page_table::entry::flags::global); + } + + auto clear_lower_address_space() -> void + { + auto current_cr3 = arch::cpu::cr3::read(); + auto pml4_address = memory::higher_half_direct_map_base + current_cr3.address().raw(); + auto pml4 = static_cast<arch::memory::page_table *>(pml4_address); + + std::ranges::for_each(std::views::iota(0uz, 1uz), [&](auto index) { (*pml4)[index].clear(); }); + + arch::memory::tlb_flush_all(); + } + } // namespace auto init() -> void @@ -212,37 +182,36 @@ namespace kapi::memory enable_cpu_protections(); region_based_allocator.emplace(collect_memory_information()); - allocation_buffer.emplace(&*region_based_allocator); - set_frame_allocator(*allocation_buffer); + set_frame_allocator(*region_based_allocator); - recursive_page_mapper.emplace(); - set_page_mapper(*recursive_page_mapper); + kstd::println("[x86_64:MEM] Establishing higher-half direct mapping."); - kstd::println("[x86_64:MEM] Preparing new paging hierarchy."); + establish_higher_half_direct_mapping(); + clear_lower_address_space(); - auto new_pml4_frame = inject_faux_pml4(*allocation_buffer, *recursive_page_mapper); + kstd::println("[x86_64:MEM] Preparing new paging hierarchy."); - remap_kernel(*recursive_page_mapper); - remap_vga_text_mode_buffer(*recursive_page_mapper); - remap_multiboot_information(*recursive_page_mapper); + // remap_kernel(*recursive_page_mapper); + // remap_vga_text_mode_buffer(*recursive_page_mapper); + // remap_multiboot_information(*recursive_page_mapper); - kstd::println("[x86_64:MEM] Switching to new paging hierarchy."); + // kstd::println("[x86_64:MEM] Switching to new paging hierarchy."); - auto cr3 = arch::cpu::cr3::read(); - cr3.frame(new_pml4_frame); - arch::cpu::cr3::write(cr3); + // auto cr3 = arch::cpu::cr3::read(); + // cr3.frame(new_pml4_frame); + // arch::cpu::cr3::write(cr3); - auto memory_map = boot::bootstrap_information.mbi->memory_map(); - auto highest_byte = std::ranges::max(std::views::transform( - std::views::filter(memory_map.regions(), - [](auto const & region) { return region.type == multiboot2::memory_type::available; }), - [](auto const & region) { return region.base + region.size_in_B; })); + // auto memory_map = boot::bootstrap_information.mbi->memory_map(); + // auto highest_byte = std::ranges::max(std::views::transform( + // std::views::filter(memory_map.regions(), + // [](auto const & region) { return region.type == multiboot2::memory_type::available; }), + // [](auto const & region) { return region.base + region.size_in_B; })); - init_pmm(frame::containing(physical_address{highest_byte}).number() + 1, handoff_to_kernel_pmm); + // init_pmm(frame::containing(physical_address{highest_byte}).number() + 1, handoff_to_kernel_pmm); - kstd::println("[x86_64:MEM] Releasing bootstrap memory allocators."); - allocation_buffer.reset(); - region_based_allocator.reset(); + // kstd::println("[x86_64:MEM] Releasing bootstrap memory allocators."); + // allocation_buffer.reset(); + // region_based_allocator.reset(); } } // namespace kapi::memory diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 056cd8e..694b8b7 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -319,10 +319,6 @@ _prepare_page_maps: call _clear_page_map_memory lea (page_map_level_4 - 0b)(%esi), %edi - mov %edi, %eax - or $0b11, %eax - mov %eax, (510 * 8)(%edi) - lea (page_map_level_3_low - 0b)(%esi), %eax or $0b11, %eax mov %eax, (%edi) diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp deleted file mode 100644 index 41f40ed..0000000 --- a/arch/x86_64/src/memory/paging_root.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "arch/memory/paging_root.hpp" - -#include <bit> -#include <cstdint> - -namespace arch::memory -{ - - namespace - { - constexpr auto recursive_base = std::uintptr_t{0177777'776'776'776'776'0000uz}; - } // namespace - - auto paging_root::get() -> paging_root * - { - return std::bit_cast<paging_root *>(recursive_base); - } - -} // namespace arch::memory
\ No newline at end of file diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp deleted file mode 100644 index c7c5341..0000000 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "arch/memory/recursive_page_mapper.hpp" - -#include "kapi/memory.hpp" -#include "kapi/system.hpp" - -#include "arch/memory/page_table.hpp" -#include "arch/memory/page_utilities.hpp" -#include "arch/memory/paging_root.hpp" - -#include <cstddef> -#include <optional> - -namespace arch::memory -{ - namespace - { - //! Perform the actual mapping of the page, via the recursive page map. - //! - //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries - //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When - //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit - //! added, thus still enforcing non-writability and non-execution of the affected page. - template<std::size_t Level> - requires(Level > 1uz && Level <= PLATFORM_PAGING_LEVELS) - auto do_map(recursive_page_table<Level> * pml, kapi::memory::page page, kapi::memory::frame_allocator & allocator, - kapi::memory::page_mapper::flags flags) - { - auto index = pml_index<Level>(page); - auto entry_flags = to_table_flags(flags); - - entry_flags = entry_flags & ~page_table::entry::flags::no_execute; - entry_flags = entry_flags | page_table::entry::flags::writable; - if (!(*pml)[index].present()) - { - auto new_table_frame = allocator.allocate(); - (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | entry_flags); - auto new_table = std::optional{std::construct_at(*pml->next(index))}; - return new_table; - } - (*pml)[index] |= entry_flags; - return pml->next(index); - } - - //! Perform the actual PML1 update. - auto do_map(page_table * pml, kapi::memory::page page, kapi::memory::frame frame, - kapi::memory::page_mapper::flags flags) -> std::optional<std::byte *> - { - auto index = pml_index<1>(page); - if ((*pml)[index].present()) - { - kapi::system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); - } - (*pml)[index].frame(frame, page_table::entry::flags::present | to_table_flags(flags)); - return std::optional{static_cast<std::byte *>(page.start_address())}; - } - - } // namespace - - recursive_page_mapper::recursive_page_mapper() {} - - auto recursive_page_mapper::map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte * - { - auto pml4 = static_cast<recursive_page_table<4> *>((paging_root::get())); - auto & allocator = kapi::memory::get_frame_allocator(); - - return std::optional{pml4} - .and_then([&](auto pml) -> auto { return do_map(pml, page, allocator, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, allocator, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, allocator, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }) - .value_or(nullptr); - } - - auto recursive_page_mapper::unmap(kapi::memory::page page) -> void - { - if (!try_unmap(page)) - { - kapi::system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); - } - } - - auto recursive_page_mapper::try_unmap(kapi::memory::page page) noexcept -> bool - { - if (!paging_root::get()->translate(page)) - { - return false; - } - - auto pml4 = paging_root::get(); - auto pml3 = pml4->next(pml_index<4>(page)).value(); - auto pml2 = pml3->next(pml_index<3>(page)).value(); - auto pml1 = pml2->next(pml_index<2>(page)).value(); - auto & allocator = kapi::memory::get_frame_allocator(); - - (*pml1)[pml_index<1>(page)].clear(); - - if (pml1->empty()) - { - auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); - allocator.release(pml1_frame); - (*pml2)[pml_index<2>(page)].clear(); - } - - if (pml2->empty()) - { - auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); - allocator.release(pml2_frame); - (*pml3)[pml_index<3>(page)].clear(); - } - - if (pml3->empty()) - { - auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); - allocator.release(pml3_frame); - (*pml4)[pml_index<4>(page)].clear(); - } - - return true; - } - -} // namespace arch::memory
\ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp deleted file mode 100644 index dde1dda..0000000 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "arch/memory/scoped_mapping.hpp" - -#include "kapi/memory.hpp" -#include "kapi/system.hpp" - -#include "arch/memory/mmu.hpp" -#include "arch/memory/page_table.hpp" -#include "arch/memory/paging_root.hpp" - -#include <cstddef> -#include <utility> - -namespace arch::memory -{ - - scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept - : m_page{std::exchange(other.m_page, kapi::memory::page{})} - , m_mapper{std::exchange(other.m_mapper, nullptr)} - , m_mapped{std::exchange(other.m_mapped, false)} - {} - - scoped_mapping::scoped_mapping(kapi::memory::page page, kapi::memory::page_mapper & mapper) - : m_page{page} - , m_mapper{&mapper} - , m_mapped{false} - { - if (paging_root::get()->translate(page)) - { - kapi::system::panic("[MEM] Tried to map a page that is already mapped!"); - } - } - - scoped_mapping::~scoped_mapping() noexcept - { - if (m_mapped) - { - unmap(); - tlb_flush(m_page.start_address()); - } - } - - auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & - { - swap(*this, other); - return *this; - } - - auto scoped_mapping::map(kapi::memory::frame frame, page_table::entry::flags flags) -> std::byte * - { - auto result = m_mapper->map(m_page, frame, to_mapper_flags(flags)); - m_mapped = true; - return result; - } - - auto scoped_mapping::unmap() -> void - { - m_mapper->unmap(m_page); - m_mapped = false; - } - - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void - { - using std::swap; - swap(lhs.m_page, rhs.m_page); - swap(lhs.m_mapper, rhs.m_mapper); - swap(lhs.m_mapped, rhs.m_mapped); - } - -} // namespace arch::memory
\ No newline at end of file |
