diff --git a/kernel/Makefile b/kernel/Makefile index ade032a26b628ff58207cb864de8b97719fcaaa3..6796ba7ab52a407b92b22f49f10333f657133218 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 9a8932e9892a7e1ade93641b32aa670eefbf5020..7d1c98321a0e42017da92cb5ac38841a5ce713e2 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 a3e534df8f31dee6173945442107bca5d036bf68..aaf4c5f12f2adaa58308acd14c778eba497c45f1 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 dfeffc2827eafaa4aa5d5cfc80ecea0066e6622c..d08db89e95ed18fe1a3e9e4c8546d30d195f9374 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 ffb9f25fc7249da41f5f5fcf35c6fbd9a6fc161e..a985ba11e1483a2881433ed40c21748f9ec7adff 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 3fe843826534ca35677e932b3a6c262ed281a400..47fdb4141d3eea154f5a2d0c035c12b5fd0e1958 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()); }