From cf71eed83e0ba435c9bc4f8d29b4293a0f152adf Mon Sep 17 00:00:00 2001
From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Mon, 11 Dec 2023 23:21:53 +0100
Subject: [PATCH] Added setup of the new and improved memory map

---
 kernel/linker.ld      |   2 +-
 kernel/src/kernel.cpp | 142 +++++++++++++++++++++++++++++++-----------
 2 files changed, 105 insertions(+), 39 deletions(-)

diff --git a/kernel/linker.ld b/kernel/linker.ld
index b3fa2b6..a240be3 100644
--- a/kernel/linker.ld
+++ b/kernel/linker.ld
@@ -45,7 +45,7 @@ SECTIONS {
 		*(.eh_frame)
 	}
 	. = ALIGN(4K);
-	_kernel_rw_start = . - KERNEL_VMA;
+	_kernel_phys_rw_start = . - KERNEL_VMA;
 	.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VMA) {
 		*(.data)
 		*(.data*)
diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp
index f2624b6..e37a9a4 100644
--- a/kernel/src/kernel.cpp
+++ b/kernel/src/kernel.cpp
@@ -23,10 +23,18 @@ os::idt<32> idt;
 extern "C" os::tss TSS;
 extern "C" char interrupt_stack_top;
 extern "C" os::paging::PML4T old_PML4T;
+char _kernel_phys_start;
+char _kernel_phys_rw_start;
+char _kernel_phys_end;
 
-os::paging::page<0> bootstrap_pages_for_memory[32]; // 32 pages = 128 KiB
+os::paging::page<0> bootstrap_pages_for_memory[256]; // 256 pages = 1MiB
 
 extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
+	if (!os::init_serial_port()) {
+		while (true) {
+			os::hlt();
+		}
+	}
 	os::assert(magic == 0x36D76289, "Incorrect magic number: wasn't booted with multiboot2.");
 
 	os::paging::page_allocator.deallocate({
@@ -35,21 +43,87 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 	});
 
 	os::assert(os::cpu_has_msr(), "MSRs aren't supported.");
-	// TODO: Initialise new PML4T
-	os::paging::global_PML4T = old_PML4T;
-	// /TODO
-	os::paging::load_pml4t(os::phys_ptr<os::paging::PML4T>{std::uintptr_t(&os::paging::global_PML4T) - 0xFFFF'FFFF'8000'0000});
-	os::print("Begin MMAP print.\n");
-	os::paging::on_all_pages(os::paging::global_PML4T, []<std::size_t depth>(os::paging::page<depth>* vaddr, os::phys_ptr<os::paging::page<depth>> paddr) {
-		os::print("{} -> {} ({})\n", vaddr, (void*)paddr.get_phys_addr(), depth);
-	});
-	os::print("End MMAP print.\n");
-
-	if (!os::init_serial_port()) {
-		while (true) {
-			os::hlt();
+	// Initialise kernel map.
+	os::assert(std::size_t(&_kernel_phys_start) % 4096 == 0, "Kernel isn't page aligned !");
+	os::assert(std::size_t(&_kernel_phys_rw_start) % 4096 == 0, "Kernel isn't page aligned !");
+	os::assert(std::size_t(&_kernel_phys_end) % 4096 == 0, "Kernel isn't page aligned !");
+	for (std::size_t i = std::size_t(&_kernel_phys_start); i < std::size_t(&_kernel_phys_rw_start); ) {
+		if (i % (1024 * 1024 * 1024) == 0 && i + 1024 * 1024 * 1024 < std::size_t(&_kernel_phys_rw_start)) {
+			os::paging::map_page<2, 3>(os::paging::global_PML4T, (os::paging::page<2>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<2>>(i),
+				{ .R_W = 0, .U_S = 0, .PWT = 0, .PCD = 0, .G = 1, .PAT = 0, .base_address = 0, .AVL_or_MPK = 0, .NX = 0 });
+			i += 1024 * 1024 * 1024;
+		} else if (i % (1024 * 1024 * 2) == 0 && i + 1024 * 1024 * 2 < std::size_t(&_kernel_phys_rw_start)) {
+			os::paging::map_page<1, 3>(os::paging::global_PML4T, (os::paging::page<1>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<1>>(i),
+				{ .R_W = 0, .U_S = 0, .PWT = 0, .PCD = 0, .G = 1, .PAT = 0, .base_address = 0, .NX = 0 });
+			i += 1024 * 1024 * 2;
+		} else {
+			os::paging::map_page<0, 3>(os::paging::global_PML4T, (os::paging::page<0>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<0>>(i),
+				{ .R_W = 0, .U_S = 0, .PWT = 0, .PCD = 0, .PAT = 0, .G = 1, .base_address = 0, .NX = 0 });
+			i += 1024 * 4;
 		}
 	}
+	for (std::size_t i = std::size_t(&_kernel_phys_rw_start); i < std::size_t(&_kernel_phys_end); ) {
+		if (i % (1024 * 1024 * 1024) == 0 && i + 1024 * 1024 * 1024 < std::size_t(&_kernel_phys_rw_start)) {
+			os::paging::map_page<2, 3>(os::paging::global_PML4T, (os::paging::page<2>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<2>>(i),
+				{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .G = 1, .PAT = 0, .base_address = 0, .AVL_or_MPK = 0, .NX = 1 });
+			i += 1024 * 1024 * 1024;
+		} else if (i % (1024 * 1024 * 2) == 0 && i + 1024 * 1024 * 2 < std::size_t(&_kernel_phys_rw_start)) {
+			os::paging::map_page<1, 3>(os::paging::global_PML4T, (os::paging::page<1>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<1>>(i),
+				{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .G = 1, .PAT = 0, .base_address = 0, .NX = 1 });
+			i += 1024 * 1024 * 2;
+		} else {
+			os::paging::map_page<0, 3>(os::paging::global_PML4T, (os::paging::page<0>*)(0xFFFF'FFFF'8000'0000 + i), os::phys_ptr<os::paging::page<0>>(i),
+				{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .PAT = 0, .G = 1, .base_address = 0, .NX = 1 });
+			i += 1024 * 4;
+		}
+	}
+	// Initialise physical memory map.
+	for (auto it = multiboot2::next(info); it->type != multiboot2::info::type_t::end; it = multiboot2::next(it)) {
+		switch (it->type) {
+		case multiboot2::info::type_t::memory_map:
+			os::print("RAM:\n");
+			for (std::size_t i = 0; i < multiboot2::memory_map_number_of_entries(it); i++) {
+				std::size_t const s = multiboot2::memory_map_base_addr(it, i);
+				std::size_t const e = s + multiboot2::memory_map_length(it, i);
+				os::print("{} -> {} : {}\n", (void*)s, (void*)e, multiboot2::memory_map_type(it, i));
+				if (multiboot2::memory_map_type(it, i) != 1) {
+					continue;
+				}
+				if (e <= 1024 * 1024) { // I'll ignore lower memory for now.
+					continue;
+				}
+				os::assert(s % 0x1000 == 0, "Memory map unaligned on page boundaries.");
+				os::assert(e % 0x1000 == 0, "Memory map unaligned on page boundaries.");
+				for (std::size_t j = s; j < e; ) {
+					if (j % (1024 * 1024 * 1024) == 0 && j + 1024 * 1024 * 1024 < e) {
+						os::paging::map_page<2, 3>(
+							os::paging::global_PML4T,
+							(os::paging::page<2>*)(0xFFFF'8000'0000'0000 + j),
+							os::phys_ptr<os::paging::page<2>>(j),
+							{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .G = 1, .PAT = 0, .base_address = 0, .AVL_or_MPK = 0, .NX = 1 });
+						j += 1024 * 1024 * 1024;
+					} else if (j % (1024 * 1024 * 2) == 0 && j + 1024 * 1024 * 2 < e) {
+						os::paging::map_page<1, 3>(os::paging::global_PML4T,
+							(os::paging::page<1>*)(0xFFFF'8000'0000'0000 + j),
+							os::phys_ptr<os::paging::page<1>>(j),
+							{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .G = 1, .PAT = 0, .base_address = 0, .NX = 1 });
+						j += 1024 * 1024 * 2;
+					} else {
+						os::paging::map_page<0, 3>(os::paging::global_PML4T,
+							(os::paging::page<0>*)(0xFFFF'8000'0000'0000 + j),
+							os::phys_ptr<os::paging::page<0>>(j),
+							{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .PAT = 0, .G = 1, .base_address = 0, .NX = 1 });
+						j += 1024 * 4;
+					}
+				}
+			}
+			os::print("RAM END\n");
+			break;
+		default: break;
+		}
+	}
+	// /TODO
+	os::paging::load_pml4t(os::phys_ptr<os::paging::PML4T>{std::uintptr_t(&os::paging::global_PML4T) - 0xFFFF'FFFF'8000'0000});
 
 	{ // 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];
@@ -88,6 +162,11 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 		asm ("movq $handler_0x1d,%0" : "=ri"(isr_info[0x1d].addr) : );
 		asm ("movq $handler_0x1e,%0" : "=ri"(isr_info[0x1e].addr) : );
 		asm ("movq $handler_0x1f,%0" : "=ri"(isr_info[0x1f].addr) : );
+		// Map local APIC in.
+		os::paging::map_page<0, 3>(os::paging::global_PML4T,
+			(os::paging::page<0>*)(0xFFFF'8000'fee0'0000),
+			os::phys_ptr<os::paging::page<0>>(0x0000'0000'fee0'0000),
+			{ .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 1, .PAT = 0, .G = 1, .base_address = 0, .NX = 1 });
 		os::enable_interrupts(isr_info, idt);
 	}
 
@@ -119,23 +198,18 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 				);
 				break;
 			case multiboot2::info::type_t::memory_map:
-				os::print("RAM:\n");
 				for (std::size_t i = 0; i < multiboot2::memory_map_number_of_entries(it); i++) {
-					if (multiboot2::memory_map_type(it, i) == 1) {
-						// Rounded up, to avoid including non-ram.
-						const os::phys_ptr<os::paging::page<0>>
-							s{(multiboot2::memory_map_base_addr(it, i) + 0x1000 - 1) / 0x1000 * 0x1000};
-						// Rounded down, to avoid including non-ram.
-						const os::phys_ptr<os::paging::page<0>>
-							e{(multiboot2::memory_map_base_addr(it, i) + multiboot2::memory_map_length(it, i)) / 0x1000 * 0x1000 - 0x1000};
-						if (s <= e) { // In the case where no full page is included in the ram section, don't add it.
-							os::assert(available_ram_length < 50, "Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
-							available_ram[available_ram_length++] = {.start_address = s, .end_address = e};
-							os::print("{} -> {} ({})\n", s, e + 1, (unsigned long)(e + 1 - s));
-						}
+					if (multiboot2::memory_map_type(it, i) != 1) {
+						continue;
+					}
+					const os::phys_ptr<os::paging::page<0>> s{multiboot2::memory_map_base_addr(it, i)};
+					const os::phys_ptr<os::paging::page<0>> e{s + multiboot2::memory_map_length(it, i) / 0x1000};
+					if (e.get_phys_addr() <= 1024 * 1024) { // I'll ignore lower memory for now.
+						continue;
 					}
+					os::assert(available_ram_length < 50, "Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
+					available_ram[available_ram_length++] = {.start_address = s, .end_address = e};
 				}
-				os::print("RAM END\n");
 				break;
 			case multiboot2::info::type_t::modules:
 				os::print("{}->{}: {}\n", multiboot2::modules_mod_start(it), multiboot2::modules_mod_end(it), multiboot2::modules_string(it));
@@ -152,16 +226,8 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 		os::assert(module_specified, "No modules specified in the multiboot. This is unsupported.");
 
 		// kernel_start and kernel_end are aligned to 4K by the linker script.
-		const os::phys_ptr<os::paging::page<0>> kernel_s = ([]() {
-			os::phys_ptr<os::paging::page<0>> ptr = nullptr;
-			asm("mov $_kernel_phys_start,%0" : "=ri"(ptr));
-			return ptr;
-		})();
-		const os::phys_ptr<os::paging::page<0>> kernel_e = ([]() {
-			os::phys_ptr<os::paging::page<0>> ptr = nullptr;
-			asm("mov $_kernel_phys_end,%0" : "=ri"(ptr));
-			return ptr - 1; // [s, e], not [s, e[
-		})();
+		const os::phys_ptr<os::paging::page<0>> kernel_s{std::size_t(&_kernel_phys_start)};
+		const os::phys_ptr<os::paging::page<0>> kernel_e{std::size_t(&_kernel_phys_end)};
 
 		// Remove kernel from available RAM:
 		for (std::size_t i = 0; i < available_ram_length; i++) {
-- 
2.46.0