From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Sun, 10 Dec 2023 10:34:07 +0000 (+0100)
Subject: Simplified the page mapping editing function, and genericised it
X-Git-Url: https://git.ameliathe1st.gay/?a=commitdiff_plain;h=693e533cf72eaf6cd41769fc76561b412328adae;p=voyage-au-centre-des-fichiers.git

Simplified the page mapping editing function, and genericised it
---

diff --git a/kernel/src/boot.S b/kernel/src/boot.S
index f9adf20..279767a 100644
--- a/kernel/src/boot.S
+++ b/kernel/src/boot.S
@@ -201,10 +201,11 @@ _start:
 	or $1 << 7, %eax # PGE
 	mov %eax, %cr4
 
-	# Set long mode bit:
+	# Set long mode bit (and NXE):
 	mov $0xC0000080, %ecx
 	rdmsr
 	or $1 << 8, %eax
+	or $1 << 11, %eax
 	wrmsr
 	# Enable paging:
 	mov %cr0, %eax
diff --git a/kernel/src/elf64.cpp b/kernel/src/elf64.cpp
index 88fbf29..d5acce1 100644
--- a/kernel/src/elf64.cpp
+++ b/kernel/src/elf64.cpp
@@ -73,9 +73,11 @@ void os::elf::load_elf(os::process& result, std::byte* start, std::size_t length
 		// Allocate, map and initialise memory for segment (memory above program_header.p_filesz is already 0-initialised by the page allocator):
 		std::size_t nb_pages = (std::uint64_t(program_header.p_vaddr) % 0x1000 + program_header.p_memsz + 0x1000 - 1) / 0x1000;
 		for (std::size_t i = 0; i < nb_pages; i++) {
-			std::byte* const page =
-				os::paging::setup_page(*result.PML4T, program_header.p_vaddr + i * 0x1000, (program_header.flags & 2) >> 1, 1);
-			memcpy(page, start + program_header.p_offset, clamp(0ul, program_header.p_filesz - i * 0x1000, 0x1000ul));
+			auto const alloc = os::paging::page_allocator.allocate(1);
+			os::assert(alloc.ptr != nullptr, "Failed to allocate enough memory for loading of elf binary.");
+			os::paging::map_page(*result.PML4T, (os::paging::page<0>*)(program_header.p_vaddr + i * 0x1000), alloc.ptr,
+				{.R_W = (program_header.flags & 2) >> 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 1 - (program_header.flags & 1)});
+			memcpy((void*)alloc.ptr, start + program_header.p_offset, clamp(0ul, program_header.p_filesz - i * 0x1000, 0x1000ul));
 		}
 	}
 }
diff --git a/kernel/src/interrupts.cpp b/kernel/src/interrupts.cpp
index 477431f..0af446a 100644
--- a/kernel/src/interrupts.cpp
+++ b/kernel/src/interrupts.cpp
@@ -111,13 +111,19 @@ extern "C" void int_page_fault(std::uint32_t err_code, std::uint64_t vaddr) {
 		(0xFFFF'C000'0000'0000 <= vaddr && vaddr < 0xFFFF'C000'1000'0000) // process/port info
 	) { // Kernel memory
 		os::print("Allocating (Ring 0): {}\n", (void*)vaddr);
-		os::paging::setup_page(os::paging::global_PML4T, (void*)vaddr, true, false);
+		auto const alloc = os::paging::page_allocator.allocate(1);
+		os::assert(alloc.ptr != nullptr, "Out of memory.");
+		os::paging::map_page(os::paging::global_PML4T, (os::paging::page<0>*)vaddr, alloc.ptr,
+			{.R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .PAT = 0, .G = 1, .base_address = 0, .NX = 1});
 		return;
 	} else if (
 		(0x0000'7FFF'FFFF'0000 <= vaddr && vaddr < 0x0000'8000'0000'0000) // stack
 	) { // Userspace memory
 		os::print("Allocating (Ring 3): {}\n", (void*)vaddr);
-		os::paging::setup_page(*os::get_process(os::current_pid).PML4T, (void*)vaddr, true, true);
+		auto const alloc = os::paging::page_allocator.allocate(1);
+		os::assert(alloc.ptr != nullptr, "Out of memory.");
+		os::paging::map_page(*os::get_process(os::current_pid).PML4T, (os::paging::page<0>*)vaddr, alloc.ptr,
+			{.R_W = 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 1});
 		return;
 	}
 	os::print("Interrupt: Page Fault.\n");
diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp
index 5093a0d..9babbd5 100644
--- a/kernel/src/kernel.cpp
+++ b/kernel/src/kernel.cpp
@@ -28,13 +28,17 @@ os::paging::page<0> bootstrap_pages_for_memory[32]; // 32 pages = 128 KiB
 
 extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
 	os::assert(magic == 0x36D76289, "Incorrect magic number: wasn't booted with multiboot2.");
+
+	os::paging::page_allocator.deallocate({
+		.ptr = os::phys_ptr<os::paging::page<0>>(reinterpret_cast<uintptr_t>(bootstrap_pages_for_memory) - 0xFFFF'FFFF'8000'0000),
+		.size = sizeof(bootstrap_pages_for_memory) / sizeof(bootstrap_pages_for_memory[0])
+	});
+
 	os::assert(os::cpu_has_msr(), "MSRs aren't supported.");
 	// TODO: Initialise new PML4T
 	os::paging::global_PML4T = old_PML4T;
 	// /TODO
-	os::print("a\n");
 	os::paging::load_pml4t(os::phys_ptr<os::paging::PML4T>{std::uintptr_t(&os::paging::global_PML4T) - 0xFFFF'FFFF'8000'0000});
-	os::print("b\n");
 
 	if (!os::init_serial_port()) {
 		while (true) {
@@ -42,11 +46,6 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 		}
 	}
 
-	os::paging::page_allocator.deallocate({
-		.ptr = os::phys_ptr<os::paging::page<0>>(reinterpret_cast<uintptr_t>(bootstrap_pages_for_memory) - 0xFFFF'FFFF'8000'0000),
-		.size = sizeof(bootstrap_pages_for_memory) / sizeof(bootstrap_pages_for_memory[0])
-	});
-
 	{ // Enable interrupts really early so I don't have to manually manage memory... Will make better later, when I make utils.hpp/incrementing_int64_map better.
 		os::isr_info isr_info[32];
 		for (size_t i = 0; i < sizeof(isr_info) / sizeof(isr_info[0]); i++) {
@@ -91,7 +90,7 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 	// TODO: Not an emergency, but adapt in case we need multiple PML4Es. (*NOT* the case right now.)
 	static_assert(sizeof(os::processes) <= 1024 * 1024 * 1024, "Error: processes array too big.");
 	{
-		const auto index = os::paging::calc_page_table_indices(&os::processes).pml4e;
+		std::size_t const index = (std::uint64_t(&os::processes) >> (12 + 9 * 3)) & 0x1FF;
 		os::paging::global_PML4T.contents[index] = {.non_page = {.P = 1, .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
 		const auto PDPT_alloc = os::paging::page_allocator.allocate(1);
 		os::memset((void*)PDPT_alloc.ptr, 0, 0x1000);
diff --git a/kernel/src/paging.cpp b/kernel/src/paging.cpp
index 2d44735..845e69a 100644
--- a/kernel/src/paging.cpp
+++ b/kernel/src/paging.cpp
@@ -16,45 +16,6 @@
 
 os::paging::PML4T os::paging::global_PML4T;
 
-std::byte* os::paging::setup_page(os::paging::PML4T& PML4T, const void* vaddr, bool R_W, bool U_S) {
-	const auto indices = os::paging::calc_page_table_indices(vaddr);
-	if (PML4T.contents[indices.pml4e].non_page.P == 0) {
-		PML4T.contents[indices.pml4e] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
-		const auto PDPT_alloc = os::paging::page_allocator.allocate(1);
-		memset((void*)PDPT_alloc.ptr, 0, 0x1000);
-		set_base_address(PML4T.contents[indices.pml4e], os::phys_ptr<os::paging::PDPT>(PDPT_alloc.ptr.get_phys_addr()));
-	}
-	os::paging::PDPT& PDPT = *get_base_address(PML4T.contents[indices.pml4e]);
-	if (PDPT.contents[indices.pdpe].non_page.P == 0) {
-		PDPT.contents[indices.pdpe] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
-		const auto PDT_alloc = os::paging::page_allocator.allocate(1);
-		memset((void*)PDT_alloc.ptr, 0, 0x1000);
-		set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr<os::paging::PDT>(PDT_alloc.ptr.get_phys_addr()));
-	} else {
-		assert(PDPT.contents[indices.pdpe].non_page.zero == 0,
-			"Cannot map memory address 0x{} because it is inside a 1GiB page", std::uintptr_t(vaddr));
-	}
-	os::paging::PDT& PDT = *get_base_address(PDPT.contents[indices.pdpe]);
-	if (PDT.contents[indices.pde].non_page.P == 0) {
-		PDT.contents[indices.pde] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
-		const auto PT_alloc = os::paging::page_allocator.allocate(1);
-		memset((void*)PT_alloc.ptr, 0, 0x1000);
-		set_base_address(PDT.contents[indices.pde], os::phys_ptr<os::paging::PT>(PT_alloc.ptr.get_phys_addr()));
-	} else {
-		assert(PDT.contents[indices.pde].non_page.zero == 0,
-			"Cannot map memory address 0x{} because it is inside a 2MiB page", std::uintptr_t(vaddr));
-	}
-	os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]);
-	os::assert(PT.contents[indices.pe].page.P == 0, "Memory at address 0x{} has already been mapped.", std::uintptr_t(vaddr));
-	PT.contents[indices.pe] =
-		{.page = {.P = 1, .R_W = R_W, .U_S = U_S, .PWT = 0, .PCD = 0, .PAT = 0, .G = (indices.pml4e < 128) ? 0ul : 1ul, .base_address = 0, .NX = 0}};
-	const auto page_alloc = os::paging::page_allocator.allocate(1);
-	memset((void*)page_alloc.ptr, 0, 0x1000);
-	set_page_base_address(PT.contents[indices.pe], os::phys_ptr<os::paging::page<0>>(page_alloc.ptr.get_phys_addr()));
-	invlpg(vaddr);
-	return (std::byte*)&*page_alloc.ptr;
-}
-
 namespace {
 void on_all_pages(const os::paging::PT& PT, void f(os::paging::page<0>*, os::phys_ptr<os::paging::page<0>>, std::size_t), std::size_t PT_virt_address) {
 	for (std::size_t i = 0; i < 512; i++) {
diff --git a/kernel/src/paging.hpp b/kernel/src/paging.hpp
index eb1696f..09ba64e 100644
--- a/kernel/src/paging.hpp
+++ b/kernel/src/paging.hpp
@@ -195,22 +195,8 @@ template <size_t depth> void set_page_base_address(paging_entry<depth>& entry, p
 	entry.page.base_address = ptr.get_phys_addr() / sizeof(page<depth>);
 }
 
-struct page_table_indices {
-	std::uint16_t pml4e;
-	std::uint16_t pdpe;
-	std::uint16_t pde;
-	std::uint16_t pe;
-};
-constexpr page_table_indices calc_page_table_indices(const void* ptr) {
-	return {
-		.pml4e = std::uint16_t((std::uint64_t(ptr) >> 39) & 0x1FF),
-		.pdpe  = std::uint16_t((std::uint64_t(ptr) >> 30) & 0x1FF),
-		.pde   = std::uint16_t((std::uint64_t(ptr) >> 21) & 0x1FF),
-		.pe    = std::uint16_t((std::uint64_t(ptr) >> 12) & 0x1FF),
-	};
-}
-
-std::byte* setup_page(PML4T& PML4T, const void* vaddr, bool R_W, bool U_S);
+template <std::size_t depth, std::size_t paging_depth = 3>
+void map_page(paging_table<paging_depth>& paging_table, page<depth> const* vaddr, phys_ptr<page<depth>> phys_addr, decltype(paging_entry<depth>::page) page_info);
 
 // For all present page mappings, calls f(virtual address, physical address, page size in bytes (4KiB, 2MiB or 1GiB)).
 void on_all_pages(const PML4T& PML4T, void f(page<0>*, phys_ptr<page<0>>, std::size_t));
@@ -245,4 +231,27 @@ private:
 	bool merge(phys_ptr<page> it);
 };
 
+template <std::size_t depth, std::size_t paging_depth = 3>
+void map_page(paging_table<paging_depth>& paging_table, page<depth> const* vaddr, phys_ptr<page<depth>> phys_addr, decltype(paging_entry<depth>::page) page_info) {
+	std::size_t const index = (std::uint64_t(vaddr) >> (12 + 9 * paging_depth)) & 0x1FF;
+	if constexpr (depth == paging_depth) {
+		os::assert(paging_table.contents[index].page.P == 0, "Virtual address 0x{} is already mapped.", vaddr);
+		paging_table.contents[index].page = page_info;
+		paging_table.contents[index].page.P = 1;
+		set_page_base_address(paging_table.contents[index], phys_addr);
+		invlpg(vaddr);
+	} else {
+		if (paging_table.contents[index].non_page.P == 1) {
+			assert(!is_page(paging_table.contents[index]), "Virtual address 0x{} is already in a mapped page.", vaddr);
+		} else {
+			auto const alloc = page_allocator.allocate(1);
+			assert(alloc.ptr != nullptr, "Not enough RAM to create the paging structures.");
+			memset((void*)alloc.ptr, 0, 0x1000);
+			paging_table.contents[index].non_page = {.P = 1, .R_W = 1, .U_S = page_info.U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0};
+			set_base_address(paging_table.contents[index], os::phys_ptr<os::paging::paging_table<paging_depth - 1>>{alloc.ptr.get_phys_addr()});
+		}
+		map_page<depth, paging_depth - 1>(*get_base_address(paging_table.contents[index]), vaddr, phys_addr, page_info);
+	}
+}
+
 } } // namespace os::paging