diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-01-16 13:36:38 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-01-16 13:36:38 +0100 |
| commit | 7d6f0ed063790042a808f4bf07c50d308b3f2de4 (patch) | |
| tree | 1a2e1c4ed7e2f3d8e6cdcfb012e554d1a4eb1e5a /arch/x86_64/kapi | |
| parent | 9750405757396d006ab6992fb93baf414b3e2ae8 (diff) | |
| download | teachos-7d6f0ed063790042a808f4bf07c50d308b3f2de4.tar.xz teachos-7d6f0ed063790042a808f4bf07c50d308b3f2de4.zip | |
chore: restructure namespaces
Diffstat (limited to 'arch/x86_64/kapi')
| -rw-r--r-- | arch/x86_64/kapi/cio.cpp | 20 | ||||
| -rw-r--r-- | arch/x86_64/kapi/cpu.cpp | 12 | ||||
| -rw-r--r-- | arch/x86_64/kapi/memory.cpp | 194 |
3 files changed, 226 insertions, 0 deletions
diff --git a/arch/x86_64/kapi/cio.cpp b/arch/x86_64/kapi/cio.cpp new file mode 100644 index 0000000..015cf5e --- /dev/null +++ b/arch/x86_64/kapi/cio.cpp @@ -0,0 +1,20 @@ +#include "kapi/cio.hpp" + +#include "arch/debug/qemu_output.hpp" +#include "arch/vga/text.hpp" + +#include <optional> + +namespace kapi::cio +{ + + auto static constinit vga_device = std::optional<arch::vga::text::device>{}; + auto static constinit dbg_device = std::optional<arch::debug::qemu_output>{}; + + auto init() -> void + { + vga_device.emplace().cursor(false); + set_output_device(dbg_device.emplace(*vga_device)); + } + +} // namespace kapi::cio diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp new file mode 100644 index 0000000..2a0f8f7 --- /dev/null +++ b/arch/x86_64/kapi/cpu.cpp @@ -0,0 +1,12 @@ +#include "kapi/cpu.hpp" + +namespace kapi::cpu +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace kapi::cpu diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp new file mode 100644 index 0000000..e366ee1 --- /dev/null +++ b/arch/x86_64/kapi/memory.cpp @@ -0,0 +1,194 @@ +#include "kapi/memory.hpp" + +#include "kapi/boot.hpp" +#include "kapi/system.hpp" + +#include "arch/boot/boot.hpp" +#include "arch/boot/ld.hpp" +#include "arch/cpu/registers.hpp" +#include "arch/memory/buffered_allocator.hpp" +#include "arch/memory/kernel_mapper.hpp" +#include "arch/memory/mmu.hpp" +#include "arch/memory/page_table.hpp" +#include "arch/memory/page_utilities.hpp" +#include "arch/memory/paging_root.hpp" +#include "arch/memory/recursive_page_mapper.hpp" +#include "arch/memory/region_allocator.hpp" +#include "arch/memory/scoped_mapping.hpp" + +#include <kstd/print> + +#include <multiboot2/information.hpp> + +#include <atomic> +#include <bit> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <optional> +#include <span> +#include <utility> + +namespace kapi::memory +{ + + namespace + { + constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; + constexpr auto static recursive_page_map_index = arch::memory::page_table::entry_count - 2; + + //! Instantiate a basic, memory region based, early frame allocator for remapping. + auto collect_memory_information() + { + 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<std::byte *>(mbi), mbi->size_bytes()}; + auto image_span = std::span{&arch::boot::_start_physical, &arch::boot::_end_physical}; + + return arch::memory::region_allocator::memory_information{ + .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 + { + arch::cpu::cr0::set(arch::cpu::cr0::flags::write_protect); + arch::cpu::i32_efer::set(arch::cpu::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, page_mapper & mapper) + { + using arch::memory::page_table; + using arch::memory::paging_root; + using arch::memory::pml_index; + using entry_flags = arch::memory::page_table::entry::flags; + + auto page = page::containing(unused_page_address); + + auto temporary_mapper = arch::memory::scoped_mapping{page, mapper}; + auto new_pml4_frame = allocator.allocate(); + + 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); + + 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); + + arch::memory::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; + } + + auto remap_kernel(page_mapper & mapper) -> void + { + auto kernel_mapper = arch::memory::kernel_mapper{boot::bootstrap_information.mbi}; + kernel_mapper.remap_kernel(mapper); + } + + auto remap_vga_text_mode_buffer(page_mapper & mapper) -> void + { + constexpr auto vga_base = std::uintptr_t{0xb8000}; + auto vga_physical_start = physical_address{vga_base}; + auto vga_virtual_start = linear_address{vga_base + std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}; + + auto page = page::containing(vga_virtual_start); + auto frame = frame::containing(vga_physical_start); + + mapper.map(page, frame, page_mapper::flags::writable); + } + + auto remap_multiboot_information(page_mapper & mapper) -> void + { + auto mbi_base = std::bit_cast<std::uintptr_t>(boot::bootstrap_information.mbi); + auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); + auto mbi_physical_start = physical_address{mbi_base & ~std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}; + auto mbi_virtual_start = linear_address{mbi_base}; + auto mbi_block_count = (mbi_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; + + for (auto i = 0uz; i < mbi_block_count; ++i) + { + auto page = page::containing(mbi_virtual_start) + i; + auto frame = frame::containing(mbi_physical_start) + i; + mapper.map(page, frame, page_mapper::flags::empty); + } + } + + auto constinit region_based_allocator = std::optional<arch::memory::region_allocator>{}; + auto constinit buffered_allocator = std::optional<arch::memory::buffered_allocator<4>>{}; + auto constinit recursive_page_mapper = std::optional<arch::memory::recursive_page_mapper>{}; + + } // namespace + + 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."); + } + + kstd::println("[x86_64:MEM] Enabling additional CPU protection features."); + + enable_cpu_protections(); + + region_based_allocator.emplace(collect_memory_information()); + buffered_allocator.emplace(&*region_based_allocator); + recursive_page_mapper.emplace(*buffered_allocator); + + kstd::println("[x86_64:MEM] Preparing new paging hierarchy."); + + auto new_pml4_frame = inject_faux_pml4(*buffered_allocator, *recursive_page_mapper); + + remap_kernel(*recursive_page_mapper); + remap_vga_text_mode_buffer(*recursive_page_mapper); + remap_multiboot_information(*recursive_page_mapper); + + kstd::println("[x86_64:MEM] Switching to new paging hierarchy."); + + auto cr3 = arch::cpu::cr3::read(); + cr3.frame(new_pml4_frame); + arch::cpu::cr3::write(cr3); + + set_frame_allocator(*buffered_allocator); + set_page_mapper(*recursive_page_mapper); + } + +} // namespace kapi::memory |
