aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/CMakeLists.txt2
-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.hpp11
-rw-r--r--arch/x86_64/include/arch/memory/paging/active_page_table.hpp102
-rw-r--r--arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp95
-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.hpp8
-rw-r--r--arch/x86_64/src/exception_handling/pure_virtual.cpp6
-rw-r--r--arch/x86_64/src/kernel/main.cpp1
-rw-r--r--arch/x86_64/src/memory/allocator/area_frame_allocator.cpp2
-rw-r--r--arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp4
-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
-rw-r--r--cmake/Platforms/x86_64.cmake2
18 files changed, 258 insertions, 237 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt
index f868b4e..7f3a203 100644
--- a/arch/x86_64/CMakeLists.txt
+++ b/arch/x86_64/CMakeLists.txt
@@ -52,6 +52,7 @@ 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"
@@ -65,6 +66,7 @@ target_sources("_exception" PRIVATE
"src/exception_handling/assert.cpp"
"src/exception_handling/abort.cpp"
"src/exception_handling/panic.cpp"
+ "src/exception_handling/pure_virtual.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 f2b77f8..f1a3a64 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,6 +1,7 @@
#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"
@@ -11,7 +12,7 @@ namespace teachos::arch::memory::allocator
/**
* @brief Allocates memory using memory areas read from the multiboot2 information pointer.
*/
- struct area_frame_allocator
+ struct area_frame_allocator : frame_allocator
{
/**
* @brief Constructor
@@ -32,7 +33,7 @@ namespace teachos::arch::memory::allocator
*
* @return next free physical frame or nullopt if none was found.
*/
- auto allocate_frame() -> std::optional<physical_frame>;
+ auto allocate_frame() -> std::optional<physical_frame> override;
/**
* @brief Deallocates a previously allocated physical frame.
@@ -43,7 +44,7 @@ namespace teachos::arch::memory::allocator
*
* @param physical_frame Previously allocated physical_frame that should be deallocated.
*/
- auto deallocate_frame(physical_frame physical_frame) -> void;
+ auto deallocate_frame(physical_frame const & physical_frame) -> void override;
private:
/**
diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp
deleted file mode 100644
index 4a7ab72..0000000
--- a/arch/x86_64/include/arch/memory/allocator/concept.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 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
new file mode 100644
index 0000000..9316ca9
--- /dev/null
+++ b/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp
@@ -0,0 +1,19 @@
+#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 a96b743..c449ac8 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,8 +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/area_frame_allocator.hpp"
-#include "arch/memory/allocator/concept.hpp"
+#include "arch/memory/allocator/frame_allocator.hpp"
#include "arch/memory/allocator/physical_frame.hpp"
#include <array>
@@ -17,7 +16,7 @@ namespace teachos::arch::memory::allocator
/**
* @brief Allocates memory using memory areas read from the multiboot2 information pointer.
*/
- struct tiny_frame_allocator
+ struct tiny_frame_allocator : frame_allocator
{
/**
* @brief Constructor.
@@ -27,7 +26,7 @@ namespace teachos::arch::memory::allocator
* @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate
* entries *when a new page table is required.
*/
- tiny_frame_allocator(area_frame_allocator & allocator);
+ tiny_frame_allocator(frame_allocator & allocator);
/**
* @brief Allocate memory by finding and returning one of the three free physical frames.
@@ -35,7 +34,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>;
+ auto allocate_frame() -> std::optional<physical_frame> override;
/**
* @brief Deallocates one of the three previously allocated physical frames.
@@ -45,7 +44,7 @@ namespace teachos::arch::memory::allocator
*
* @param physical_frame Previously allocated physical_frame that should be deallocated.
*/
- auto deallocate_frame(physical_frame physical_frame) -> void;
+ auto deallocate_frame(physical_frame const & physical_frame) -> void override;
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 a60b3ad..e558fa5 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,12 +1,13 @@
#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP
#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP
-#include "arch/exception_handling/assert.hpp"
-#include "arch/memory/allocator/concept.hpp"
-#include "arch/memory/cpu/tlb.hpp"
+#include "arch/memory/allocator/frame_allocator.hpp"
+#include "arch/memory/allocator/physical_frame.hpp"
+#include "arch/memory/paging/page_table.hpp"
#include "arch/memory/paging/virtual_page.hpp"
#include <array>
+#include <bitset>
#include <optional>
namespace teachos::arch::memory::paging
@@ -65,44 +66,21 @@ 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.
*/
- 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);
- }
-
+ auto map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, allocator::physical_frame frame,
+ std::bitset<64U> flags) -> void;
/**
* @brief Allocates the next free frame and then uses that frame to call map_page_to_frame.
*
* @see map_page_to_frame
*/
- 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);
- }
+ auto map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page,
+ std::bitset<64U> flags) -> void;
/**
* @brief Gets the corresponding page the given frame has to be contained in and uses that to call
@@ -110,12 +88,8 @@ namespace teachos::arch::memory::paging
*
* @see map_page_to_frame
*/
- 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);
- }
+ auto identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame,
+ std::bitset<64U> flags) -> void;
/**
* @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags.
@@ -129,46 +103,7 @@ namespace teachos::arch::memory::paging
* entries when a new page table is required.
* @param page Virtual page that is being unmapped.
*/
- 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;
- std::array<page_table_handle, 3U> handles{current_handle, current_handle, current_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();
- // The level is used as the index, because it ensures the first level is the lowest one and then the remaining
- // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check
- // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2
- // page is empty and clear the Level 3 page entry and so on.
- handles.at(level - 1U) = current_handle;
- }
-
- // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the
- // last one. We check if it was the last one using is empty on the page table handle, when we have removed the
- // page to be unmapped.
- for (auto & handle : handles)
- {
- unmap_page_table_entry(allocator, page, handle);
- if (!handle.is_empty())
- {
- break;
- }
- }
- // Uses flush all instead of cpu::tlb_flush(page.start_address());, because when we unmap the active page and
- // only flush one page, the rest of the page which is huge still exist in the cache and
- // can therefore still be accessed. But because they are huge pages the new mapping can not be accessed correctly.
- cpu::tlb_flush_all();
- }
+ auto unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void;
private:
/**
@@ -192,24 +127,13 @@ 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.
*/
- 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());
- }
+ static auto unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page,
+ page_table_handle & handle) -> void;
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 bcc3eba..2f55a13 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/cpu/control_register.hpp"
+#include "arch/memory/allocator/frame_allocator.hpp"
+#include "arch/memory/multiboot/reader.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,7 +14,6 @@ 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
{
/**
@@ -23,12 +22,7 @@ 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(T & allocator, multiboot::memory_information const & mem_info)
- : allocator(allocator)
- , mem_info(mem_info)
- {
- // Nothing to do
- }
+ kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info);
/**
* @brief Remap the kernel, meaning we map the entire kernel and all of it's elf sections with the correct flags
@@ -38,21 +32,7 @@ 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 &
- {
- /*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(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 remap_kernel() -> active_page_table &;
private:
/**
@@ -63,8 +43,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
@@ -72,20 +52,8 @@ namespace teachos::arch::memory::paging
* @param active_table Active level 4 page table that has its recursive mapping overwritten temporarily and then
* restored once the process is finished.
*/
- auto remap_elf_kernel_sections(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 remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page,
+ active_page_table & active_table) -> void;
/**
* @brief Switches the current active table pointed to by the CR3 register with another page table that is currently
@@ -94,16 +62,7 @@ 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 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 switch_active_page_table(inactive_page_table new_table) -> inactive_page_table;
/**
* @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of
@@ -112,41 +71,9 @@ 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
- {
- 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);
- }
+ auto map_elf_kernel_sections(active_page_table & active_table) -> void;
- T & allocator;
+ allocator::frame_allocator & 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 7a15875..24ff8f4 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/concept.hpp"
+#include "arch/memory/allocator/frame_allocator.hpp"
#include "arch/memory/paging/page_entry.hpp"
namespace teachos::arch::memory::paging
@@ -82,26 +82,7 @@ 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.
*/
- 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();
- }
+ auto next_table_or_create(allocator::frame_allocator & allocator, std::size_t table_index) -> page_table_handle;
/**
* @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 a850879..3c4301a 100644
--- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp
+++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp
@@ -20,13 +20,7 @@ namespace teachos::arch::memory::paging
* @param page Page to turn into temporary page
* @param allocator Frame allocator used to fill page
*/
- template<allocator::FrameAllocator T>
- temporary_page(virtual_page page, T & allocator)
- : page{page}
- , allocator{allocator}
- {
- // Nothing to do
- }
+ temporary_page(virtual_page page, allocator::frame_allocator & allocator);
/**
* @brief Unmap the current page.
diff --git a/arch/x86_64/src/exception_handling/pure_virtual.cpp b/arch/x86_64/src/exception_handling/pure_virtual.cpp
new file mode 100644
index 0000000..67772f7
--- /dev/null
+++ b/arch/x86_64/src/exception_handling/pure_virtual.cpp
@@ -0,0 +1,6 @@
+#include "arch/exception_handling/panic.hpp"
+
+extern "C" auto __cxa_pure_virtual() -> void
+{
+ teachos::arch::exception_handling::panic("Runtime", "Tried to call a pure virtual function!");
+}
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp
index 5b0f2c3..8c68a49 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/src/kernel/main.cpp
@@ -2,6 +2,7 @@
#include "arch/exception_handling/assert.hpp"
#include "arch/memory/allocator/area_frame_allocator.hpp"
+#include "arch/memory/cpu/control_register.hpp"
#include "arch/memory/cpu/msr.hpp"
#include "arch/memory/multiboot/reader.hpp"
#include "arch/memory/paging/kernel_mapper.hpp"
diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
index 3bc9676..cb4fefa 100644
--- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
+++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp
@@ -81,5 +81,5 @@ namespace teachos::arch::memory::allocator
return allocate_frame();
}
- auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { (void)physical_frame; }
+ auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { (void)physical_frame; }
} // namespace teachos::arch::memory::allocator
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 d37864e..ed000a0 100644
--- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp
+++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp
@@ -4,7 +4,7 @@
namespace teachos::arch::memory::allocator
{
- tiny_frame_allocator::tiny_frame_allocator(area_frame_allocator & 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(),
@@ -34,7 +34,7 @@ namespace teachos::arch::memory::allocator
return std::nullopt;
}
- auto tiny_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void
+ auto tiny_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void
{
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 0113869..d2bf683 100644
--- a/arch/x86_64/src/memory/paging/active_page_table.cpp
+++ b/arch/x86_64/src/memory/paging/active_page_table.cpp
@@ -1,5 +1,7 @@
#include "arch/memory/paging/active_page_table.hpp"
+#include "arch/memory/cpu/tlb.hpp"
+
namespace teachos::arch::memory::paging
{
namespace
@@ -15,6 +17,71 @@ 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
new file mode 100644
index 0000000..f938cb3
--- /dev/null
+++ b/arch/x86_64/src/memory/paging/kerne