From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Fri, 6 May 2022 22:57:12 +0000 (+0200)
Subject: Changed the physical page allocator completely, to make the code simpler
X-Git-Url: https://git.ameliathe1st.gay/?a=commitdiff_plain;h=6a6989d4c3cd42c60348b2ff7000da31198c91b0;p=voyage-au-centre-des-fichiers.git

Changed the physical page allocator completely, to make the code simpler
---

diff --git a/src/boot.S b/src/boot.S
index 5c331ef..6cd3e60 100644
--- a/src/boot.S
+++ b/src/boot.S
@@ -85,11 +85,6 @@ TSS:
 TSS_END:
 .set TSS_SIZE, TSS_END - TSS
 .align 0x1000
-#TODO replace with actual RAM detection
-.globl test_ram
-test_ram: .quad 256
-          .quad 0
-          .skip 0x1000 * 256 - 16 # 1MiB RAM
 PDPT_low:  .quad 0x83
            .quad 0x83 + 1024 * 1024 * 1024
            .skip 0x1000 - 16
@@ -99,6 +94,11 @@ PDPT_high: .skip 0x1000 - 16
 
 .section .bss
 .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 784859f..4b810d9 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -11,9 +11,33 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 		os::halt();
 	}
 
-	uintptr_t ram_ptr;
-	asm("mov $test_ram - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
-	os::paging::page_allocator page_allocator(ram_ptr);
+
+	os::paging::page_allocator page_allocator{([]() {
+		os::phys_ptr<os::paging::page> ram_ptr = nullptr;
+		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});
+	}
+
+	page_allocator.print_all();
+	{
+		os::println("Alloc #1.");
+		auto mem1 = page_allocator.allocate(0x10);
+		page_allocator.print_all();
+		os::println("Alloc #2.");
+		auto mem2 = page_allocator.allocate(0x20);
+		page_allocator.print_all();
+		os::println("Dealloc #1.");
+		page_allocator.deallocate(mem1);
+		page_allocator.print_all();
+		os::println("Dealloc #2.");
+		page_allocator.deallocate(mem2);
+		page_allocator.print_all();
+	}
 
 	os::framebuffer framebuffer;
 
@@ -30,16 +54,19 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 				multiboot2::color_info(it)
 			);
 			break;
+		case multiboot2::info::type_t::memory_map:
+			os::println("Memory map.");
+			break;
 		default: break;
 		}
 	}
 
-	for (size_t x = 0; x < framebuffer.get_width(); x++) {
-		for (size_t y = 0; y < framebuffer.get_height(); y++) {
+	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, {
-				.r = uint8_t(x * 256 / framebuffer.get_width()),
+				.r = std::uint8_t(x * 256 / framebuffer.get_width()),
 				.g = 0,
-				.b = uint8_t(y * 256 / framebuffer.get_height()),
+				.b = std::uint8_t(y * 256 / framebuffer.get_height()),
 			});
 		}
 	}
diff --git a/src/paging.cpp b/src/paging.cpp
index 55ed826..f3b45cd 100644
--- a/src/paging.cpp
+++ b/src/paging.cpp
@@ -1,109 +1,97 @@
 #include "paging.hpp"
 
-os::paging::page_allocator::page_allocator(os::phys_ptr<paging::page> head): head(head.get_phys_addr()) {
-	phys_ptr<page> prev{nullptr};
-	for (auto it = this->head; it != nullptr; prev = it, it = it->next_streak) {
-		if (prev >= it) {
-			os::println("Error: unordered memory given to the page allocator.");
-			break;
-		}
-		while (it.get_phys_addr() + it->streak_size * 0x1000 == it->next_streak.get_phys_addr()) {
-			it->streak_size += it->next_streak->streak_size;
-			it->next_streak = it->next_streak->next_streak;
-		}
-	}
+os::paging::page_allocator::page_allocator(phys_ptr<paging::page> one_past_end): begin_(one_past_end.get_phys_addr()), end_(begin_) {
+	end_->prev = nullptr;
+	end_->next = nullptr;
+	end_->size = 1;
 }
 
 void os::paging::page_allocator::print_all() const {
-	if (head == nullptr) {
+	if (is_empty()) {
 		os::println("No RAM left.");
-	} else for (auto it = head; it != nullptr; it = it->next_streak) {
+	} 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->streak_size);
+		os::print(it->size);
 		os::printc('\n');
 	}
 }
 
-os::paging::page_allocator::block os::paging::page_allocator::allocate(uint64_t count) {
-	phys_ptr<page> prev{nullptr};
-	for (auto it = head; it != nullptr; prev = it, it = it->next_streak) {
-		if (it->streak_size == count) {
-			if (prev == nullptr) {
-				head = it->next_streak;
-			} else {
-				prev->next_streak = it->next_streak;
-			}
+// void os::paging::page_allocator::mark_as_used(block b);
+os::paging::page_allocator::block os::paging::page_allocator::allocate(std::uint64_t count) {
+	for (auto it = begin(); it != end(); it = it->next) {
+		if (count == it->size) {
+			erase(it);
 			return {
-				.ptr = it.get_phys_addr(),
+				.ptr = phys_ptr<paging::page>(it.get_phys_addr()),
 				.size = count,
 			};
-		}
-		if (it->streak_size > count) {
-			if (prev == nullptr) {
-				head = it.get_phys_addr() + count * 0x1000;
-				head->streak_size = it->streak_size - count;
-				head->next_streak = it->next_streak;
-			} else {
-				prev->next_streak = it.get_phys_addr() + count * 0x1000;
-				prev->next_streak->streak_size = it->streak_size - count;
-				head->next_streak->next_streak = it->next_streak;
-			}
+		} else if (count < it->size) {
+			erase(split_at_offset(it, count));
 			return {
-				.ptr = it.get_phys_addr(),
+				.ptr = phys_ptr<paging::page>(it.get_phys_addr()),
 				.size = count,
 			};
 		}
 	}
-	return {.ptr = nullptr, .size = 0};
+	return { .ptr = nullptr, .size = 0 };
 }
-
 void os::paging::page_allocator::deallocate(block b) {
-	const phys_ptr<page> ptr = b.ptr.get_phys_addr();
-	const uint64_t size = b.size;
-	
+	const phys_ptr<page> b_it{b.ptr.get_phys_addr()};
+	auto it = begin();
+	while (it != end() && it < b_it) { it = it->next; }
+	try_merge_next(try_merge_prev(insert(it, b)));
+}
+
+bool os::paging::page_allocator::is_empty() const { return begin() == end(); }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::begin() { return begin_; }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::end()   { return end_;   }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::begin() const { return begin_; }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::end()   const { return end_;   }
 
-	phys_ptr<page> before{nullptr};
-	phys_ptr<page> after = head;
-	while (after != nullptr && after < ptr) {
-		before = after;
-		after = after->next_streak;
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::insert(phys_ptr<page> it, block b) {
+	const phys_ptr<page> b_it{b.ptr.get_phys_addr()};
+	if (it->prev == nullptr) {
+		begin_ = b_it;
+	} else {
+		it->prev->next = b_it;
 	}
-	if (before != nullptr && before.get_phys_addr() + 0x1000 * before->streak_size == ptr) {
-		// Should merge with previous.
-		if (after != nullptr && ptr.get_phys_addr() + 0x1000 * size == after) {
-			// Should merge with next.
-			before->streak_size += size + after->streak_size;
-			before->next_streak = after->next_streak;
-		} else {
-			// Shouldn't merge with next.
-			before->streak_size += size;
-		}
+	b_it->prev = it->prev;
+	b_it->next = it;
+	it->prev = b_it;
+	b_it->size = b.size;
+	return b_it;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::try_merge_prev(phys_ptr<page> it) {
+	os::assert(it != end(), "end() passed to page_allocator::try_merge_prev(phys_ptr<page>).");
+	if (it->prev == nullptr) { return it; }
+	if (it->prev + it->prev->size != it) { return it; }
+	it->prev->size += it->size;
+	return erase(it)->prev;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::try_merge_next(phys_ptr<page> it) {
+	os::assert(it != end(), "end() passed to page_allocator::try_merge_next(phys_ptr<page>).");
+	if (it->next == end()) return it;
+	try_merge_prev(it->next);
+	return it;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::erase(phys_ptr<page> it) {
+	os::assert(it != end(), "end() passed to page_allocator::remove(phys_ptr<page>).");
+	if (it->prev == nullptr) {
+		begin_ = it->next;
 	} else {
-		// Shouldn't merge with previous.
-		if (after != nullptr && ptr.get_phys_addr() + 0x1000 * size == after) {
-			// Should merge with next.
-			if (before != nullptr) {
-				before->next_streak = before->next_streak.get_phys_addr() - 0x1000 * size;
-				before->next_streak->next_streak = after->next_streak;
-				before->next_streak->streak_size = after->streak_size + size;
-			} else {
-				head = head.get_phys_addr() - 0x1000 * size;
-				head->next_streak = after->next_streak;
-				head->streak_size = after->streak_size + size;
-			}
-		} else {
-			// Shouldn't merge with next.
-			if (before != nullptr) {
-				before->next_streak = ptr;
-				ptr->next_streak = after;
-				ptr->streak_size = size;
-			} else {
-				head = ptr;
-				ptr->next_streak = after;
-				ptr->streak_size = size;
-			}
-		}
+		it->prev->next = it->next;
 	}
+	it->next->prev = it->prev;
+	return it->next;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::split_at_offset(phys_ptr<page> it, std::size_t offset) {
+	os::assert(it != end(), "end() passed to page_allocator::split_at_offset(phys_ptr<page>, std::size_t).");
+	os::assert(offset < it->size, "offset passed to page_allocator::split_at_offset(phys_ptr<page>, std::size_t) was too big.");
+	os::assert(offset != 0, "offset 0 passed to page_allocator::split_at_offset(phys_ptr<page>, std::size_t).");
+	phys_ptr<page> after_split = it + offset;
+	insert(it->next, block{ .ptr = phys_ptr<paging::page>{after_split.get_phys_addr()}, .size = it->size - offset });
+	it->size = offset;
+	return it;
 }
diff --git a/src/paging.hpp b/src/paging.hpp
index c2d0fa7..bcdb12d 100644
--- a/src/paging.hpp
+++ b/src/paging.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <stdint.h>
+#include <cstdint>
 #include "serial.hpp"
 #include "utils.hpp"
 
@@ -36,20 +36,20 @@ public:
 	inline void PK(unsigned v) {
 		os::assert(is_page(), "Error: write to protection key of non-page.");
 		os::assert((v & 0xF) == v, "Error: incorrect protection key.");
-		data = (data & ~(0xFul << 59)) | (uint64_t(v) << 59);
+		data = (data & ~(0xFul << 59)) | (std::uint64_t(v) << 59);
 	}
 	inline unsigned AVL_high() {
 		return (data >> 52) & (is_page() ? 0x7F : 0x7FF);
 	}
 	inline void AVL_high(unsigned v) {
 		os::assert((v & (is_page() ? 0x7F : 0x7FF)) == v, "Error: incorrect AVL high bits.");
-		data = (data & ~((is_page() ? 0x7Ful : 0x7FFul) << 52)) | (uint64_t(v) << 52);
+		data = (data & ~((is_page() ? 0x7Ful : 0x7FFul) << 52)) | (std::uint64_t(v) << 52);
 	}
 	inline phys_ptr<paging_table<order - 1>> base_address() {
 		return {data & 0x000FFFFFFFFFF000 & ~(order != 0 && is_page() ? 1ul << 12 : 0ul)};
 	}
 	inline void base_address(phys_ptr<paging_table<order - 1>> v) {
-		const uint64_t v_int = v.get_phys_addr();
+		const std::uint64_t v_int = v.get_phys_addr();
 		os::assert((v_int & 0x000FFFFFFFFFF000 & (0xFFFFFFFFFFFFF000 << (is_page() ? 9 * order : 0))) == v_int, "Error: incorrect base address.");
 		data = (data & ~0x000FFFFFFFFFF000ul & ~(order != 0 && is_page() ? 1ul << 12 : 0ul)) | v_int;
 	}
@@ -122,7 +122,7 @@ public:
 	}
 
 private:
-	uint64_t data;
+	std::uint64_t data;
 };
 
 template <int order>
@@ -133,7 +133,7 @@ struct __attribute__((aligned(0x1000))) paging_table {
 
 template<>
 struct paging_table<-1> {
-	uint8_t contents[0x1000];
+	std::uint8_t contents[0x1000];
 };
 
 using PML4T = paging_table<3>;
@@ -150,24 +150,38 @@ class page_allocator {
 public:
 	struct block {
 		phys_ptr<paging::page> ptr = nullptr;
-		uint64_t size;
+		std::uint64_t size;
 	};
 
-	page_allocator(phys_ptr<paging::page> head);
+	page_allocator(phys_ptr<paging::page> one_past_end_page);
 	void print_all() const;
 
-	block allocate(uint64_t page_count);
+	void mark_as_used(block b);
+	block allocate(std::uint64_t page_count);
 	void deallocate(block b);
 
 private:
 	struct __attribute__((aligned(0x1000))) page {
-		uint64_t streak_size;
-		phys_ptr<page> next_streak;
-		char padding[0x1000 - 8 - 8];
+		phys_ptr<page> prev;
+		phys_ptr<page> next;
+		std::uint64_t size;
+		char padding[0x1000 - 8 * 3];
 	};
 	static_assert(sizeof(page) == 0x1000);
 	static_assert(alignof(page) == 0x1000);
-	phys_ptr<page> head;
+	phys_ptr<page> begin_;
+	phys_ptr<page> end_;
+
+	phys_ptr<page> begin();
+	phys_ptr<page> end();
+	phys_ptr<page> begin() const;
+	phys_ptr<page> end() const;
+	bool is_empty() const;
+	phys_ptr<page> insert(phys_ptr<page> it, block b);
+	phys_ptr<page> try_merge_prev(phys_ptr<page> it);
+	phys_ptr<page> try_merge_next(phys_ptr<page> it);
+	phys_ptr<page> erase(phys_ptr<page> it);
+	phys_ptr<page> split_at_offset(phys_ptr<page> it, std::size_t offset);
 };
 
 }} // os::paging