From 617e23517d703ea2151f9846006c5e126fc4eed3 Mon Sep 17 00:00:00 2001
From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Mon, 9 May 2022 00:48:36 +0200
Subject: [PATCH] Changed the rounding of usable RAM addresses and the freeing
 of the multiboot2 info struct to avoid accidentally marking unusable RAM as
 usable

---
 src/kernel.cpp | 42 ++++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/src/kernel.cpp b/src/kernel.cpp
index 5799f46..32ec362 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -49,8 +49,9 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 		asm("mov $_kernel_phys_end,%0" : "=ri"(ptr));
 		return ptr;
 	})();
-	const os::phys_ptr<os::paging::page> info_start{info.get_phys_addr()};
-	const os::phys_ptr<os::paging::page> info_end = info_start + (info->total_size - 1 + 0x1000) / 0x1000; // Number of pages taken, rounded up
+	const os::phys_ptr<os::paging::page> info_start{info.get_phys_addr() / 0x1000 * 0x1000}; // Round start down.
+	const os::phys_ptr<os::paging::page> info_end{(info.get_phys_addr() + info->total_size + 0x1000 - 1) / 0x1000 * 0x1000}; // Round end up.
+	bool info_pages_wholly_usable = false;
 
 	os::framebuffer framebuffer;
 
@@ -59,6 +60,11 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 	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::framebuffer_info:
+			os::print("Framebuffer:\n");
+			os::print(multiboot2::framebuffer_addr(it));
+			os::print("->");
+			os::print(multiboot2::framebuffer_addr(it) + multiboot2::framebuffer_pitch(it) * multiboot2::framebuffer_height(it));
+			os::printc('\n');
 			framebuffer = os::framebuffer(
 				multiboot2::framebuffer_addr(it),
 				multiboot2::framebuffer_pitch(it),
@@ -70,19 +76,14 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 			);
 			break;
 		case multiboot2::info::type_t::memory_map:
-			os::println("Memory map:");
 			for (std::size_t i = 0; i < multiboot2::memory_map_number_of_entries(it); i++) {
-				os::print(multiboot2::memory_map_base_addr(it, i));
-				os::print("->");
-				os::print(multiboot2::memory_map_base_addr(it, i) + multiboot2::memory_map_length(it, i));
-				os::printc(':');
-				os::printc('0' + multiboot2::memory_map_type(it, i));
-				os::printc('\n');
 				if (multiboot2::memory_map_type(it, i) == 1) {
-					const os::phys_ptr<os::paging::page> s{multiboot2::memory_map_base_addr(it, i) == 0 ? 0x1000 : multiboot2::memory_map_base_addr(it, i)};
+					const os::phys_ptr<os::paging::page> s{
+						multiboot2::memory_map_base_addr(it, i) < 0x1000
+							? 0x1000
+							: (multiboot2::memory_map_base_addr(it, i) + 0x1000 - 1) / 0x1000 * 0x1000
+					};
 					const os::phys_ptr<os::paging::page> e{multiboot2::memory_map_base_addr(it, i) + multiboot2::memory_map_length(it, i) / 0x1000 * 0x1000};
-					if (s == nullptr) {
-					}
 					if (s < e) {
 						remove_some_mem(
 						s, e, kernel_start, kernel_end,
@@ -96,6 +97,14 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 						}
 						);
 					}
+					bool info_usable = true;
+					remove_some_mem(info_start, info_end, s, e, [&info_usable](auto, auto) {
+						info_usable = false;
+					});
+					info_pages_wholly_usable = info_pages_wholly_usable || info_usable;
+					// info_pages_wholly_usable will only be false if no usable RAM section covers all the multiboot info struct.
+					// This allows me to make sure that I don't use any unusable RAM, in the very improbable case where the
+					// multiboot info struct is in a partially usable memory page.
 				}
 			}
 			break;
@@ -104,9 +113,14 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 	}
 
 	// Deallocate multiboot info structure: not usable anymore.
-	page_allocator.deallocate({.ptr = info_start, .size = (info_end.get_phys_addr() - info_start.get_phys_addr()) / 0x1000});
+	if (info_pages_wholly_usable) {
+		page_allocator.deallocate({.ptr = info_start, .size = (info_end.get_phys_addr() - info_start.get_phys_addr()) / 0x1000});
+	} else if (info_start + 1 < info_end - 1) {
+		// Ignore the first and last blocks: ensures all the RAM is truly usable.
+		page_allocator.deallocate({.ptr = info_start + 1, .size = (info_end.get_phys_addr() - info_start.get_phys_addr()) / 0x1000 - 2});
+	}
 
-	os::println("RAM:");
+	os::print("RAM:\n");
 	page_allocator.print_all();
 
 	for (std::size_t x = 0; x < framebuffer.get_width(); x++) {
-- 
2.46.0