#include "kapi/memory.hpp" #include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" #include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/buffered_allocator.hpp" #include "x86_64/memory/kernel_mapper.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 "x86_64/memory/region_allocator.hpp" #include "x86_64/memory/scoped_mapping.hpp" #include #include #include #include namespace teachos::memory { namespace { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; //! Instantiate a basic, memory region based, early frame allocator for remapping. auto create_early_frame_allocator() { auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map(); if (!memory_map) { system::panic("[x86_64] Failed to create early allocator, no memory map available."); } auto const & mbi = boot::bootstrap_information.mbi; auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; return x86_64::region_allocator{ { .image_range = std::make_pair(physical_address{&image_span.front()}, physical_address{&image_span.back()}), .mbi_range = std::make_pair(physical_address{&mbi_span.front()}, physical_address{&mbi_span.back()}), .memory_map = *memory_map, } }; } //! Enable additional CPU protection features, required during later stages of the kernel. auto enable_cpu_protections() -> void { cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); cpu::x86_64::i32_efer::set(cpu::x86_64::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) { using namespace x86_64; using entry_flags = page_table::entry::flags; auto page = page::containing(unused_page_address); auto temporary_mapper = scoped_mapping{page, allocator}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as(*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); 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; } } // namespace auto active_allocator() -> frame_allocator & { if (!allocator) { system::panic("[x86_64] The frame allocator has not been set yet."); } return *allocator; } auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; if (is_initialized.test_and_set()) { system::panic("[x86_64] Memory management has already been initialized."); } auto allocator = create_early_frame_allocator(); enable_cpu_protections(); auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; auto new_pml4_frame = inject_faux_pml4(allocation_buffer); auto mapper = x86_64::kernel_mapper{allocation_buffer, boot::bootstrap_information.mbi}; mapper.remap_kernel(); cio::println("[x86_64:MEM] prepared new kernel image page maps."); auto cr3 = cpu::x86_64::cr3::read(); cr3.address(new_pml4_frame.start_address()); cpu::x86_64::cr3::write(cr3); // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); // video::vga::text::newline(); } } // namespace teachos::memory