From 2dc36ddd2e8f577785195e550dd3764e9733af01 Mon Sep 17 00:00:00 2001 From: Amelia Coutard Date: Sat, 8 Oct 2022 20:27:23 +0200 Subject: [PATCH] Changed the algorithm that makes the free RAM available, to make it cleaner and more effective --- src/kernel.cpp | 137 +++++++++++++++++++++++-------------------------- 1 file changed, 64 insertions(+), 73 deletions(-) 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 mem_start, - os::phys_ptr mem_end, - os::phys_ptr remove_start, - os::phys_ptr remove_end, - std::invocable, os::phys_ptr> 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 info) { @@ -35,64 +11,79 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr kernel_start = ([]() { - os::phys_ptr ptr = nullptr; - asm("mov $_kernel_phys_start,%0" : "=ri"(ptr)); - return ptr; - })(); - const os::phys_ptr kernel_end = ([]() { - os::phys_ptr ptr = nullptr; - asm("mov $_kernel_phys_end,%0" : "=ri"(ptr)); - return ptr; - })(); - const os::phys_ptr info_start{info.get_phys_addr() / 0x1000 * 0x1000}; // Round start down. - const os::phys_ptr 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 start_address = nullptr; + os::phys_ptr 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 s{(multiboot2::memory_map_base_addr(it, i) + 0x1000 - 1) / 0x1000 * 0x1000}; - const os::phys_ptr 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 + s{(multiboot2::memory_map_base_addr(it, i) + 0x1000 - 1) / 0x1000 * 0x1000}; + // Rounded down, to avoid including non-ram. + const os::phys_ptr + 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 s = ([]() { + os::phys_ptr ptr = nullptr; + asm("mov $_kernel_phys_start,%0" : "=ri"(ptr)); + return ptr; + })(); + const os::phys_ptr e = ([]() { + os::phys_ptr 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"); -- 2.47.0