]> git.ameliathe1st.gay Git - voyage-au-centre-des-fichiers.git/commitdiff
Changed the physical page allocator completely, to make the code simpler
authorAmelia Coutard <eliottulio.coutard@gmail.com>
Fri, 6 May 2022 22:57:12 +0000 (00:57 +0200)
committerAmelia Coutard <eliottulio.coutard@gmail.com>
Fri, 6 May 2022 22:58:52 +0000 (00:58 +0200)
src/boot.S
src/kernel.cpp
src/paging.cpp
src/paging.hpp

index 5c331ef4b51519e874cf659c835d504b85db9cfd..6cd3e606aa5243d8e5c2aa7eed066596715bd091 100644 (file)
@@ -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
index 784859fc919692f75d502c16f38d260f5dbe7601..4b810d95ec85fc9da2ee504cf9dd9bace3fc592d 100644 (file)
@@ -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()),
                        });
                }
        }
index 55ed826c3a970e2465ddbdf744685515138280fb..f3b45cd3ee3acbee32c8080e0e755c7060e6b2bb 100644 (file)
 #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;
 }
index c2d0fa7c2c28359e5356b4d838cbb81ae4969a6f..bcdb12dd2f32573cb6a767db0ab17883b48332ee 100644 (file)
@@ -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