From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Sat, 8 Oct 2022 18:27:23 +0000 (+0200)
Subject: Changed the algorithm that makes the free RAM available, to make it cleaner and more... 
X-Git-Url: https://git.ameliathe1st.gay/?a=commitdiff_plain;h=2dc36ddd2e8f577785195e550dd3764e9733af01;p=voyage-au-centre-des-fichiers.git

Changed the algorithm that makes the free RAM available, to make it cleaner and more effective
---

diff --git a/src/kernel.cpp b/src/kernel.cpp
index 1b51307..a52ecab 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -4,30 +4,6 @@
 #include "serial.hpp"
 #include "interrupts.hpp"
 
-void remove_some_mem(os::phys_ptr<os::paging::page> mem_start,
-		os::phys_ptr<os::paging::page> mem_end,
-		os::phys_ptr<os::paging::page> remove_start,
-		os::phys_ptr<os::paging::page> remove_end,
-		std::invocable<os::phys_ptr<os::paging::page>, os::phys_ptr<os::paging::page>> auto callback
-		) {
-	if (remove_start <= mem_start && mem_start < remove_end && remove_end < mem_end) {
-		// Removes start:
-		callback(remove_end, mem_end);
-	} else if (mem_start < remove_start && remove_start < mem_end && mem_end <= remove_end) {
-		// Removes end:
-		callback(mem_start, remove_start);
-	} else if (remove_start <= mem_start && mem_end <= remove_end) {
-		// Removes all:
-	} else if (mem_start < remove_start && remove_end < mem_end) {
-		// Removes middle:
-		callback(mem_start, remove_start);
-		callback(remove_end, mem_end);
-	} else {
-		// Remove nothing:
-		callback(mem_start, mem_end);
-	}
-}
-
 os::idt<32> idt;
 
 extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
@@ -35,64 +11,79 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 	os::assert(os::cpu_has_msr(), "MSRs aren't supported.");
 
 	if (!os::init_serial_port()) {
-		os::hlt();
+		while (true) {
+			os::hlt();
+		}
 	}
 
-	const os::phys_ptr<os::paging::page> kernel_start = ([]() {
-		os::phys_ptr<os::paging::page> ptr = nullptr;
-		asm("mov $_kernel_phys_start,%0" : "=ri"(ptr));
-		return ptr;
-	})();
-	const os::phys_ptr<os::paging::page> kernel_end = ([]() {
-		os::phys_ptr<os::paging::page> ptr = nullptr;
-		asm("mov $_kernel_phys_end,%0" : "=ri"(ptr));
-		return ptr;
-	})();
-	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;
+	{
+		struct {
+			os::phys_ptr<os::paging::page> start_address = nullptr;
+			os::phys_ptr<os::paging::page> end_address = nullptr;
+		} available_ram[50];
+		std::size_t available_ram_length = 0;
 
-	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:
-			for (std::size_t i = 0; i < multiboot2::memory_map_number_of_entries(it); i++) {
-				if (multiboot2::memory_map_type(it, i) == 1) {
-					const os::phys_ptr<os::paging::page> s{(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 < e) {
-						remove_some_mem(
-						s, e, kernel_start, kernel_end,
-						[info_start, info_end] (auto s, auto e) {
-							remove_some_mem(
-							s, e, info_start, info_end,
-							[] (auto s, auto e) {
-								os::paging::page_allocator.deallocate({.ptr = s, .size = std::uint64_t(e - 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::memory_map:
+				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>
+							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>
+							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};
 						}
-						);
 					}
-					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;
+			default: break;
 			}
-			break;
-		default: break;
 		}
-	}
 
-	// Deallocate multiboot info structure: not usable anymore.
-	if (info_pages_wholly_usable) {
-		os::paging::page_allocator.deallocate({.ptr = info_start, .size = std::uint64_t(info_end - info_start)});
-	} else if (info_start + 1 < info_end - 1) {
-		// Ignore the first and last blocks: ensures all the RAM is truly usable.
-		os::paging::page_allocator.deallocate({.ptr = info_start + 1, .size = std::uint64_t(info_end - info_start - 2)});
+		// kernel_start and kernel_end are aligned to 4K by the linker script.
+		const os::phys_ptr<os::paging::page> s = ([]() {
+			os::phys_ptr<os::paging::page> ptr = nullptr;
+			asm("mov $_kernel_phys_start,%0" : "=ri"(ptr));
+			return ptr;
+		})();
+		const os::phys_ptr<os::paging::page> e = ([]() {
+			os::phys_ptr<os::paging::page> ptr = nullptr;
+			asm("mov $_kernel_phys_end,%0" : "=ri"(ptr));
+			return ptr - 1; // [s, e], not [s, e[
+		})();
+
+		// Remove kernel from available RAM:
+		for (std::size_t i = 0; i < available_ram_length; i++) {
+			if (e < available_ram[i].start_address || available_ram[i].end_address < s) {
+				continue;
+			}
+			if (s <= available_ram[i].start_address && available_ram[i].end_address <= e) {
+				available_ram[i] = available_ram[--available_ram_length];
+			} else if (s <= available_ram[i].start_address) {
+				available_ram[i].start_address = e + 1; // Since e < end_address, new start_address <= end_address.
+			} else if (available_ram[i].end_address <= e) {
+				available_ram[i].end_address = s - 1; // Since start_address < s, start_address <= new end_address.
+			} else {
+				os::assert(available_ram_length < 50, "Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
+				available_ram[available_ram_length] = available_ram[i];
+				available_ram[i].end_address = s - 1;
+				available_ram[available_ram_length].start_address = e + 1;
+				available_ram_length++;
+			}
+		}
+
+		// Add available RAM to the page allocator (warning: overrides the multiboot info structure):
+		for (std::size_t i = 0; i < available_ram_length; i++) {
+			os::paging::page_allocator.deallocate({
+				.ptr = available_ram[i].start_address,
+				.size = std::size_t(available_ram[i].end_address - available_ram[i].start_address + 1)
+			});
+		}
 	}
 
 	os::print("RAM:\n");