aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/CMakeLists.txt1
-rw-r--r--arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp7
-rw-r--r--arch/x86_64/include/arch/memory/allocator/concept.hpp22
-rw-r--r--arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp19
-rw-r--r--arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp32
-rw-r--r--arch/x86_64/include/arch/memory/paging/active_page_table.hpp82
-rw-r--r--arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp94
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_table.hpp23
-rw-r--r--arch/x86_64/include/arch/memory/paging/temporary_page.hpp17
-rw-r--r--arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp16
-rw-r--r--arch/x86_64/src/memory/paging/active_page_table.cpp67
-rw-r--r--arch/x86_64/src/memory/paging/kernel_mapper.cpp94
-rw-r--r--arch/x86_64/src/memory/paging/page_table.cpp21
-rw-r--r--arch/x86_64/src/memory/paging/temporary_page.cpp9
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 =
- ++(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};