]> git.ameliathe1st.gay Git - voyage-au-centre-des-fichiers.git/commitdiff
Added serial logging and a simple physical page allocator
authorAmelia Coutard <eliottulio.coutard@gmail.com>
Thu, 5 May 2022 17:17:47 +0000 (19:17 +0200)
committerAmelia Coutard <eliottulio.coutard@gmail.com>
Thu, 5 May 2022 17:17:47 +0000 (19:17 +0200)
docs.txt [new file with mode: 0644]
src/kernel.cpp
src/paging.cpp [new file with mode: 0644]
src/paging.hpp [new file with mode: 0644]
src/serial.cpp [new file with mode: 0644]
src/serial.hpp [new file with mode: 0644]
src/utils.S [new file with mode: 0644]
src/utils.hpp [new file with mode: 0644]

diff --git a/docs.txt b/docs.txt
new file mode 100644 (file)
index 0000000..99fac45
--- /dev/null
+++ b/docs.txt
@@ -0,0 +1,10 @@
+Memory mapping:
+       0x0000000000000000···0x00007FFFFFFFFFFF (128 TiB)= user
+
+       0xFFFF800000000000···0xFFFFBFFFFFFFFFFF ( 64 TiB) = physical memory mapping
+       0xFFFFC00000000000···0xFFFFFFFF7FFFFFFF (~64 TiB) = unused
+       0xFFFFFFFF80000000···0xFFFFFFFFFFFFFFFF (  2 GiB) = kernel
+
+Unused pages: First 8 bytes: size of current streak, in pages
+              Next 8 bytes: pointer to next stream (or 0 if no free memory after this streak).
+              All other bytes are unused.
index e7d9d6aeb9cec3e21d1296ed5c85de8461f4034a..f6415ae3bd2f0b956e18650818316c71cddf22da 100644 (file)
@@ -1,10 +1,24 @@
 #include "multiboot2.hpp"
+#include "paging.hpp"
+#include "utils.hpp"
+#include "serial.hpp"
 
-extern "C" void kmain() {
-       volatile short* vga_text = reinterpret_cast<volatile short*>((void*)0xFFFFFFFF800B8000);
-       const char* str = "Success ! Took me long enough.";
-       for (unsigned long i = 0; str[i] != '\0'; i++) {
-               vga_text[i] = (0x02 << 8) + str[i];
+extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
+       os::assert(magic == 0x36D76289, "Error: Incorrect magic number: wasn't booted with multiboot.");
+
+       if (!os::init_serial_port()) {
+               os::halt();
        }
-       while (true) {}
+
+       uintptr_t ram_ptr;
+       asm("mov $test_ram - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
+       os::paging::page_allocator page_allocator(ram_ptr);
+
+       for (auto it = multiboot2::next(info); it->type != multiboot2::info::type_t::end; it = multiboot2::next(it)) {
+               switch (it->type) {
+               default: break;
+               }
+       }
+
+       os::halt();
 }
diff --git a/src/paging.cpp b/src/paging.cpp
new file mode 100644 (file)
index 0000000..55ed826
--- /dev/null
@@ -0,0 +1,109 @@
+#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;
+               }
+       }
+}
+
+void os::paging::page_allocator::print_all() const {
+       if (head == nullptr) {
+               os::println("No RAM left.");
+       } else for (auto it = head; it != nullptr; it = it->next_streak) {
+               os::print("addr:size = 0x");
+               os::print(it.get_phys_addr());
+               os::print(":0x");
+               os::print(it->streak_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;
+                       }
+                       return {
+                               .ptr = 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;
+                       }
+                       return {
+                               .ptr = it.get_phys_addr(),
+                               .size = count,
+                       };
+               }
+       }
+       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;
+       
+
+       phys_ptr<page> before{nullptr};
+       phys_ptr<page> after = head;
+       while (after != nullptr && after < ptr) {
+               before = after;
+               after = after->next_streak;
+       }
+       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;
+               }
+       } 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;
+                       }
+               }
+       }
+}
diff --git a/src/paging.hpp b/src/paging.hpp
new file mode 100644 (file)
index 0000000..c2d0fa7
--- /dev/null
@@ -0,0 +1,173 @@
+#pragma once
+
+#include <stdint.h>
+#include "serial.hpp"
+#include "utils.hpp"
+
+namespace os { namespace paging {
+
+template <int order>
+struct __attribute__((aligned(0x1000))) paging_table;
+
+template <int order>
+struct paging_entry {
+public:
+       static_assert(order >= 0, "Error: negative order for paging entry.");
+       paging_entry(bool is_page) {
+               os::assert(order != 0 || is_page, "4KiB defined as non-page.");
+               if (order != 0 && is_page) {
+                       data |= 1 << 7; // Mark as smallest page.
+               }
+       }
+       inline bool is_page() {
+               return order == 0 || (data & (1 << 7)) != 0;
+       }
+       
+       inline bool NX() {
+               return (data & (1ul << 63)) != 0;
+       }
+       inline void NX(bool v) {
+               data = (data & ~(1ul << 63)) | (v ? (1ul << 63) : 0);
+       }
+       inline unsigned PK() {
+               os::assert(is_page(), "Error: read protection key of non-page.");
+               return (data >> 52) & 0xF;
+       }
+       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);
+       }
+       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);
+       }
+       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();
+               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;
+       }
+       inline unsigned AVL_low() {
+               return (data >> 9) & 0x7;
+       }
+       inline void AVL_low(unsigned v) {
+               os::assert((v & 0x7) == v, "Error: incorrect AVL low bits");
+               data = (data & ~(0x7ul << 9)) | (v << 9);
+       }
+       inline bool G() {
+               os::assert(is_page(), "Error: read global bit of non-page.");
+               return (data & (1 << 8)) != 0;
+       }
+       inline void G(bool v) {
+               os::assert(is_page(), "Error: write to global bit of non-page.");
+               data = (data & ~(1ul << 8)) | (v ? 1 << 8 : 0);
+       }
+       inline bool PAT() {
+               os::assert(is_page(), "Error: read PAT bit of non-page.");
+               return (data & (1 << (order == 0 ? 7 : 12))) != 0;
+       }
+       inline void PAT(bool v) {
+               os::assert(is_page(), "Error: write to PAT bit of non-page.");
+               data = (data & ~(1ul << (order == 0 ? 7 : 12))) | (v ? 1 << (order == 0 ? 7 : 12) : 0);
+       }
+       inline bool D() {
+               os::assert(is_page(), "Error: read dirty bit of non-page.");
+               return (data & (1 << 6)) != 0;
+       }
+       inline void D(bool v) {
+               os::assert(is_page(), "Error: write to dirty bit of non-page.");
+               data = (data & ~(1ul << 6)) | (v ? 1 << 6 : 0);
+       }
+       inline bool A() {
+               return (data & (1 << 5)) != 0;
+       }
+       inline void A(bool v) {
+               data = (data & ~(1ul << 5)) | (v ? 1 << 5 : 0);
+       }
+       inline bool PCD() {
+               return (data & (1 << 4)) != 0;
+       }
+       inline void PCD(bool v) {
+               data = (data & ~(1ul << 4)) | (v ? 1 << 4 : 0);
+       }
+       inline bool PWT() {
+               return (data & (1 << 3)) != 0;
+       }
+       inline void PWT(bool v) {
+               data = (data & ~(1ul << 3)) | (v ? 1 << 3 : 0);
+       }
+       inline bool U_S() {
+               return (data & (1 << 2)) != 0;
+       }
+       inline void U_S(bool v) {
+               data = (data & ~(1ul << 2)) | (v ? 1 << 2 : 0);
+       }
+       inline bool R_W() {
+               return (data & (1 << 1)) != 0;
+       }
+       inline void R_W(bool v) {
+               data = (data & ~(1ul << 1)) | (v ? 1 << 1 : 0);
+       }
+       inline bool P() {
+               return (data & (1 << 0)) != 0;
+       }
+       inline void P(bool v) {
+               data = (data & ~(1ul << 0)) | (v ? 1 << 0 : 0);
+       }
+
+private:
+       uint64_t data;
+};
+
+template <int order>
+struct __attribute__((aligned(0x1000))) paging_table {
+       static_assert(order >= 0, "Paging table of negative order.");
+       paging_entry<order> contents[512];
+};
+
+template<>
+struct paging_table<-1> {
+       uint8_t contents[0x1000];
+};
+
+using PML4T = paging_table<3>;
+using PML4E = paging_entry<3>;
+using PDPT = paging_table<2>;
+using PDPE = paging_entry<2>;
+using PDT = paging_table<1>;
+using PDE = paging_entry<1>;
+using PT = paging_table<0>;
+using PE = paging_entry<0>;
+using page = paging_table<-1>;
+
+class page_allocator {
+public:
+       struct block {
+               phys_ptr<paging::page> ptr = nullptr;
+               uint64_t size;
+       };
+
+       page_allocator(phys_ptr<paging::page> head);
+       void print_all() const;
+
+       block allocate(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];
+       };
+       static_assert(sizeof(page) == 0x1000);
+       static_assert(alignof(page) == 0x1000);
+       phys_ptr<page> head;
+};
+
+}} // os::paging
diff --git a/src/serial.cpp b/src/serial.cpp
new file mode 100644 (file)
index 0000000..8cf52b7
--- /dev/null
@@ -0,0 +1,122 @@
+#include <stddef.h>
+#include "serial.hpp"
+
+namespace {
+       void outb(uint16_t port, uint8_t data) {
+               asm volatile ("outb %1,%0" : : "dN"(port), "a"(data));
+       }
+       uint8_t inb(uint16_t port) {
+               uint8_t data;
+               asm volatile ("inb %1,%0" : "=a"(data) : "dN"(port));
+               return data;
+       }
+}
+
+bool os::init_serial_port() {
+       outb(serial_port + 1, 0x00); // Disable interrupts.
+       outb(serial_port + 3, 0x80); // Prepare to set baud rate divisor (38400 baud).
+       outb(serial_port + 0, 0x03); // lo byte
+       outb(serial_port + 1, 0x00); // hi byte
+       outb(serial_port + 3, 0x03); // 8 bits, no parity, 1 stop bit.
+       outb(serial_port + 2, 0xC7); // Enable FIFO, clear FIFO, 14-byte threshold.
+       outb(serial_port + 4, 0x0B); // IRQs enabled, RTS/DSR set.
+
+       outb(serial_port + 4, 0x1E); // Enable loopback mode (to check).
+       outb(serial_port + 0, 0xAE); // Send byte.
+       if (inb(serial_port + 0) != 0xAE) {
+               return false;
+       }
+       outb(serial_port + 4, 0x0B); // Disable loopback.
+       return true;
+}
+
+bool os::serial_received() {
+       return (inb(serial_port + 5) & 0x01) != 0;
+}
+uint8_t os::read_serial() {
+       while (!serial_received()) {}
+       return inb(serial_port + 0);
+}
+bool os::serial_transmit_empty() {
+       return (inb(serial_port + 5) & 0x20) != 0;
+}
+void os::write_serial(uint8_t v) {
+       while (!serial_transmit_empty()) {}
+       outb(serial_port + 0, v);
+}
+
+void os::printc(char c) {
+       write_serial(c);
+}
+void os::print(const char* str) {
+       for (size_t i = 0; str[i] != '\0'; i++) {
+               os::printc(str[i]);
+       }
+}
+void os::print(uint64_t v) {
+       for (int i = 60; i >= 0; i -= 4) {
+               const int c = (v >> i) & 0xF;
+               os::printc(c < 10 ? c + '0' : c + 'A' - 10);
+       }
+}
+void os::print(uint32_t v) {
+       for (int i = 28; i >= 0; i -= 4) {
+               const int c = (v >> i) & 0xF;
+               os::printc(c < 10 ? c + '0' : c + 'A' - 10);
+       }
+}
+void os::print(uint16_t v) {
+       for (int i = 12; i >= 0; i -= 4) {
+               const int c = (v >> i) & 0xF;
+               os::printc(c < 10 ? c + '0' : c + 'A' - 10);
+       }
+}
+void os::print(uint8_t v) {
+       for (int i = 4; i >= 0; i -= 4) {
+               const int c = (v >> i) & 0xF;
+               os::printc(c < 10 ? c + '0' : c + 'A' - 10);
+       }
+}
+void os::print(int64_t v) {
+       if (v < 0) {
+               os::printc('-');
+               os::print(uint64_t(-v));
+       } else {
+               os::printc(' ');
+               os::print(uint64_t(v));
+       }
+}
+void os::print(int32_t v) {
+       if (v < 0) {
+               os::printc('-');
+               os::print(uint32_t(-v));
+       } else {
+               os::printc(' ');
+               os::print(uint32_t(v));
+       }
+}
+void os::print(int16_t v) {
+       if (v < 0) {
+               os::printc('-');
+               os::print(uint16_t(-v));
+       } else {
+               os::printc(' ');
+               os::print(uint16_t(v));
+       }
+}
+void os::print(int8_t v) {
+       if (v < 0) {
+               os::printc('-');
+               os::print(uint8_t(-v));
+       } else {
+               os::printc(' ');
+               os::print(uint8_t(v));
+       }
+}
+void os::println(const char* str) {
+       os::print(str);
+       os::printc('\n');
+}
+void os::assert(bool cond, const char* diagnostic) {
+       if (!cond) { os::println(diagnostic); }
+}
diff --git a/src/serial.hpp b/src/serial.hpp
new file mode 100644 (file)
index 0000000..a62a59a
--- /dev/null
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <stdint.h>
+
+namespace os {
+
+constexpr uint16_t serial_port{0x3F8};
+
+bool init_serial_port();
+
+bool serial_received();
+uint8_t read_serial();
+bool serial_transmit_empty();
+void write_serial(uint8_t v);
+
+void printc(char c);
+void print(const char* str);
+void print(uint64_t v);
+void print(uint32_t v);
+void print(uint16_t v);
+void print(uint8_t v);
+void print(int64_t v);
+void print(int32_t v);
+void print(int16_t v);
+void print(int8_t v);
+void println(const char* str);
+void assert(bool cond, const char* diagnostic);
+
+}
diff --git a/src/utils.S b/src/utils.S
new file mode 100644 (file)
index 0000000..f1287d8
--- /dev/null
@@ -0,0 +1,6 @@
+.section .text
+.globl halt
+halt:
+       cli
+1:     hlt
+       jmp 1b
diff --git a/src/utils.hpp b/src/utils.hpp
new file mode 100644 (file)
index 0000000..82abfb6
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <stddef.h>
+
+namespace os {
+
+       template <typename T>
+       class phys_ptr {
+       public:
+               constexpr phys_ptr(uintptr_t phys_addr): phys_addr(phys_addr) {}
+               constexpr phys_ptr(nullptr_t): phys_addr(0) {}
+
+               constexpr T& operator[](size_t i) const {
+                       return get_virt_addr()[i];
+               }
+               constexpr T& operator*() const {
+                       return *get_virt_addr();
+               }
+               constexpr T* operator->() const {
+                       return get_virt_addr();
+               }
+               constexpr bool operator< (phys_ptr<T> other) const { return phys_addr < other.phys_addr; }
+               constexpr bool operator<=(phys_ptr<T> other) const { return phys_addr <= other.phys_addr; }
+               constexpr bool operator==(phys_ptr<T> other) const { return phys_addr == other.phys_addr; }
+               constexpr bool operator!=(phys_ptr<T> other) const { return phys_addr != other.phys_addr; }
+               constexpr bool operator> (phys_ptr<T> other) const { return phys_addr > other.phys_addr; }
+               constexpr bool operator>=(phys_ptr<T> other) const { return phys_addr >= other.phys_addr; }
+
+               constexpr uintptr_t get_phys_addr() const {
+                       return phys_addr;
+               }
+
+       private:
+               constexpr T* get_virt_addr() const {
+                       return reinterpret_cast<T*>(phys_addr + 0xFFFF800000000000);
+               }
+
+               uintptr_t phys_addr;
+       };
+
+       extern "C" void halt();
+} // namespace os