From 018c83575fa32c71e62adb4e0e969d60efafe7cb Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Sun, 2 May 2021 22:24:53 +0800
Subject: [PATCH] allocator

---
 kernel/Makefile           |  2 +-
 kernel/include/kutils.hpp | 94 +++++++++++++++++++++++++--------------
 kernel/include/stdint.hpp |  4 ++
 kernel/include/stdlib.hpp |  9 +++-
 kernel/include/vga.hpp    |  4 +-
 kernel/kernel.cc          | 14 ++++++
 6 files changed, 89 insertions(+), 38 deletions(-)

diff --git a/kernel/Makefile b/kernel/Makefile
index ade032a..6796ba7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -15,7 +15,7 @@ head:
 	nasm -f elf$(BITS) -DTARGET_BITS=$(BITS) image_head.asm -o image_head.o
 
 kernel:
-	g++ -ffreestanding -fpie -c kernel.cc -o kernel.o -m$(BITS) -std=c++17
+	g++ -ffreestanding -fpie -fno-exceptions -c kernel.cc -o kernel.o -m$(BITS) -std=c++17
 
 clean:
 	rm -f *.o *.img
diff --git a/kernel/include/kutils.hpp b/kernel/include/kutils.hpp
index 9a8932e..7d1c983 100644
--- a/kernel/include/kutils.hpp
+++ b/kernel/include/kutils.hpp
@@ -9,18 +9,19 @@ namespace impl {
     constexpr uint64_t kalloc_end_addr = 0x200000;
     // Currently 1MB, must be paged. 
 
-    struct __attribute__((packed)) free_slot_head_t {
+    struct __attribute__((packed)) free_slot_header_t {
         uint32_t size;
         uint64_t next; // 0x0 means tail.
     };
-    static_assert(sizeof(free_slot_head_t) == sizeof(uint32_t) + sizeof(uint64_t));
+    static_assert(sizeof(free_slot_header_t) == sizeof(uint32_t) + sizeof(uint64_t));
 
-    using allocated_slot_head_t = uint32_t; // contains size EXCEPT the head!
+    using allocated_slot_header_t = uint32_t; // contains size EXCEPT the head!
 
     inline void kalloc_init_pool() {
+        // Just create a single huge slot, which contains the whole pool. 
         struct __attribute__((packed)) _kalloc_head {
             uint32_t magic = 0x12230823;
-            free_slot_head_t free_slot_head {kalloc_end_addr - kalloc_begin_addr - sizeof(_kalloc_head), 0x0};
+            free_slot_header_t free_slot_head {kalloc_end_addr - kalloc_begin_addr - sizeof(_kalloc_head), 0x0};
         } kalloc_head;
         static_assert(sizeof(kalloc_head) == sizeof(uint32_t)*2 + sizeof(uint64_t));
 
@@ -28,57 +29,84 @@ namespace impl {
     }
 }
 
-// naive kalloc
+// naive kalloc. We keep a list of free slot. 
+// The return value is NULL on failure, and is a valid pointer `p` on success. 
+// ((allocated_slot_header_t *)p)[-1] contains the header, which records the allocated size. 
+// and ((char *)p)[0:requested_size] is available for use. 
 inline void *kalloc_impl(const uint32_t requested_size) {
-    const auto req_size_with_head = requested_size + sizeof(impl::allocated_slot_head_t);
+    const auto req_size_with_head = requested_size + sizeof(impl::allocated_slot_header_t);
     uint64_t prev_slot_addr = 0x0;
-    auto curr_slot_addr = impl::kalloc_begin_addr + sizeof(impl::free_slot_head_t::size);
+    // Locate first free slot. 
+    auto curr_slot_addr = impl::kalloc_begin_addr + sizeof(impl::free_slot_header_t::size);
     while(true) {
-        auto curr_slot = (impl::free_slot_head_t *)curr_slot_addr;
-        if(curr_slot->size >= req_size_with_head) {
-            if(curr_slot->size < 32 + req_size_with_head) {
-                // Give the whole slot
+        // Iterate all free slots. It's slow, but good enough for a toy. 
+        auto curr_freeslot_header_ptr = (impl::free_slot_header_t *)curr_slot_addr;
+        if(curr_freeslot_header_ptr->size >= req_size_with_head) {
+            // Good. We can do the allocate now! 
+            decltype(impl::free_slot_header_t::size) actually_assigned_size;
+            decltype(curr_slot_addr) allocated_slot_addr;
+            if(curr_freeslot_header_ptr->size < 32 + req_size_with_head) {
+                // Give the current slot. 
                 if(prev_slot_addr == 0x0) {
-                    // No previous slot. I am the first one.
-                    // Never give the WHOLE first slot. Try again. 
-                    goto _kalloc_failed_try_again;
+                    // The first slot must be a valid free_slot_head. It's required 
+                    //   to locate the next free_slot. 
+                    curr_freeslot_header_ptr->size = 0;
+                    // Is this case, the space of free_slot_head is not available.
+                    actually_assigned_size = curr_freeslot_header_ptr->size;
+                    allocated_slot_addr = curr_slot_addr + sizeof(impl::free_slot_header_t);
                 }
-                // Do the alloc
                 else {
-                    curr_slot->size -= req_size_with_head;
-                    auto prev_slot = (impl::free_slot_head_t *)prev_slot_addr;
-                    prev_slot->next = curr_slot->next;
+                    // Eliminate the current free_slot_head. 
+                    curr_freeslot_header_ptr->size -= req_size_with_head;
+                    auto prev_slot = (impl::free_slot_header_t *)prev_slot_addr;
+                    prev_slot->next = curr_freeslot_header_ptr->next;
+                    // Is this case, the space of free_slot_head is available.
+                    actually_assigned_size = curr_freeslot_header_ptr->size + sizeof(impl::free_slot_header_t);
+                    allocated_slot_addr = curr_slot_addr;
                 }
-                const auto actually_assigned_size = sizeof(impl::free_slot_head_t) + curr_slot->size;
-                *(impl::allocated_slot_head_t *)curr_slot_addr = actually_assigned_size;
-                return (char *)curr_slot_addr + sizeof(impl::allocated_slot_head_t);
             }
             else {
-                // Shrink the slot.
-                // Do the alloc
-                // TODO
-                curr_slot->size -= req_size_with_head;
-                return (char *)curr_slot_addr + curr_slot->size;
+                // The slot is too large. Shrink the free_slot, and give the tail space as result.
+                curr_freeslot_header_ptr->size -= req_size_with_head;
+                actually_assigned_size = req_size_with_head;
+                allocated_slot_addr = curr_slot_addr + sizeof(impl::free_slot_header_t) + curr_freeslot_header_ptr->size;
             }
+            // Create the allocated_slot_head structure. 
+            *(impl::allocated_slot_header_t *)allocated_slot_addr = actually_assigned_size - sizeof(impl::allocated_slot_header_t);
+            return (char *)allocated_slot_addr + sizeof(impl::allocated_slot_header_t);
         }
-        else if (curr_slot->next != 0x0){
-            // Failed. Next.
-_kalloc_failed_try_again:
+        else if (curr_freeslot_header_ptr->next != 0x0){
+            // Failed. Try next slot.
             prev_slot_addr = curr_slot_addr;
-            curr_slot_addr = curr_slot->next;
+            curr_slot_addr = curr_freeslot_header_ptr->next;
             continue;
         }
         else {
-            // No memory
-            return 0x0;
+            // We're already at the end. Return NO_MEMORY. 
+            return NULL;
         }
     }
 }
 
-
 inline void kfree(void *memory) {
 
 }
 
+template <typename T>
+struct kallocator {
+    using value_type = T;
+    kallocator() noexcept {}
+    template <typename AnyType> kallocator (const kallocator &) noexcept {}
+    template <typename AnyType> kallocator (kallocator &&) noexcept {}
+
+    T *allocate(uint32_t count) {
+        return (T*)kalloc_impl(sizeof(T) * count);
+    }
+
+    void deallocate (T* p, uint32_t) {
+        kfree(p);
+    }
+};
+
 #endif
 
diff --git a/kernel/include/stdint.hpp b/kernel/include/stdint.hpp
index a3e534d..aaf4c5f 100644
--- a/kernel/include/stdint.hpp
+++ b/kernel/include/stdint.hpp
@@ -1,3 +1,7 @@
+
+#include <stdint.h>
+#define ROS_KERN_STDINT_HPP
+
 #ifndef ROS_KERN_STDINT_HPP
 #define ROS_KERN_STDINT_HPP
 
diff --git a/kernel/include/stdlib.hpp b/kernel/include/stdlib.hpp
index dfeffc2..d08db89 100644
--- a/kernel/include/stdlib.hpp
+++ b/kernel/include/stdlib.hpp
@@ -3,14 +3,18 @@
 
 #include "stdint.hpp"
 
+#ifndef NULL
+#define NULL 0
+#endif
+
 template <typename T>
-inline void memcpy(T *dst, const T *src, size_t count) {
+inline void memcpy(T *dst, const T *src, uint32_t count) {
     for(auto i = 0; i < count; ++i) {
         dst[i] = src[i];
     }
 }
 template <typename T>
-inline void memset(T *dst, const T &data_to_set, size_t count) {
+inline void memset(T *dst, const T &data_to_set, uint32_t count) {
     char *cdst = reinterpret_cast<char *>(dst);
 
     for(auto i = 0; i < count; ++i) {
@@ -19,4 +23,5 @@ inline void memset(T *dst, const T &data_to_set, size_t count) {
 }
 
 
+
 #endif
diff --git a/kernel/include/vga.hpp b/kernel/include/vga.hpp
index ffb9f25..a985ba1 100644
--- a/kernel/include/vga.hpp
+++ b/kernel/include/vga.hpp
@@ -24,7 +24,7 @@ inline void set_char(uint16_t x, uint16_t y, char c, char color) {
     VGA_BEGIN_ADDR[y*VGA_WIDTH + x] = VGA_MAKE_CHAR(c, color);
 }
 
-inline void put_char(char c, uint8_t color) {
+inline void print_char(char c, uint8_t color = default_color) {
     static uint16_t pos = 0;
     if(pos >= VGA_WIDTH * VGA_HEIGHT)
         trigger_scroll(&pos);
@@ -43,7 +43,7 @@ inline void put_char(char c, uint8_t color) {
 
 inline void print(const char *cstr, uint8_t color = default_color) {
     while(*cstr != '\0') {
-        put_char(*(cstr++), color);
+        print_char(*(cstr++), color);
     }
 }
 
diff --git a/kernel/kernel.cc b/kernel/kernel.cc
index 3fe8438..47fdb41 100644
--- a/kernel/kernel.cc
+++ b/kernel/kernel.cc
@@ -4,6 +4,8 @@
 #include "include/bus_io.hpp"
 #include "include/kutils.hpp"
 
+#include <string>
+
 void test_dummy_function() {
     auto tmp = read_byte_from_bus(0x3f2);
     tmp |= 0x08;
@@ -15,11 +17,23 @@ void kernel_init() {
 }
 
 void main() {
+    kernel_init();
+
     clear_screen();
     print("Hello world!\n");
     print("Hello world!\n", 0xb1);
     print("Hello world!\n", 0xae);
     print("Hello world!\n", 0x5c);
     print("Hello world! This is recolic's test message, \n");
+
+    // std::array<uint32_t, 32> test_buf;
+    // uint32_t * test_buf = (uint32_t *)kalloc_impl(sizeof(uint32_t) * 32);
+    // for(auto i = 0; i < 32; ++i) {
+    //     test_buf[i] = i == 0 ? 1 : test_buf[i-1]*2+1;
+    //     print_char('0' + test_buf[i], default_color);
+    // }
+    // std::string s = "cxxhello world";
+    std::basic_string<char, std::char_traits<char>, kallocator<char>> s = "cxx hello world";
+    print(s.c_str());
 }
 
-- 
GitLab