From 8cade7acc1c1b1e62c136f5a76f72f2abd5a1841 Mon Sep 17 00:00:00 2001
From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Sun, 8 May 2022 00:37:30 +0200
Subject: [PATCH] Added actual detection of RAM, to be able to use all of the
 computer's memory

---
 linker.ld          |  4 +++
 src/boot.S         |  3 --
 src/kernel.cpp     | 82 ++++++++++++++++++++++++++++++++++++++++++----
 src/multiboot2.hpp | 19 +++++++++++
 src/paging.cpp     |  5 ++-
 5 files changed, 101 insertions(+), 12 deletions(-)

diff --git a/linker.ld b/linker.ld
index 7c4e9f6..7b57d1e 100644
--- a/linker.ld
+++ b/linker.ld
@@ -5,6 +5,8 @@ SECTIONS {
 
 	. = 1M;
 
+	. = ALIGN(4K);
+	_kernel_phys_start = .;
 	.bootstrap ALIGN(4K) : {
 		*(.multiboot_header)
 		. = ALIGN(4K);
@@ -29,6 +31,8 @@ SECTIONS {
 		*(.bss)
 		*(COMMON)
 	}
+	. = ALIGN(4K);
+	_kernel_phys_end = . - KERNEL_VMA;
 
 
 	/DISCARD/ : {
diff --git a/src/boot.S b/src/boot.S
index 6cd3e60..ec6a75f 100644
--- a/src/boot.S
+++ b/src/boot.S
@@ -96,9 +96,6 @@ PDPT_high: .skip 0x1000 - 16
 .align 0x1000
 .globl page_list_one_past_end
 page_list_one_past_end: .skip 0x1000
-#TODO replace with actual RAM detection
-.globl test_ram
-test_ram: .skip 0x1000 * 256 # 1MiB RAM
 PML4T: .skip 0x1000
 phys_mem_map: .skip 0x1000 * 128 - 8
 .align 16
diff --git a/src/kernel.cpp b/src/kernel.cpp
index e627ac5..ef4d26f 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -4,6 +4,34 @@
 #include "utils.hpp"
 #include "serial.hpp"
 
+namespace detail {
+	template <typename F> concept func_on_mem = std::invocable<F, os::phys_ptr<os::paging::page>, os::phys_ptr<os::paging::page>>;
+}
+
+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,
+		detail::func_on_mem 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);
+	}
+}
+
 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.");
 
@@ -17,14 +45,23 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 		asm("mov $page_list_one_past_end - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
 		return ram_ptr;
 	})()};
-	{
-		os::phys_ptr<os::paging::page> ram_ptr = nullptr;
-		asm("mov $test_ram - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
-		page_allocator.deallocate({.ptr = ram_ptr, .size = 256});
-	}
+	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()};
+	const os::phys_ptr<os::paging::page> info_end = info_start + (info->total_size - 1 + 0x1000) / 0x1000; // Number of pages taken, rounded up
 
 	os::framebuffer framebuffer;
 
+
+
 	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:
@@ -39,12 +76,45 @@ 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.");
+			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> 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,
+						[&page_allocator, info_start, info_end] (auto s, auto e) {
+							remove_some_mem(
+							s, e, info_start, info_end,
+							[&page_allocator] (auto s, auto e) {
+								page_allocator.deallocate({.ptr = s, .size = (e.get_phys_addr() - s.get_phys_addr()) / 0x1000});
+							}
+							);
+						}
+						);
+					}
+				}
+			}
 			break;
 		default: break;
 		}
 	}
 
+	// 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});
+
+	os::println("RAM:");
+	page_allocator.print_all();
+
 	for (std::size_t x = 0; x < framebuffer.get_width(); x++) {
 		for (std::size_t y = 0; y < framebuffer.get_height(); y++) {
 			framebuffer.putpixel(x, y, {
diff --git a/src/multiboot2.hpp b/src/multiboot2.hpp
index cbbdf5c..372fb13 100644
--- a/src/multiboot2.hpp
+++ b/src/multiboot2.hpp
@@ -89,6 +89,25 @@
 	inline const std::uint8_t* color_info(os::phys_ptr<const info> ptr) {
 		return reinterpret_cast<const std::uint8_t*>(&ptr->rest[24]);
 	}
+
+	inline std::uint32_t memory_map_entry_size(os::phys_ptr<const info> ptr) {
+		return *reinterpret_cast<const std::uint32_t*>(&ptr->rest[0]);
+	}
+	inline std::uint32_t memory_map_entry_version(os::phys_ptr<const info> ptr) {
+		return *reinterpret_cast<const std::uint32_t*>(&ptr->rest[4]);
+	}
+	inline std::size_t memory_map_number_of_entries(os::phys_ptr<const info> ptr) {
+		return (ptr->size - 16) / memory_map_entry_size(ptr);
+	}
+	inline std::uint64_t memory_map_base_addr(os::phys_ptr<const info> ptr, std::size_t index) {
+		return *reinterpret_cast<const std::uint64_t*>(&ptr->rest[8 + memory_map_entry_size(ptr) * index +  0]);
+	}
+	inline std::uint64_t memory_map_length(os::phys_ptr<const info> ptr, std::size_t index) {
+		return *reinterpret_cast<const std::uint64_t*>(&ptr->rest[8 + memory_map_entry_size(ptr) * index +  8]);
+	}
+	inline std::uint32_t memory_map_type(os::phys_ptr<const info> ptr, std::size_t index) {
+		return *reinterpret_cast<const std::uint32_t*>(&ptr->rest[8 + memory_map_entry_size(ptr) * index + 16]);
+	}
 #endif // __cplusplus
 
 #ifdef __cplusplus
diff --git a/src/paging.cpp b/src/paging.cpp
index d841509..530436c 100644
--- a/src/paging.cpp
+++ b/src/paging.cpp
@@ -10,10 +10,9 @@ void os::paging::page_allocator::print_all() const {
 	if (is_empty()) {
 		os::println("No RAM left.");
 	} else for (auto it = begin(); it != end(); it = it->next) {
-		os::print("addr:size = 0x");
 		os::print(it.get_phys_addr());
-		os::print(":0x");
-		os::print(it->size);
+		os::print("->");
+		os::print((it + it->size).get_phys_addr());
 		os::printc('\n');
 	}
 }
-- 
2.46.0