diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-12-02 18:40:10 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-12-02 18:40:10 +0100 |
| commit | a96b1b4b43a1ed962b412c3d28db0fe00661d96f (patch) | |
| tree | ddc7e9dcc9814b07c2ff36d4875a0fe2ae13a665 | |
| parent | be86be1facfce8fe3f376153b9c582f2c5c026aa (diff) | |
| download | teachos-a96b1b4b43a1ed962b412c3d28db0fe00661d96f.tar.xz teachos-a96b1b4b43a1ed962b412c3d28db0fe00661d96f.zip | |
x86_64/memory: extract PML4 injection
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/page_table.hpp | 3 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/scoped_mapping.hpp | 4 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/memory.cpp | 79 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/page_table.cpp | 6 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging_root.cpp | 18 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/scoped_mapping.cpp | 77 |
6 files changed, 103 insertions, 84 deletions
diff --git a/arch/x86_64/include/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp index 53af5d0..6b8eb8c 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -74,6 +74,9 @@ namespace teachos::memory::x86_64 //! Clear the entire page table, effectively evicting all entries. auto clear() -> void; + //! Check if the page table is empty. + [[nodiscard]] auto empty() const noexcept -> bool; + private: std::array<entry, entry_count> m_entries{}; }; diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index 1719e6b..5737bb0 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -12,7 +12,7 @@ namespace teachos::memory::x86_64 { scoped_mapping(scoped_mapping const &) = delete; scoped_mapping(scoped_mapping &&); - scoped_mapping(linear_address address, frame_allocator & allocator); + scoped_mapping(page page, frame_allocator & allocator); ~scoped_mapping(); @@ -29,7 +29,7 @@ namespace teachos::memory::x86_64 } private: - linear_address m_address; + page m_page; frame_allocator * m_allocator; bool m_mapped; }; diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 920c82b..36b1706 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,6 +1,5 @@ #include "kapi/memory.hpp" -#include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" @@ -28,7 +27,8 @@ namespace teachos::memory // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast<frame_allocator *>(nullptr); - constexpr auto static unused_page_address = 0x0000'7fff'cafe'faceuz; + constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; + constexpr auto static recursive_page_map_index = 510; auto create_memory_information() -> x86_64::region_allocator::memory_information { @@ -61,62 +61,18 @@ namespace teachos::memory auto inject_faux_pml4(frame_allocator & allocator) -> void { - using entry_flags = x86_64::page_table::entry::flags; - using page_table = x86_64::page_table; - - auto temporary_page = page::containing(linear_address{unused_page_address}); - auto temporary_page_address = temporary_page.start_address(); - - auto & pml4 = x86_64::paging_root::get(); - - // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) - auto faux_pml4_frame = - allocator.allocate() - .and_then([&](auto frame) -> auto { - auto index = temporary_page_address >> 39 & 0x1ffu; - pml4[index].frame(frame, entry_flags::present | entry_flags::writable); - return pml4.next(index); - }) - .and_then([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 30 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml->next(index); - }) - .and_then([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 21 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml->next(index); - }) - .transform([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 12 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml; - }) - .and_then([&](auto pml) -> auto { - auto faux_pml4_pointer = std::bit_cast<page_table *>(temporary_page_address.raw()); - auto faux_pml4 = std::construct_at<page_table>(faux_pml4_pointer); - - auto index = temporary_page_address >> 12 & 0x1ffu; - auto frame = (*pml)[index].frame(); - - (*faux_pml4)[510].frame(*frame, entry_flags::present | entry_flags::writable); - return frame; - }); - // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) - - if (!faux_pml4_frame) - { - system::panic("[MEM] Failed to map and construct faux PML4"); - } + using namespace x86_64; + using entry_flags = page_table::entry::flags; + + auto temporary_mapper = scoped_mapping{page::containing(unused_page_address), allocator}; + auto new_pml4_frame = allocator.allocate(); - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) - pml4[510].frame(*faux_pml4_frame, entry_flags::present | entry_flags::writable); - x86_64::tlb_flush_all(); + 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); + paging_root::get()[recursive_page_map_index].frame(new_pml4_frame.value(), + entry_flags::present | entry_flags::writable); - cio::println("[MEM] Injected faux PML4 as recursive map."); + tlb_flush_all(); } } // namespace @@ -141,19 +97,8 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - - // TODO: remove inject_faux_pml4(allocator); - // TODO: implement - auto temporary_mapper = x86_64::scoped_mapping{linear_address{unused_page_address}, allocator}; - auto new_pml4_frame = allocator.allocate(); - - auto new_plm4 = temporary_mapper.map_as<x86_64::page_table>( - *new_pml4_frame, x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); - (*new_plm4)[510].frame(new_pml4_frame.value(), - x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); - // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 1273676..60bf94d 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -54,4 +54,10 @@ namespace teachos::memory::x86_64 std::ranges::for_each(m_entries, &page_table::entry::clear); } + auto page_table::empty() const noexcept -> bool + { + return std::ranges::all_of(m_entries, + [](auto const & entry) -> auto { return entry.all_flags() == entry::flags::empty; }); + } + } // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b65f60..a29304e 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -40,13 +40,27 @@ namespace teachos::memory::x86_64 auto handle_huge_page = [&] -> std::optional<frame> { auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (pml3_entry && pml3_entry->huge()) + if (!pml3_entry) + { + return std::nullopt; + } + else if (pml3_entry->huge()) { auto pml3_entry_frame = *pml3_entry->frame(); return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; } - // auto pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + 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 frame{pml2_entry_frame.number() + pml_index<1>(page)}; + } return std::nullopt; }; diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 27c4785..602198e 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,25 +4,28 @@ #include "kapi/system.hpp" #include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include <memory> #include <utility> namespace teachos::memory::x86_64 { scoped_mapping::scoped_mapping(scoped_mapping && other) - : m_address{std::exchange(other.m_address, linear_address{})} + : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} {} - scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) - : m_address{address} + scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + : m_page{page} , m_allocator{&allocator} , m_mapped{false} { - if (paging_root::get().translate(address)) + if (paging_root::get().translate(page)) { system::panic("[MEM] Tried to map a page that is already mapped!"); } @@ -33,7 +36,7 @@ namespace teachos::memory::x86_64 if (m_mapped) { unmap(); - x86_64::tlb_flush(m_address); + x86_64::tlb_flush(m_page.start_address()); } } @@ -46,7 +49,7 @@ namespace teachos::memory::x86_64 using std::swap; - swap(m_address, other.m_address); + swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); @@ -55,12 +58,38 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - static_cast<void>(frame); - static_cast<void>(flags); + auto & pml4 = paging_root::get(); + auto pml4_index = pml_index<4>(m_page); + if (!pml4[pml4_index].present()) + { + auto new_frame = m_allocator->allocate(); + pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at(pml4.next(pml4_index).value()); + } - m_mapped = true; + auto pml3 = pml4.next(pml4_index).value(); + auto pml3_index = pml_index<3>(m_page); + if (!(*pml3)[pml3_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml3).next(pml3_index).value()); + } - return nullptr; + auto pml2 = (*pml3).next(pml3_index).value(); + auto pml2_index = pml_index<2>(m_page); + if (!(*pml2)[pml2_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml2).next(pml2_index).value()); + } + + auto pml1 = (*pml2).next(pml2_index).value(); + auto pml1_index = pml_index<1>(m_page); + (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + + return static_cast<std::byte *>(frame.start_address()); } auto scoped_mapping::unmap() -> void @@ -70,9 +99,31 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - // TODO: scan pages - // TODO: remove mapping - // TODO: release temporary table frames + auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml2 = pml3->next(pml_index<3>(m_page)).value(); + auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } + + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } + + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } + m_mapped = false; } |
