aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2025-12-02 18:40:10 +0100
committerFelix Morgner <felix.morgner@ost.ch>2025-12-02 18:40:10 +0100
commita96b1b4b43a1ed962b412c3d28db0fe00661d96f (patch)
treeddc7e9dcc9814b07c2ff36d4875a0fe2ae13a665
parentbe86be1facfce8fe3f376153b9c582f2c5c026aa (diff)
downloadteachos-a96b1b4b43a1ed962b412c3d28db0fe00661d96f.tar.xz
teachos-a96b1b4b43a1ed962b412c3d28db0fe00661d96f.zip
x86_64/memory: extract PML4 injection
-rw-r--r--arch/x86_64/include/x86_64/memory/page_table.hpp3
-rw-r--r--arch/x86_64/include/x86_64/memory/scoped_mapping.hpp4
-rw-r--r--arch/x86_64/src/kapi/memory.cpp79
-rw-r--r--arch/x86_64/src/memory/page_table.cpp6
-rw-r--r--arch/x86_64/src/memory/paging_root.cpp18
-rw-r--r--arch/x86_64/src/memory/scoped_mapping.cpp77
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;
}