Переглянути джерело

Merge branch 'memory' into dev

greatbridf 2 роки тому
батько
коміт
3f9c17ee90

+ 1 - 4
CMakeLists.txt

@@ -29,14 +29,13 @@ add_subdirectory(gblibc)
 add_subdirectory(user-space-program)
 
 set(BOOTLOADER_SOURCES src/boot.s
-                       src/asm/a20.s
                        src/asm/interrupt.s
                        src/asm/port_io.s
                        src/asm/sys.s
                        )
 
 set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
-                        src/kernel_main.cpp
+                        src/kinit.cpp
                         src/kernel/errno.c
                         src/kernel/interrupt.cpp
                         src/kernel/process.cpp
@@ -53,7 +52,6 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/types/bitmap.c
                         src/types/elf.cpp
                         src/types/libstdcpp.cpp
-                        include/asm/boot.h
                         include/asm/port_io.h
                         include/asm/sys.h
                         include/fs/fat.hpp
@@ -92,7 +90,6 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/vector.hpp
                         include/types/function.hpp
                         include/kernel/log.hpp
-                        include/kernel_main.hpp
                         )
 
 add_executable(kernel.out ${KERNEL_MAIN_SOURCES} ${BOOTLOADER_SOURCES})

+ 0 - 24
include/asm/boot.h

@@ -1,24 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-
-#define KERNEL_EARLY_STACK_ADDR ((phys_ptr_t)0x01000000)
-#define KERNEL_EARLY_STACK_SIZE ((size_t)0x100000)
-
-struct __attribute__((__packed__)) gdt_descriptor {
-    uint16_t size;
-    uint32_t address;
-};
-
-extern struct gdt_descriptor asm_gdt_descriptor;
-
-extern struct mem_size_info asm_mem_size_info;
-
-extern uint8_t asm_e820_mem_map[1024];
-extern uint32_t asm_e820_mem_map_count;
-extern uint32_t asm_e820_mem_map_entry_size;
-
-extern uint32_t asm_kernel_size;
-
-extern uint32_t bss_section_start_addr;
-extern uint32_t bss_section_end_addr;

+ 4 - 2
include/asm/sys.h

@@ -7,7 +7,7 @@
 extern "C" {
 #endif
 
-void asm_switch_pd(pd_t pd_addr);
+void asm_switch_pd(page_t pd_addr);
 void asm_enable_paging(pd_t pd_addr);
 
 pptr_t current_pd(void);
@@ -18,7 +18,9 @@ void asm_load_gdt(uint32_t limit, pptr_t addr);
 
 void asm_load_tr(uint16_t index);
 
-extern void* __real_kernel_end;
+extern const uint32_t kernel_size;
+extern char* const bss_addr;
+extern const uint32_t bss_len;
 
 #ifdef __cplusplus
 }

+ 4 - 1
include/kernel/errno.h

@@ -1,4 +1,5 @@
-#pragma once
+#ifndef __GBOS_ERRNO_H
+#define __GBOS_ERRNO_H
 
 #include <types/types.h>
 
@@ -22,3 +23,5 @@ extern uint32_t* _get_errno(void);
 #define ENOTDIR (1 << 5)
 #define ENOTFOUND (1 << 6)
 #define ECHILD (1 << 7)
+
+#endif

+ 8 - 15
include/kernel/mem.h

@@ -3,8 +3,7 @@
 #include <stdint.h>
 #include <types/size.h>
 
-#define PAGE_SIZE (4096)
-#define KERNEL_IDENTICALLY_MAPPED_AREA_LIMIT ((void*)0x30000000)
+#define PAGE_SIZE (0x1000)
 
 #ifdef __cplusplus
 extern "C" {
@@ -89,25 +88,16 @@ typedef union pte_t {
 } pte_t;
 typedef pte_t (*pt_t)[1024];
 
-// in kernel_main.c
+// in mem.cpp
 extern uint8_t e820_mem_map[1024];
 extern uint32_t e820_mem_map_count;
 extern uint32_t e820_mem_map_entry_size;
-extern size_t kernel_size;
 extern struct mem_size_info mem_size_info;
 
-#define KERNEL_HEAP_START ((void*)0x30000000)
-#define KERNEL_HEAP_LIMIT ((void*)0x40000000)
+#define KERNEL_HEAP_START ((void*)0xd0000000)
+#define KERNEL_HEAP_LIMIT ((void*)0xd4000000)
 
-void* k_malloc(size_t size);
-
-void k_free(void* ptr);
-
-void* ki_malloc(size_t size);
-
-void ki_free(void* ptr);
-
-#define KERNEL_PAGE_DIRECTORY_ADDR ((pd_t)0x00001000)
+#define EARLY_KERNEL_PD_PAGE ((page_t)0x000001)
 
 void init_mem(void);
 
@@ -136,6 +126,9 @@ typedef struct segment_descriptor_struct {
     uint64_t base_high : 8;
 } segment_descriptor;
 
+// in mem.cpp
+extern segment_descriptor gdt[6];
+
 void create_segment_descriptor(
     segment_descriptor* sd,
     uint32_t base,

+ 120 - 105
include/kernel/mm.hpp

@@ -20,8 +20,10 @@ constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
 
 struct page {
     page_t phys_page_id;
-    pte_t* pte;
     size_t* ref_count;
+    // 0 :11 : pte_index
+    // 12:31 : pt_page
+    uint32_t pg_pteidx;
     union {
         uint32_t v;
         struct {
@@ -46,17 +48,6 @@ int mmap(
 
 using page_arr = types::vector<page, types::kernel_ident_allocator>;
 
-// allocate n raw page(s)
-// @return the id of the first page allocated
-page_t alloc_n_raw_pages(size_t n);
-void free_n_raw_pages(page_t start_pg, size_t n);
-
-pd_t alloc_pd(void);
-pt_t alloc_pt(void);
-
-void dealloc_pd(pd_t pd);
-void dealloc_pt(pt_t pt);
-
 // forward declaration
 namespace kernel {
 class mm_list;
@@ -86,6 +77,17 @@ inline constexpr uint32_t align_up(uint32_t v)
     return align_down<n>(v + pow<2, n>() - 1);
 }
 
+void dealloc_pd(page_t pd);
+
+// allocate a struct page together with the raw page
+page allocate_page(void);
+void free_page(page* pg);
+
+// TODO: this is for alloc_kstack()
+// CHANGE THIS
+page_t __alloc_raw_page(void);
+void __free_raw_page(page_t pg);
+
 struct mm {
 public:
     void* start;
@@ -108,9 +110,9 @@ public:
         return (char*)this->start + this->pgs->size() * PAGE_SIZE;
     }
 
-    inline bool is_ident(void) const
+    inline bool is_kernel_space(void) const
     {
-        return this->end() <= (void*)0x40000000U;
+        return this->start >= (void*)0xc0000000;
     }
 
     constexpr bool is_avail(void* start, void* end) const
@@ -126,6 +128,34 @@ public:
 
 namespace kernel {
 
+uint8_t* pmap(page_t pg);
+void pfree(page_t pg);
+
+class paccess : public types::non_copyable {
+private:
+    page_t m_pg;
+    void* m_ptr;
+
+public:
+    paccess(void) = delete;
+    paccess(paccess&&) = delete;
+    paccess& operator=(paccess&&) = delete;
+
+    constexpr explicit paccess(page_t pg)
+        : m_pg(pg)
+    {
+        m_ptr = pmap(pg);
+    }
+    constexpr void* ptr(void) const
+    {
+        return m_ptr;
+    }
+    ~paccess()
+    {
+        pfree(m_pg);
+    }
+};
+
 class mm_list {
 public:
     using list_type = ::types::list<mm, types::kernel_ident_allocator>;
@@ -136,10 +166,10 @@ private:
     list_type m_areas;
 
 public:
-    pd_t m_pd;
+    page_t m_pd;
 
 public:
-    explicit constexpr mm_list(pd_t pd)
+    explicit constexpr mm_list(page_t pd)
         : m_pd(pd)
     {
     }
@@ -148,7 +178,7 @@ public:
         : m_areas(::types::move(v.m_areas))
         , m_pd(v.m_pd)
     {
-        v.m_pd = nullptr;
+        v.m_pd = 0;
     }
     ~mm_list()
     {
@@ -203,7 +233,7 @@ public:
     constexpr void clear_user()
     {
         for (auto iter = this->begin(); iter != this->end();) {
-            if (iter->is_ident()) {
+            if (iter->is_kernel_space()) {
                 ++iter;
                 continue;
             }
@@ -237,7 +267,7 @@ public:
         return GB_OK;
     }
 
-    constexpr void unmap(iterator_type area)
+    inline void unmap(iterator_type area)
     {
         int i = 0;
 
@@ -247,16 +277,13 @@ public:
         // bool should_invlpg = (area->pgs->size() > 4);
 
         for (auto& pg : *area->pgs) {
-            if (*pg.ref_count == 1) {
-                ki_free(pg.ref_count);
-                free_n_raw_pages(pg.phys_page_id, 1);
-            } else {
-                --*pg.ref_count;
-            }
+            kernel::paccess pa(pg.pg_pteidx >> 12);
+            auto pt = (pt_t)pa.ptr();
+            assert(pt);
+            auto* pte = *pt + (pg.pg_pteidx & 0xfff);
+            pte->v = 0;
 
-            pg.phys_page_id = 0;
-            pg.attr.v = 0;
-            pg.pte->v = 0;
+            free_page(&pg);
 
             invalidate_tlb((uint32_t)area->start + (i++) * PAGE_SIZE);
         }
@@ -295,88 +322,76 @@ inline kernel::mm_list* kernel_mms;
 inline page empty_page;
 // --------------------------------
 
-// translate physical address to virtual(mapped) address
-void* ptovp(pptr_t p_ptr);
-
 inline constexpr size_t vptrdiff(void* p1, void* p2)
 {
     return (uint8_t*)p1 - (uint8_t*)p2;
 }
-inline constexpr page* lto_page(mm* mm_area, void* l_ptr)
+// inline constexpr page* lto_page(mm* mm_area, void* l_ptr)
+// {
+//     size_t offset = vptrdiff(l_ptr, mm_area->start);
+//     return &mm_area->pgs->at(offset / PAGE_SIZE);
+// }
+// inline constexpr page_t to_page(pptr_t ptr)
+// {
+//     return ptr >> 12;
+// }
+// inline constexpr size_t to_pdi(page_t pg)
+// {
+//     return pg >> 10;
+// }
+// inline constexpr size_t to_pti(page_t pg)
+// {
+//     return pg & (1024 - 1);
+// }
+// inline constexpr pptr_t to_pp(page_t p)
+// {
+//     return p << 12;
+// }
+inline size_t v_to_pdi(void* addr)
 {
-    size_t offset = vptrdiff(l_ptr, mm_area->start);
-    return &mm_area->pgs->at(offset / PAGE_SIZE);
+    return (uint32_t)addr >> 22;
 }
-inline constexpr page_t to_page(pptr_t ptr)
+inline size_t v_to_pti(void* addr)
 {
-    return ptr >> 12;
+    return ((uint32_t)addr >> 12) & 0x3ff;
 }
-inline constexpr size_t to_pdi(page_t pg)
-{
-    return pg >> 10;
-}
-inline constexpr size_t to_pti(page_t pg)
-{
-    return pg & (1024 - 1);
-}
-inline constexpr pptr_t to_pp(page_t p)
-{
-    return p << 12;
-}
-inline constexpr size_t lto_pdi(pptr_t ptr)
-{
-    return to_pdi(to_page(ptr));
-}
-inline constexpr size_t lto_pti(pptr_t ptr)
-{
-    return to_pti(to_page(ptr));
-}
-inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
-{
-    return *pt + to_pti(pg);
-}
-inline void* to_vp(page_t pg)
-{
-    return ptovp(to_pp(pg));
-}
-inline pd_t to_pd(page_t pg)
-{
-    return reinterpret_cast<pd_t>(to_vp(pg));
-}
-inline pt_t to_pt(page_t pg)
-{
-    return reinterpret_cast<pt_t>(to_vp(pg));
-}
-inline pt_t to_pt(pde_t* pde)
-{
-    return to_pt(pde->in.pt_page);
-}
-inline pde_t* to_pde(pd_t pd, void* addr)
-{
-    return *pd + lto_pdi((pptr_t)addr);
-}
-inline pte_t* to_pte(pt_t pt, void* addr)
-{
-    return *pt + lto_pti((pptr_t)addr);
-}
-inline pte_t* to_pte(pde_t* pde, void* addr)
-{
-    return to_pte(to_pt(pde), addr);
-}
-inline pte_t* to_pte(pd_t pd, void* addr)
-{
-    return to_pte(to_pde(pd, addr), addr);
-}
-inline pte_t* to_pte(pde_t* pde, page_t pg)
-{
-    return to_pte(to_pt(pde), pg);
-}
-
-// allocate a raw page
-inline page_t alloc_raw_page(void)
-{
-    return alloc_n_raw_pages(1);
-}
-
-// allocate a struct page together with the raw page
-struct page allocate_page(void);
+// inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
+// {
+//     return *pt + to_pti(pg);
+// }
+// inline void* to_vp(page_t pg)
+// {
+//     return ptovp(to_pp(pg));
+// }
+// inline pd_t to_pd(page_t pg)
+// {
+//     return reinterpret_cast<pd_t>(to_vp(pg));
+// }
+// inline pt_t to_pt(page_t pg)
+// {
+//     return reinterpret_cast<pt_t>(to_vp(pg));
+// }
+// inline pt_t to_pt(pde_t* pde)
+// {
+//     return to_pt(pde->in.pt_page);
+// }
+// inline pde_t* to_pde(pd_t pd, void* addr)
+// {
+//     return *pd + lto_pdi((pptr_t)addr);
+// }
+// inline pte_t* to_pte(pt_t pt, void* addr)
+// {
+//     return *pt + lto_pti((pptr_t)addr);
+// }
+// inline pte_t* to_pte(pde_t* pde, void* addr)
+// {
+//     return to_pte(to_pt(pde), addr);
+// }
+// inline pte_t* to_pte(pd_t pd, void* addr)
+// {
+//     return to_pte(to_pde(pd, addr), addr);
+// }
+// inline pte_t* to_pte(pde_t* pde, page_t pg)
+// {
+//     return to_pte(to_pt(pde), pg);
+// }

+ 11 - 16
include/kernel/process.hpp

@@ -31,6 +31,8 @@ inline thread* volatile current_thread;
 inline proclist* procs;
 inline readyqueue* readythds;
 
+inline tss32_t tss;
+
 struct process_attr {
     uint16_t system : 1;
     uint16_t zombie : 1 = 0;
@@ -44,17 +46,12 @@ struct thread_attr {
 
 struct thread {
 private:
-    inline void alloc_kstack(void)
-    {
-        // TODO: alloc low mem
-        kstack = to_pp(alloc_n_raw_pages(2));
-        kstack += THREAD_KERNEL_STACK_SIZE;
-        esp = reinterpret_cast<uint32_t*>(kstack);
-    }
+    void alloc_kstack(void);
+    void free_kstack(uint32_t p);
 
 public:
     uint32_t* esp;
-    pptr_t kstack;
+    uint32_t pkstack;
     process* owner;
     thread_attr attr;
 
@@ -71,13 +68,13 @@ public:
 
     constexpr thread(thread&& val)
         : esp { val.esp }
-        , kstack { val.kstack }
+        , pkstack { val.pkstack }
         , owner { val.owner }
         , attr { val.attr }
     {
         val.attr = {};
         val.esp = 0;
-        val.kstack = 0;
+        val.pkstack = 0;
         val.owner = nullptr;
     }
 
@@ -96,8 +93,8 @@ public:
 
     constexpr ~thread()
     {
-        if (kstack)
-            free_n_raw_pages(to_page(kstack - THREAD_KERNEL_STACK_SIZE), 2);
+        if (pkstack)
+            free_kstack(pkstack);
     }
 };
 
@@ -122,9 +119,7 @@ public:
             thd.owner = new_parent;
     }
 
-    explicit constexpr thdlist(void)
-    {
-    }
+    explicit constexpr thdlist(void) = default;
 
     // implementation is below
     constexpr ~thdlist();
@@ -161,7 +156,7 @@ public:
     public:
         inline static void init_global_file_container(void)
         {
-            files = types::pnew<types::kernel_allocator>(files);
+            files = new container_type;
         }
 
     private:

+ 0 - 10
include/kernel_main.hpp

@@ -1,10 +0,0 @@
-#pragma once
-#include <types/types.h>
-
-#define KERNEL_STACK_SIZE (16 * 1024)
-#define KERNEL_STACK_SEGMENT (0x10)
-
-#define KERNEL_START_ADDR (0x00100000)
-
-// in kernel_main.cpp
-extern struct tss32_t tss;

+ 186 - 18
include/types/allocator.hpp

@@ -1,5 +1,5 @@
 #pragma once
-#include <kernel/mem.h>
+#include <assert.h>
 #include <stdint.h>
 #include <types/cplusplus.hpp>
 #include <types/types.h>
@@ -11,6 +11,160 @@ constexpr void* operator new(size_t, void* ptr)
 
 namespace types {
 
+namespace __allocator {
+    class brk_memory_allocator {
+    public:
+        using byte = uint8_t;
+        using size_type = size_t;
+
+        struct mem_blk_flags {
+            uint8_t is_free;
+            uint8_t has_next;
+            uint8_t _unused2;
+            uint8_t _unused3;
+        };
+
+        struct mem_blk {
+            size_t size;
+            struct mem_blk_flags flags;
+            // the first byte of the memory space
+            // the minimal allocated space is 4 bytes
+            uint8_t data[4];
+        };
+
+    private:
+        byte* p_start;
+        byte* p_break;
+        byte* p_limit;
+
+        brk_memory_allocator(void) = delete;
+        brk_memory_allocator(const brk_memory_allocator&) = delete;
+        brk_memory_allocator(brk_memory_allocator&&) = delete;
+
+        constexpr int brk(byte* addr)
+        {
+            if (unlikely(addr >= p_limit))
+                return GB_FAILED;
+            p_break = addr;
+            return GB_OK;
+        }
+
+        // sets errno
+        inline byte* sbrk(size_type increment)
+        {
+            if (unlikely(brk(p_break + increment) != GB_OK))
+                return nullptr;
+            else
+                return p_break;
+        }
+
+        inline mem_blk* _find_next_mem_blk(mem_blk* blk, size_type blk_size)
+        {
+            byte* p = (byte*)blk;
+            p += sizeof(mem_blk);
+            p += blk_size;
+            p -= (4 * sizeof(byte));
+            return (mem_blk*)p;
+        }
+
+        // sets errno
+        // @param start_pos position where to start finding
+        // @param size the size of the block we're looking for
+        // @return found block if suitable block exists, if not, the last block
+        inline mem_blk* find_blk(mem_blk* start_pos, size_type size)
+        {
+            while (1) {
+                if (start_pos->flags.is_free && start_pos->size >= size) {
+                    return start_pos;
+                } else {
+                    if (unlikely(!start_pos->flags.has_next))
+                        return start_pos;
+
+                    start_pos = _find_next_mem_blk(start_pos, start_pos->size);
+                }
+            }
+        }
+
+        inline mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
+        {
+            auto ret = sbrk(sizeof(mem_blk) + size - 4 * sizeof(byte));
+            if (!ret)
+                return nullptr;
+
+            mem_blk* blk = _find_next_mem_blk(blk_before, blk_before->size);
+
+            blk_before->flags.has_next = 1;
+
+            blk->flags.has_next = 0;
+            blk->flags.is_free = 1;
+            blk->size = size;
+
+            return blk;
+        }
+
+        inline void split_block(mem_blk* blk, size_type this_size)
+        {
+            // block is too small to get split
+            if (blk->size < sizeof(mem_blk) + this_size) {
+                return;
+            }
+
+            mem_blk* blk_next = _find_next_mem_blk(blk, this_size);
+
+            blk_next->size = blk->size
+                - this_size
+                - sizeof(mem_blk)
+                + 4 * sizeof(byte);
+
+            blk_next->flags.has_next = blk->flags.has_next;
+            blk_next->flags.is_free = 1;
+
+            blk->flags.has_next = 1;
+            blk->size = this_size;
+        }
+
+    public:
+        inline brk_memory_allocator(byte* start, size_type limit)
+            : p_start(start)
+            , p_limit(p_start + limit)
+        {
+            brk(p_start);
+            mem_blk* p_blk = (mem_blk*)sbrk(0);
+            p_blk->size = 4;
+            p_blk->flags.has_next = 0;
+            p_blk->flags.is_free = 1;
+        }
+
+        // sets errno
+        inline void* alloc(size_type size)
+        {
+            struct mem_blk* block_allocated;
+
+            block_allocated = find_blk((mem_blk*)p_start, size);
+            if (!block_allocated->flags.has_next
+                && (!block_allocated->flags.is_free || block_allocated->size < size)) {
+                // 'block_allocated' in the argument list is the pointer
+                // pointing to the last block
+                block_allocated = allocate_new_block(block_allocated, size);
+                if (!block_allocated)
+                    return nullptr;
+            } else {
+                split_block(block_allocated, size);
+            }
+
+            block_allocated->flags.is_free = 0;
+            return block_allocated->data;
+        }
+
+        inline void free(void* ptr)
+        {
+            mem_blk* blk = (mem_blk*)((byte*)ptr - (sizeof(mem_blk_flags) + sizeof(size_t)));
+            blk->flags.is_free = 1;
+            // TODO: fusion free blocks nearby
+        }
+    };
+}; // namespace __allocator
+
 template <typename T>
 concept Allocator = requires(size_t size, typename T::value_type* ptr)
 {
@@ -26,21 +180,11 @@ concept Allocator = requires(size_t size, typename T::value_type* ptr)
 template <Allocator T>
 class allocator_traits;
 
-template <typename T>
-class kernel_allocator {
-public:
-    using value_type = T;
-
-    static constexpr value_type* allocate_memory(size_t count)
-    {
-        return static_cast<value_type*>(::k_malloc(count));
-    }
-
-    static constexpr void deallocate_memory(value_type* ptr)
-    {
-        ::k_free(ptr);
-    }
-};
+namespace __allocator {
+    inline char __ident_heap[0x100000];
+    inline __allocator::brk_memory_allocator
+        m_alloc { (uint8_t*)__ident_heap, sizeof(__ident_heap) };
+} // namespace __allocator
 
 template <typename T>
 class kernel_ident_allocator {
@@ -49,12 +193,12 @@ public:
 
     static constexpr value_type* allocate_memory(size_t count)
     {
-        return static_cast<value_type*>(::ki_malloc(count));
+        return static_cast<value_type*>(__allocator::m_alloc.alloc(count));
     }
 
     static constexpr void deallocate_memory(value_type* ptr)
     {
-        ::ki_free(ptr);
+        __allocator::m_alloc.free(ptr);
     }
 };
 
@@ -125,4 +269,28 @@ public:
         deallocate(ptr);
     }
 };
+
+namespace __allocator {
+    inline __allocator::brk_memory_allocator* m_palloc;
+    inline void init_kernel_heap(void* start, size_t sz)
+    {
+        m_palloc = pnew<kernel_ident_allocator>(m_palloc, (uint8_t*)start, sz);
+    }
+} // namespace __allocator
+
+template <typename T>
+class kernel_allocator {
+public:
+    using value_type = T;
+
+    static constexpr value_type* allocate_memory(size_t count)
+    {
+        return static_cast<value_type*>(__allocator::m_palloc->alloc(count));
+    }
+
+    static constexpr void deallocate_memory(value_type* ptr)
+    {
+        __allocator::m_palloc->free(ptr);
+    }
+};
 } // namespace types

+ 3 - 3
include/types/bitmap.h

@@ -6,9 +6,9 @@
 extern "C" {
 #endif
 
-int bm_test(char* bm, size_t n);
-void bm_set(char* bm, size_t n);
-void bm_clear(char* bm, size_t n);
+int bm_test(uint8_t* bm, size_t n);
+void bm_set(uint8_t* bm, size_t n);
+void bm_clear(uint8_t* bm, size_t n);
 
 #ifdef __cplusplus
 }

+ 1 - 1
include/types/elf.hpp

@@ -14,7 +14,7 @@ using elf32_off_t = uint32_t;
 using elf_addr_t = elf32_addr_t;
 using elf_off_t = elf32_off_t;
 
-constexpr elf32_addr_t ELF_STACK_BOTTOM = 0xfffff000;
+constexpr elf32_addr_t ELF_STACK_BOTTOM = 0xbffff000;
 constexpr elf32_off_t ELF_STACK_SIZE = 8 * 1024 * 1024;
 constexpr elf32_addr_t ELF_STACK_TOP = ELF_STACK_BOTTOM - ELF_STACK_SIZE;
 

+ 6 - 2
include/types/list.hpp

@@ -313,7 +313,9 @@ public:
 
     constexpr iterator_type begin() noexcept
     {
-        return iterator_type(head->next);
+        if (head)
+            return iterator_type(head->next);
+        return end();
     }
 
     constexpr iterator_type end() noexcept
@@ -323,7 +325,9 @@ public:
 
     constexpr const_iterator_type begin() const noexcept
     {
-        return const_iterator_type(head->next);
+        if (head)
+            return const_iterator_type(head->next);
+        return end();
     }
 
     constexpr const_iterator_type end() const noexcept

+ 1 - 1
include/types/size.h

@@ -19,4 +19,4 @@ typedef int64_t diff_t;
 #endif
 
 typedef ptr_t pptr_t;
-typedef size_t page_t;
+typedef ssize_t page_t;

+ 1 - 0
include/types/vector.hpp

@@ -173,6 +173,7 @@ public:
     constexpr void resize(size_type n)
     {
         value_type* new_ptr = allocator_traits<allocator_type>::allocate(n);
+        assert(!n || (n && new_ptr));
 
         m_capacity = n;
         size_t orig_size = m_size;

+ 0 - 30
src/asm/a20.s

@@ -1,30 +0,0 @@
-.text
-
-.globl check_a20_on
-.type  check_a20_on @function
-
-check_a20_on:
-    pushal
-    movl $0x112345, %edi
-    movl $0x012345, %esi
-
-    movl (%esi), %eax
-    movl (%edi), %ecx
-
-    movl %esi, (%esi)
-    movl %edi, (%edi)
-    cmpsl
-
-    subl $4, %esi
-    subl $4, %edi
-
-    movl %eax, (%esi)
-    movl %ecx, (%edi)
-
-    popal
-    jne a20_on
-    movl $0, %eax
-    ret
-a20_on:
-    movl $1, %eax
-    ret

+ 14 - 12
src/asm/interrupt.s

@@ -182,18 +182,6 @@ irq15:
     popal
     iret
 
-.globl asm_load_idt
-.type  asm_load_idt @function
-asm_load_idt:
-    movl 4(%esp), %edx
-    lidt (%edx)
-    movl 8(%esp), %edx
-    cmpl $0, %edx
-    je asm_load_idt_skip
-    sti
-asm_load_idt_skip:
-    ret
-
 .globl syscall_stub
 .type  syscall_stub @function
 syscall_stub:
@@ -251,3 +239,17 @@ asm_ctx_switch:
 
 _ctx_switch_return:
     ret
+
+.section .text.kinit
+
+.globl asm_load_idt
+.type  asm_load_idt @function
+asm_load_idt:
+    movl 4(%esp), %edx
+    lidt (%edx)
+    movl 8(%esp), %edx
+    cmpl $0, %edx
+    je asm_load_idt_skip
+    sti
+asm_load_idt_skip:
+    ret

+ 1 - 0
src/asm/port_io.s

@@ -41,6 +41,7 @@ asm_sti:
     sti
     ret
 
+.section .text.kinit
 .globl asm_enable_sse
 .type  asm_enable_sse @function
 asm_enable_sse:

+ 9 - 6
src/asm/sys.s

@@ -6,9 +6,18 @@
 .type   asm_switch_pd @function
 asm_switch_pd:
     movl 4(%esp), %eax
+    shll $12, %eax
     movl %eax, %cr3
     ret
 
+.global current_pd
+.type   current_pd @function
+current_pd:
+    movl %cr3, %eax
+    ret
+
+.section .text.kinit
+
 .global asm_enable_paging
 .type   asm_enable_paging @function
 asm_enable_paging:
@@ -24,12 +33,6 @@ asm_enable_paging:
 
     ret
 
-.global current_pd
-.type   current_pd @function
-current_pd:
-    movl %cr3, %eax
-    ret
-
 .global asm_load_gdt
 .type   asm_load_gdt @function
 asm_load_gdt:

+ 120 - 89
src/boot.s

@@ -1,4 +1,4 @@
-.section .text.loader
+.section .stage1
 .code16
 loader_start:
 # set segment registers
@@ -37,7 +37,7 @@ _get_memory_size_use_ax:
 
 _get_memory_size_error:
     xchgw %bx, %bx
-    jmp loader_halt
+    jmp __stage1_halt
 
 _e820_mem_map_load:
     addl $4, %esp
@@ -96,49 +96,117 @@ _load_gdt:
 .code32
 
 start_32bit:
-    movw $16, %ax
+    movw $0x10, %ax
     movw %ax, %ds
     movw %ax, %es
     movw %ax, %fs
     movw %ax, %gs
     movw %ax, %ss
 
-# set up early stack at 0x001000000
-    movl $0x01000000, %ebp
-    movl $0x01000000, %esp
+    movl $0, %esp
+    movl $0, %ebp
 
 setup_early_kernel_page_table:
-# set up early kernel page table
-
-# the early kernel page directory is located at physical
-# address 0x00001000, size 4k, and the empty page is at
-# 0x0000-0x0fff, so we fill the first 6KiB
+# memory map:
+# 0x0000-0x1000: empty page
+# 0x1000-0x2000: early kernel pd
+# 0x2000-0x6000: 4 pts
+# 0x6000-0x8000: early kernel stack
+# so we fill the first 8KiB with zero
     movl $0x00000000, %eax
-    movl $0x6000, %ecx
-    call _fill_zero
+    movl $0x8000, %ecx
 
-# map the first 16MiB identically
-# 0x1000-0x1fff: early kernel pd
-# 0x2000-0x5fff: pde 0 - 4
-    movl $0x00001000, %eax
-    movl $0x00002003, %ebx
-_fill_pde_loop:
-    movl %ebx, (%eax)
+_fill_zero:
+    cmpl $0, %ecx
+    jz _fill_zero_end
+    subl $4, %ecx
+    movl $0, (%eax)
     addl $4, %eax
-    addl $0x1000, %ebx
-    cmpl $0x6003, %ebx
-    jne _fill_pde_loop
-
-# then, create page tables
-    movl $0x00000003, %eax
-    movl $0x00002000, %ecx
+    jmp _fill_zero
+_fill_zero_end:
 
-_create_page_table_loop1:
-    movl %eax, (%ecx)
-    addl $4, %ecx
-    addl $0x1000, %eax
-    cmpl $0x5ffc, %ecx
-    jle _create_page_table_loop1
+# pt#0: 0x00000000 to 0x00400000
+    movl $0x00001000, %eax
+    movl $0x00002003, (%eax)
+# pt#1: 0xc0000000 to 0xc0400000
+    movl $0x00001c00, %eax
+    movl $0x00003003, (%eax)
+# pt#2: 0xff000000 to 0xff400000
+    movl $0x00001ff0, %eax
+    movl $0x00004003, (%eax)
+# pt#3: 0xffc00000 to 0xffffffff
+    movl $0x00001ffc, %eax
+    movl $0x00005003, (%eax)
+
+# map early kernel page directory to 0xff000000
+    movl $0x00004000, %eax
+    movl $0x00001003, (%eax)
+
+# map kernel pt#2 to 0xff001000
+    movl $0x00004004, %eax
+    movl $0x00004003, (%eax)
+
+# map __stage1_start ---- __kinit_end identically
+    movl $__stage1_start, %ebx
+    movl $__kinit_end, %ecx
+    movl %ebx, %edx
+    shrl $12, %edx
+    andl $0x3ff, %edx
+
+
+__map_stage1_kinit:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00002000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_stage1_kinit
+
+# map __text_start ---- __data_end to 0xc0000000
+    movl %ecx, %ebx
+    movl $__text_start, %edx
+    shrl $12, %edx
+    andl $0x3ff, %edx
+
+    movl $__data_end, %ecx
+    subl $__text_start, %ecx
+    addl %ebx, %ecx
+
+__map_kernel_space:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00003000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_kernel_space
+
+# map __data_end ---- __bss_end from 0x100000
+    movl $0x100000, %ebx
+    movl $__bss_end, %ecx
+    subl $__data_end, %ecx
+    addl %ebx, %ecx
+
+__map_kernel_bss:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00003000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_kernel_bss
+
+# map kernel stack 0xffffe000-0xffffffff
+    movl $0x6000, %ebx
+    movl $0x8000, %ecx
+    movl $0x0ffffe, %edx
+    andl $0x3ff, %edx
+
+__map_kernel_stack:
+    leal 3(%ebx), %eax
+    movl %eax, 0x00005000(, %edx, 4)
+    addl $0x1000, %ebx
+    incl %edx
+    cmpl %ebx, %ecx
+    jne __map_kernel_stack
 
 load_early_kernel_page_table:
     movl $0x00001000, %eax
@@ -149,60 +217,24 @@ load_early_kernel_page_table:
     orl $0x80010001, %eax
     movl %eax, %cr0
 
-    jmp start_move_kernel
-
-# quick call
-# %eax: address to fill
-# %ecx: byte count to fill
-_fill_zero:
-    movl %ecx, -4(%esp)
-    movl %eax, -8(%esp)
-
-_fill_zero_loop:
-    cmpl $0, %ecx
-    jz _fill_zero_end
-    subl $4, %ecx
-    movl $0, (%eax)
-    addl $4, %eax
-    jmp _fill_zero_loop
+# set stack pointer and clear stack bottom
+    movl $0xfffffff0, %esp
+    movl $0xfffffff0, %ebp
 
-_fill_zero_end:
-    movl -8(%esp), %eax
-    movl -4(%esp), %ecx
-    ret
-
-start_move_kernel:
-# move the kernel to 0x100000
-    movl $__loader_end, %eax
-    movl $__real_kernel_start, %ebx
-
-    movl $__p_kernel_text_and_data_size_addr, %ecx
-    movl (%ecx), %ecx
-    movl (%ecx), %ecx
-
-_move_kernel:
-    movl (%eax), %edx
-    movl %edx, (%ebx)
-    addl $4, %eax
-    addl $4, %ebx
-    subl $4, %ecx
-    cmpl $0, %ecx
-    jge _move_kernel
+    movl $0x00, (%esp)
+    movl $0x00, 4(%esp)
+    movl $0x00, 8(%esp)
+    movl $0x00, 12(%esp)
 
-    call kernel_main
+    call kernel_init
 
-loader_halt:
+__stage1_halt:
     hlt
-    jmp loader_halt
+    jmp __stage1_halt
 
 asm_gdt_descriptor:
     .word (5 * 8) - 1 # size
     .long asm_gdt_table  # address
-
-.globl asm_gdt_descriptor
-.type asm_gdt_descriptor @object
-.size asm_gdt_descriptor, (.-asm_gdt_descriptor)
-
 asm_gdt_table:
     .8byte 0         # null descriptor
 
@@ -238,26 +270,25 @@ asm_gdt_table:
     .byte 0b11001111 # flag and limit 16:20
     .byte 0x00       # base 24:31
 
-asm_mem_size_info:
-    .word 0x12
-    .word 0x34
-
 .globl asm_mem_size_info
 .type  asm_mem_size_info @object
 .size  asm_mem_size_info, (.-asm_mem_size_info)
+asm_mem_size_info:
+    .word 0x12
+    .word 0x34
 
-asm_e820_mem_map:
-    .space 1024
 .globl asm_e820_mem_map
 .type  asm_e820_mem_map @object
 .size  asm_e820_mem_map, (.-asm_e820_mem_map)
+asm_e820_mem_map:
+    .space 1024
 
-asm_e820_mem_map_count:
-    .long 0
 .globl asm_e820_mem_map_count
 .type  asm_e820_mem_map_count @object
-
-asm_e820_mem_map_entry_size:
+asm_e820_mem_map_count:
     .long 0
+
 .globl asm_e820_mem_map_entry_size
 .type  asm_e820_mem_map_entry_size @object
+asm_e820_mem_map_entry_size:
+    .long 0

+ 5 - 5
src/fs/fat.cpp

@@ -40,7 +40,7 @@ char* fat32::read_cluster(cluster_t no)
         ++iter->value.ref;
         return iter->value.data;
     }
-    auto* data = (char*)k_malloc(sectors_per_cluster * SECTOR_SIZE);
+    auto* data = new char[sectors_per_cluster * SECTOR_SIZE];
     _raw_read_cluster(data, no);
     buf.emplace(no,
         buf_object {
@@ -123,7 +123,7 @@ fat32::fat32(inode* _device)
     : device(_device)
     , label { 0 }
 {
-    char* buf = (char*)k_malloc(SECTOR_SIZE);
+    auto* buf = new char[SECTOR_SIZE];
     _raw_read_sector(buf, 0);
 
     auto* info = reinterpret_cast<ext_boot_sector*>(buf);
@@ -137,7 +137,7 @@ fat32::fat32(inode* _device)
     fat_copies = info->old.fat_copies;
 
     data_region_offset = reserved_sectors + fat_copies * sectors_per_fat;
-    fat = (cluster_t*)k_malloc(SECTOR_SIZE * sectors_per_fat);
+    fat = (cluster_t*)new char[SECTOR_SIZE * sectors_per_fat];
     // TODO: optimize
     for (uint32_t i = 0; i < 4; ++i)
         _raw_read_sector((char*)fat + i * SECTOR_SIZE, reserved_sectors + i);
@@ -157,7 +157,7 @@ fat32::fat32(inode* _device)
     free_clusters = fsinfo->free_clusters;
     next_free_cluster_hint = fsinfo->next_free_cluster;
 
-    k_free(buf);
+    delete[] buf;
 
     size_t _root_dir_clusters = 1;
     cluster_t next = root_dir;
@@ -173,7 +173,7 @@ fat32::fat32(inode* _device)
 
 fat32::~fat32()
 {
-    k_free(fat);
+    delete[]((char*)fat);
 }
 
 size_t fat32::inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n)

+ 77 - 26
src/kernel.ld

@@ -8,29 +8,28 @@ MEMORY
 
 SECTIONS
 {
-    .text.loader 0x7e00 : AT(0x00000000)
+    .stage1 0x8000 : AT(0x00000000)
     {
-        *(.text.loader)
-        __p_kernel_text_and_data_size_addr = .;
-        LONG(__loader_end + kernel_text_and_data_size - __real_kernel_start);
-        __loader_end = .;
+        __stage1_start = .;
+        *(.stage1)
+
+        . = ALIGN(0x1000);
+        __stage1_end = .;
     } > MEM
 
-    .text 0x100000 : AT(LOADADDR(.text.loader) + SIZEOF(.text.loader))
+    .kinit :
+        AT(LOADADDR(.stage1) + SIZEOF(.stage1))
     {
-        __real_kernel_start = .;
-        *(.text*)
-        *(.rodata*)
+        __kinit_start = .;
+        *(.text.kinit)
 
-        . = ALIGN(4);
-        kernel_text_and_data_size = .;
-        LONG(__kernel_text_and_data_end - ADDR(.text));
-        asm_kernel_size = .;
-        LONG(__real_kernel_end - ADDR(.text));
-        bss_section_start_addr = .;
-        LONG(ABSOLUTE(__bss_start));
-        bss_section_end_addr = .;
-        LONG(ABSOLUTE(__bss_end));
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        *(.rodata.kinit)
+
+        . = ALIGN(16);
 
         start_ctors = .;
         KEEP(*(.init_array));
@@ -39,25 +38,78 @@ SECTIONS
         KEEP(*(SORT_BY_INIT_PRIORITY(.ctors*)));
         end_ctors = .;
 
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        *(.data.kinit)
+
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        *(.bss.kinit)
+
+        LONG(0x00000000)
+        LONG(0x19191919)
+        LONG(0x00000000)
+
+        . = ALIGN(0x1000);
+        __kinit_end = .;
+    } > MEM
+
+    .text 0xc0000000 :
+        AT(LOADADDR(.kinit) + SIZEOF(.kinit))
+    {
+        __text_start = .;
+        *(.text)
+        *(.text*)
+
+        . = ALIGN(0x1000);
+        __text_end = .;
+    } > MEM
+
+    .rodata :
+        AT(LOADADDR(.text) + SIZEOF(.text))
+    {
+        __rodata_start = .;
+        *(.rodata)
+        *(.rodata*)
+
+        . = ALIGN(16);
+
+        bss_addr = .;
+        LONG(ABSOLUTE(__bss_start));
+        bss_len = .;
+        LONG(__bss_end - __bss_start);
+        kernel_size = .;
+        LONG(__data_end - __kinit_start);
         __stack_chk_guard = .;
         LONG(0x19198101);
 
+        . = ALIGN(0x1000);
+        __rodata_end = .;
+    } > MEM
+
+    .data :
+        AT(LOADADDR(.rodata) + SIZEOF(.rodata))
+    {
+        __data_start = .;
         *(.data)
         *(.data*)
-        __kernel_text_and_data_end = .;
+
+        . = ALIGN(0x1000);
+        __data_end = .;
     } > MEM
 
-    .bss ALIGN(0x1000) :
+    .bss :
     {
         __bss_start = .;
         *(.bss)
         *(.bss*)
-        __bss_end = ALIGN(0x1000);
-    } > MEM
 
-    .kernel_end :
-    {
-        __real_kernel_end = .;
+        . = ALIGN(0x1000);
+        __bss_end = .;
     } > MEM
 
     /* Stabs debugging sections.  */
@@ -98,7 +150,6 @@ SECTIONS
     {
         *(.fini_array*)
         *(.eh_frame*)
-        *(.text.bootsect)
         *(.note*)
     }
 }

+ 1 - 1
src/kernel/event/event.cpp

@@ -17,7 +17,7 @@ namespace event {
 ::types::list<::input_event>& input_event_queue(void)
 {
     if (!_input_event_queue) {
-        _input_event_queue = types::pnew<types::kernel_allocator>(_input_event_queue);
+        _input_event_queue = new types::list<input_event>;
     }
     return *_input_event_queue;
 }

+ 4 - 4
src/kernel/hw/ata.cpp

@@ -202,13 +202,13 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
 // data: void (*func_to_call_next)(void)
 void hw::init_ata(void)
 {
-    ata_pri = types::pnew<types::kernel_allocator>(ata_pri, ATA_PRIMARY_BUS_BASE);
+    ata_pri = new hw::ata(ATA_PRIMARY_BUS_BASE);
     if (ata_pri->identify())
         ata_pri->select(true);
 
-    ata_sec = types::pnew<types::kernel_allocator>(ata_pri, ATA_SECONDARY_BUS_BASE);
-    if (ata_pri->identify())
-        ata_pri->select(true);
+    ata_sec = new hw::ata(ATA_SECONDARY_BUS_BASE);
+    if (ata_sec->identify())
+        ata_sec->select(true);
 
     // data1: offset sectors
     // data2: limit sectors

+ 1 - 0
src/kernel/hw/serial.cpp

@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <types/status.h>
 
+SECTION(".text.kinit")
 int32_t init_serial_port(port_id_t port)
 {
     // taken from osdev.org

+ 1 - 0
src/kernel/hw/timer.c

@@ -3,6 +3,7 @@
 
 static time_t _current_ticks = 0;
 
+SECTION(".text.kinit")
 void init_pit(void)
 {
     // set interval

+ 14 - 8
src/kernel/interrupt.cpp

@@ -13,7 +13,6 @@
 #include <kernel/syscall.hpp>
 #include <kernel/vfs.hpp>
 #include <kernel/vga.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <types/size.h>
@@ -37,6 +36,7 @@ static inline void NORETURN die(regs_32& regs, ptr_t eip)
     freeze();
 }
 
+SECTION(".text.kinit")
 void init_idt()
 {
     asm_cli();
@@ -62,6 +62,7 @@ void init_idt()
     asm_load_idt(idt_descriptor, 0);
 }
 
+SECTION(".text.kinit")
 void init_pic(void)
 {
     asm_cli();
@@ -183,8 +184,11 @@ extern "C" void int14_handler(int14_data* d)
     if (unlikely(d->error_code.user && mm_area->attr.in.system))
         _int14_kill_user();
 
-    pte_t* pte = to_pte(mms->m_pd, d->l_addr);
-    page* page = lto_page(&mm_area, d->l_addr);
+    page* page = &mm_area->pgs->at(vptrdiff(d->l_addr, mm_area->start) / PAGE_SIZE);
+    kernel::paccess pa(page->pg_pteidx >> 12);
+    auto pt = (pt_t)pa.ptr();
+    assert(pt);
+    pte_t* pte = *pt + (page->pg_pteidx & 0xfff);
 
     if (unlikely(d->error_code.present == 0 && !mm_area->mapped_file))
         _int14_panic(d->v_eip, d->l_addr, d->error_code);
@@ -199,14 +203,17 @@ extern "C" void int14_handler(int14_data* d)
             return;
         }
         // duplicate the page
-        page_t new_page = alloc_raw_page();
+        page_t new_page = __alloc_raw_page();
 
         // memory mapped
         if (d->error_code.present == 0)
             pte->in.p = 1;
 
-        char* new_page_data = (char*)to_vp(new_page);
-        memcpy(new_page_data, to_vp(page->phys_page_id), PAGE_SIZE);
+        kernel::paccess pdst(new_page), psrc(page->phys_page_id);
+        auto* new_page_data = (char*)pdst.ptr();
+        auto* src = psrc.ptr();
+        assert(new_page_data && src);
+        memcpy(new_page_data, src, PAGE_SIZE);
 
         pte->in.page = new_page;
         pte->in.rw = mm_area->attr.in.write;
@@ -214,8 +221,7 @@ extern "C" void int14_handler(int14_data* d)
 
         --*page->ref_count;
 
-        page->ref_count = (size_t*)ki_malloc(sizeof(size_t));
-        *page->ref_count = 1;
+        page->ref_count = types::pnew<types::kernel_ident_allocator>(page->ref_count, 1);
         page->attr.in.cow = 0;
         page->phys_page_id = new_page;
 

+ 190 - 321
src/kernel/mem.cpp

@@ -1,4 +1,3 @@
-#include <asm/boot.h>
 #include <asm/port_io.h>
 #include <asm/sys.h>
 #include <assert.h>
@@ -8,7 +7,6 @@
 #include <kernel/process.hpp>
 #include <kernel/task.h>
 #include <kernel/vga.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <types/allocator.hpp>
@@ -18,221 +16,59 @@
 
 // constant values
 
-#define EMPTY_PAGE_ADDR ((pptr_t)0x0000)
-#define EMPTY_PAGE_END ((pptr_t)0x1000)
-
-#define IDENTICALLY_MAPPED_HEAP_SIZE ((size_t)0x400000)
+#define EMPTY_PAGE ((page_t)0)
 
 // ---------------------
 
 static size_t mem_size;
-static char mem_bitmap[1024 * 1024 / 8];
-
-class brk_memory_allocator {
-public:
-    using byte = uint8_t;
-    using size_type = size_t;
-
-    struct mem_blk_flags {
-        uint8_t is_free;
-        uint8_t has_next;
-        uint8_t _unused2;
-        uint8_t _unused3;
-    };
-
-    struct mem_blk {
-        size_t size;
-        struct mem_blk_flags flags;
-        // the first byte of the memory space
-        // the minimal allocated space is 4 bytes
-        uint8_t data[4];
-    };
+static uint8_t mem_bitmap[1024 * 1024 / 8];
 
-private:
-    byte* p_start;
-    byte* p_break;
-    byte* p_limit;
+// global
+segment_descriptor gdt[6];
 
-    brk_memory_allocator(void) = delete;
-    brk_memory_allocator(const brk_memory_allocator&) = delete;
-    brk_memory_allocator(brk_memory_allocator&&) = delete;
+uint8_t e820_mem_map[1024];
+uint32_t e820_mem_map_count;
+uint32_t e820_mem_map_entry_size;
+struct mem_size_info mem_size_info;
 
-    inline constexpr int brk(byte* addr)
-    {
-        if (unlikely(addr >= p_limit))
-            return GB_FAILED;
-        p_break = addr;
-        return GB_OK;
-    }
-
-    // sets errno
-    inline byte* sbrk(size_type increment)
-    {
-        if (unlikely(brk(p_break + increment) != GB_OK)) {
-            errno = ENOMEM;
-            return nullptr;
-        } else {
-            errno = 0;
-            return p_break;
-        }
-    }
-
-    inline mem_blk* _find_next_mem_blk(mem_blk* blk, size_type blk_size)
-    {
-        byte* p = (byte*)blk;
-        p += sizeof(mem_blk);
-        p += blk_size;
-        p -= (4 * sizeof(byte));
-        return (mem_blk*)p;
-    }
-
-    // sets errno
-    // @param start_pos position where to start finding
-    // @param size the size of the block we're looking for
-    // @return found block if suitable block exists, if not, the last block
-    mem_blk* find_blk(mem_blk* start_pos, size_type size)
-    {
-        while (1) {
-            if (start_pos->flags.is_free && start_pos->size >= size) {
-                errno = 0;
-                return start_pos;
-            } else {
-                if (unlikely(!start_pos->flags.has_next)) {
-                    errno = ENOTFOUND;
-                    return start_pos;
-                }
-                start_pos = _find_next_mem_blk(start_pos, start_pos->size);
-            }
-        }
-    }
-
-    // sets errno
-    mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
-    {
-        sbrk(sizeof(mem_blk) + size - 4 * sizeof(byte));
-        // preserves errno
-        if (unlikely(errno)) {
-            return nullptr;
-        }
-
-        mem_blk* blk = _find_next_mem_blk(blk_before, blk_before->size);
-
-        blk_before->flags.has_next = 1;
-
-        blk->flags.has_next = 0;
-        blk->flags.is_free = 1;
-        blk->size = size;
-
-        errno = 0;
-        return blk;
-    }
-
-    void split_block(mem_blk* blk, size_type this_size)
-    {
-        // block is too small to get split
-        if (blk->size < sizeof(mem_blk) + this_size) {
-            return;
-        }
-
-        mem_blk* blk_next = _find_next_mem_blk(blk, this_size);
-
-        blk_next->size = blk->size
-            - this_size
-            - sizeof(mem_blk)
-            + 4 * sizeof(byte);
-
-        blk_next->flags.has_next = blk->flags.has_next;
-        blk_next->flags.is_free = 1;
-
-        blk->flags.has_next = 1;
-        blk->size = this_size;
-    }
-
-public:
-    brk_memory_allocator(void* start, size_type limit)
-        : p_start((byte*)start)
-        , p_limit(p_start + limit)
-    {
-        brk(p_start);
-        mem_blk* p_blk = (mem_blk*)sbrk(0);
-        p_blk->size = 4;
-        p_blk->flags.has_next = 0;
-        p_blk->flags.is_free = 1;
-    }
-
-    // sets errno
-    void* alloc(size_type size)
-    {
-        struct mem_blk* block_allocated;
-
-        block_allocated = find_blk((mem_blk*)p_start, size);
-        if (errno == ENOTFOUND) {
-            // 'block_allocated' in the argument list is the pointer
-            // pointing to the last block
-            block_allocated = allocate_new_block(block_allocated, size);
-            if (errno) {
-                // preserves errno
-                return nullptr;
-            }
-        } else {
-            split_block(block_allocated, size);
-        }
-
-        errno = 0;
-        block_allocated->flags.is_free = 0;
-        return block_allocated->data;
-    }
-
-    void free(void* ptr)
-    {
-        mem_blk* blk = (mem_blk*)((byte*)ptr - (sizeof(mem_blk_flags) + sizeof(size_t)));
-        blk->flags.is_free = 1;
-        // TODO: fusion free blocks nearby
-    }
-};
-
-static brk_memory_allocator* kernel_heap_allocator;
-static brk_memory_allocator
-    kernel_ident_mapped_allocator((void*)bss_section_end_addr,
-        IDENTICALLY_MAPPED_HEAP_SIZE);
+void* operator new(size_t sz)
+{
+    void* ptr = types::__allocator::m_palloc->alloc(sz);
+    assert(ptr);
+    return ptr;
+}
 
-void* k_malloc(size_t size)
+void* operator new[](size_t sz)
 {
-    void* ptr = kernel_heap_allocator->alloc(size);
-    assert(likely(ptr));
+    void* ptr = types::__allocator::m_palloc->alloc(sz);
+    assert(ptr);
     return ptr;
 }
 
-void k_free(void* ptr)
+void operator delete(void* ptr)
 {
-    kernel_heap_allocator->free(ptr);
+    types::__allocator::m_palloc->free(ptr);
 }
 
-void* ki_malloc(size_t size)
+void operator delete(void* ptr, size_t)
 {
-    void* ptr = kernel_ident_mapped_allocator.alloc(size);
-    assert(likely(ptr));
-    return ptr;
+    types::__allocator::m_palloc->free(ptr);
 }
 
-void ki_free(void* ptr)
+void operator delete[](void* ptr)
 {
-    kernel_ident_mapped_allocator.free(ptr);
+    types::__allocator::m_palloc->free(ptr);
 }
 
-void* ptovp(pptr_t p_ptr)
+void operator delete[](void* ptr, size_t)
 {
-    // memory below 768MiB is identically mapped
-    // TODO: address translation for high mem
-    assert(p_ptr <= 0x30000000);
-    return (void*)p_ptr;
+    types::__allocator::m_palloc->free(ptr);
 }
 
 inline void mark_page(page_t n)
 {
     bm_set(mem_bitmap, n);
 }
-
 inline void free_page(page_t n)
 {
     bm_clear(mem_bitmap, n);
@@ -240,130 +76,113 @@ inline void free_page(page_t n)
 
 constexpr void mark_addr_len(pptr_t start, size_t n)
 {
-    if (unlikely(n == 0))
+    if (n == 0)
         return;
-    page_t start_page = to_page(start);
-    page_t end_page = to_page(start + n + 4095);
+    page_t start_page = align_down<12>(start) >> 12;
+    page_t end_page = align_up<12>(start + n) >> 12;
     for (page_t i = start_page; i < end_page; ++i)
         mark_page(i);
 }
 
 constexpr void free_addr_len(pptr_t start, size_t n)
 {
-    if (unlikely(n == 0))
+    if (n == 0)
         return;
-    page_t start_page = to_page(start);
-    page_t end_page = to_page(start + n + 4095);
+    page_t start_page = align_down<12>(start) >> 12;
+    page_t end_page = align_up<12>(start + n) >> 12;
     for (page_t i = start_page; i < end_page; ++i)
         free_page(i);
 }
 
-inline constexpr void mark_addr_range(pptr_t start, pptr_t end)
+constexpr void mark_addr_range(pptr_t start, pptr_t end)
 {
     mark_addr_len(start, end - start);
 }
 
-inline constexpr void free_addr_range(pptr_t start, pptr_t end)
+constexpr void free_addr_range(pptr_t start, pptr_t end)
 {
     free_addr_len(start, end - start);
 }
 
-// @return the max count (but less than n) of the pages continuously available
-static inline size_t _test_n_raw_pages(page_t start, size_t n)
-{
-    // *start is already allocated
-    if (bm_test(mem_bitmap, start))
-        return 0;
-
-    return 1 + ((n > 1) ? _test_n_raw_pages(start + 1, n - 1) : 0);
-}
-
-page_t alloc_n_raw_pages(size_t n)
+page_t __alloc_raw_page(void)
 {
-    page_t first = 0;
-    while (first <= 1024 * 1024 - n) {
-        size_t max = _test_n_raw_pages(first, n);
-        if (max != n) {
-            first += (max + 1);
-        } else {
-            for (page_t i = first; i < first + n; ++i)
-                mark_page(i);
-            return first;
+    for (size_t i = 0; i < sizeof(mem_bitmap); ++i) {
+        if (bm_test(mem_bitmap, i) == 0) {
+            bm_set(mem_bitmap, i);
+            return i;
         }
     }
-    assert(false);
-    return 0xffffffff;
+    return -1;
 }
 
-void free_n_raw_pages(page_t start_pg, size_t n)
+void __free_raw_page(page_t pg)
 {
-    while (n--)
-        free_page(start_pg++);
+    bm_clear(mem_bitmap, pg);
 }
 
-struct page allocate_page(void)
+page allocate_page(void)
 {
     return page {
-        .phys_page_id = alloc_raw_page(),
-        .pte = nullptr,
+        .phys_page_id = __alloc_raw_page(),
         .ref_count = types::_new<types::kernel_ident_allocator, size_t>(0),
+        .pg_pteidx = 0,
         .attr { 0 },
     };
 }
 
-pd_t alloc_pd(void)
+void free_page(page* pg)
 {
-    // TODO: alloc page in low mem and gen struct page for it
-    page_t pd_page = alloc_raw_page();
-    pd_t pd = to_pd(pd_page);
-    memset(pd, 0x00, PAGE_SIZE);
-    return pd;
-}
-
-pt_t alloc_pt(void)
-{
-    // TODO: alloc page in low mem and gen struct page for it
-    page_t pt_page = alloc_raw_page();
-    pt_t pt = to_pt(pt_page);
-    memset(pt, 0x00, PAGE_SIZE);
-    return pt;
+    if (*pg->ref_count == 1) {
+        types::pdelete<types::kernel_ident_allocator>(pg->ref_count);
+        __free_raw_page(pg->phys_page_id);
+    } else {
+        --*pg->ref_count;
+    }
 }
 
-void dealloc_pd(pd_t pd)
+void dealloc_pd(page_t pd)
 {
-    for (pde_t* ent = (*pd) + 256; ent < (*pd) + 1024; ++ent) {
-        if (!ent->in.p)
-            continue;
-        dealloc_pt(to_pt(ent));
+    {
+        kernel::paccess pa(pd);
+        auto p_pd = (pd_t)pa.ptr();
+        assert(p_pd);
+        for (pde_t* ent = (*p_pd); ent < (*p_pd) + 768; ++ent) {
+            if (!ent->in.p)
+                continue;
+            __free_raw_page(ent->in.pt_page);
+        }
     }
-    memset(pd, 0x00, sizeof(*pd));
-
-    page_t pg = to_page((pptr_t)pd);
-    free_page(pg);
-}
-void dealloc_pt(pt_t pt)
-{
-    memset(pt, 0x00, sizeof(*pt));
-
-    page_t pg = to_page((pptr_t)pt);
-    free_page(pg);
+    __free_raw_page(pd);
 }
 
+SECTION(".text.kinit")
 static inline void init_mem_layout(void)
 {
     mem_size = 1024 * mem_size_info.n_1k_blks;
     mem_size += 64 * 1024 * mem_size_info.n_64k_blks;
 
-    // mark kernel page directory
-    mark_addr_range(0x00001000, 0x00006000);
     // mark empty page
-    mark_addr_range(EMPTY_PAGE_ADDR, EMPTY_PAGE_END);
+    mark_addr_range(0x00000000, 0x00001000);
+    // mark kernel page directory
+    mark_addr_range(0x00001000, 0x00002000);
+    // mark kernel page table
+    mark_addr_range(0x00002000, 0x00006000);
+    // mark kernel early stack
+    mark_addr_range(0x00006000, 0x00008000);
     // mark EBDA and upper memory as allocated
-    mark_addr_range(0x80000, 0xfffff);
-    // mark kernel
-    mark_addr_len(0x00100000, kernel_size);
-    // mark identically mapped heap
-    mark_addr_len(bss_section_end_addr, IDENTICALLY_MAPPED_HEAP_SIZE);
+    mark_addr_range(0x80000, 0x100000);
+    extern char __stage1_start[];
+    extern char __kinit_end[];
+    extern char __text_start[];
+    extern char __data_end[];
+
+    constexpr pptr_t PHYS_BSS_START = 0x100000;
+    // mark .stage1 and .kinit
+    mark_addr_range((pptr_t)__stage1_start, (pptr_t)__kinit_end);
+    // mark kernel .text to .data
+    mark_addr_len((pptr_t)__kinit_end, __data_end - __text_start);
+    // mark kernel .bss
+    mark_addr_len(PHYS_BSS_START, bss_len);
 
     if (e820_mem_map_entry_size == 20) {
         struct e820_mem_map_entry_20* entry = (struct e820_mem_map_entry_20*)e820_mem_map;
@@ -386,9 +205,12 @@ using kernel::mm_list;
 mm_list::mm_list(const mm_list& v)
     : m_areas(v.m_areas)
 {
-    pd_t pd = alloc_pd();
-    memcpy(pd, v.m_pd, PAGE_SIZE);
-    m_pd = pd;
+    m_pd = __alloc_raw_page();
+    kernel::paccess pdst(m_pd), psrc(v.m_pd);
+    auto* dst = pdst.ptr();
+    auto* src = psrc.ptr();
+    assert(dst && src);
+    memcpy(dst, src, PAGE_SIZE);
 }
 
 inline void map_raw_page_to_pte(
@@ -409,32 +231,56 @@ inline void map_raw_page_to_pte(
 int mm::append_page(page* pg, bool present, bool write, bool priv, bool cow)
 {
     void* addr = this->end();
-    pde_t* pde = to_pde(this->owner->m_pd, addr);
+    kernel::paccess pa(this->owner->m_pd);
+    auto pd = (pd_t)pa.ptr();
+    assert(pd);
+    pde_t* pde = *pd + v_to_pdi(addr);
+
+    page_t pt_pg = 0;
+    pte_t* pte = nullptr;
     // page table not exist
     if (unlikely(!pde->in.p)) {
         // allocate a page for the page table
+        pt_pg = __alloc_raw_page();
         pde->in.p = 1;
         pde->in.rw = 1;
         pde->in.us = 1;
-        pde->in.pt_page = alloc_raw_page();
+        pde->in.pt_page = pt_pg;
+
+        auto pt = (pt_t)kernel::pmap(pt_pg);
+        assert(pt);
+        pte = *pt;
 
-        memset(to_pt(pde), 0x00, PAGE_SIZE);
+        memset(pt, 0x00, PAGE_SIZE);
+    } else {
+        pt_pg = pde->in.pt_page;
+        auto pt = (pt_t)kernel::pmap(pt_pg);
+        assert(pt);
+        pte = *pt;
     }
 
     // map the page in the page table
-    pte_t* pte = to_pte(pde, addr);
+    int pti = v_to_pti(addr);
+    pte += pti;
+
     map_raw_page_to_pte(pte, pg->phys_page_id, present, (write && !cow), priv);
 
+    kernel::pfree(pt_pg);
+
     if (unlikely(cow && !pg->attr.in.cow)) {
+        kernel::paccess pa(pg->pg_pteidx >> 12);
+        auto* pg_pte = (pte_t*)pa.ptr();
+        assert(pg_pte);
+        pg_pte += (pg->pg_pteidx & 0xfff);
         pg->attr.in.cow = 1;
-        pg->pte->in.rw = 0;
-        pg->pte->in.a = 0;
+        pg_pte->in.rw = 0;
+        pg_pte->in.a = 0;
         invalidate_tlb(addr);
     }
     ++*pg->ref_count;
 
     auto iter = this->pgs->emplace_back(*pg);
-    iter->pte = pte;
+    iter->pg_pteidx = (pt_pg << 12) + pti;
     return GB_OK;
 }
 
@@ -485,67 +331,30 @@ int mmap(
     return _mmap(&current_process->mms, hint, len, file, offset, write, priv);
 }
 
-// map a page identically
-// this function is only meant to be used in the initialization process
-// it checks the pde's P bit so you need to make sure it's already set
-// to avoid dead loops
-static inline void _init_map_page_identically(page_t page)
-{
-    pde_t* pde = *KERNEL_PAGE_DIRECTORY_ADDR + to_pdi(page);
-    // page table not exist
-    if (unlikely(!pde->in.p)) {
-        // allocate a page for the page table
-        // set the P bit of the pde in advance
-        pde->in.p = 1;
-        pde->in.rw = 1;
-        pde->in.us = 0;
-        pde->in.pt_page = alloc_raw_page();
-        _init_map_page_identically(pde->in.pt_page);
-        memset(to_pt(pde), 0x00, PAGE_SIZE);
-    }
-
-    // map the page in the page table
-    pte_t* pt = to_pte(pde, page);
-    pt->v = 0x00000003;
-    pt->in.page = page;
-}
-
-static inline void init_paging_map_low_mem_identically(void)
-{
-    for (pptr_t addr = 0x01000000; addr < 0x30000000; addr += 0x1000) {
-        // check if the address is valid and not mapped
-        if (bm_test(mem_bitmap, to_page(addr)))
-            continue;
-        _init_map_page_identically(to_page(addr));
-    }
-}
-
+SECTION(".text.kinit")
 void init_mem(void)
 {
     init_mem_layout();
 
-    // map the 16MiB-768MiB identically
-    init_paging_map_low_mem_identically();
-
-    kernel_mms = types::pnew<types::kernel_ident_allocator>(kernel_mms, KERNEL_PAGE_DIRECTORY_ADDR);
+    // TODO: replace early kernel pd
+    kernel_mms = types::pnew<types::kernel_ident_allocator>(kernel_mms, EARLY_KERNEL_PD_PAGE);
     auto heap_mm = kernel_mms->addarea(KERNEL_HEAP_START, true, true);
 
     // create empty_page struct
     empty_page.attr.in.cow = 0;
-    empty_page.phys_page_id = to_page(EMPTY_PAGE_ADDR);
+    empty_page.phys_page_id = EMPTY_PAGE;
     empty_page.ref_count = types::_new<types::kernel_ident_allocator, size_t>(1);
-    empty_page.pte = to_pte(*KERNEL_PAGE_DIRECTORY_ADDR, empty_page.phys_page_id);
-    empty_page.pte->in.rw = 0;
-    invalidate_tlb(0x00000000);
+    empty_page.pg_pteidx = 0x00002000;
 
-    // 0x30000000 to 0x40000000 or 768MiB to 1GiB
-    while (heap_mm->pgs->size() < 256 * 1024 * 1024 / PAGE_SIZE)
+    // 0xd0000000 to 0xd4000000 or 3.5GiB, size 64MiB
+    while (heap_mm->pgs->size() < 64 * 1024 * 1024 / PAGE_SIZE)
         heap_mm->append_page(&empty_page, true, true, true, true);
 
-    kernel_heap_allocator = types::pnew<types::kernel_ident_allocator>(kernel_heap_allocator,
-        KERNEL_HEAP_START, vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
+    types::__allocator::init_kernel_heap(KERNEL_HEAP_START,
+        vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
 }
 
+SECTION(".text.kinit")
 void create_segment_descriptor(
     segment_descriptor* sd,
     uint32_t base,
@@ -561,3 +370,63 @@ void create_segment_descriptor(
     sd->access = access;
     sd->flags = flags;
 }
+
+namespace __physmapper {
+struct mapped_area {
+    size_t ref;
+    uint8_t* ptr;
+};
+
+static types::hash_map<page_t, mapped_area,
+    types::linux_hasher<page_t>, types::kernel_ident_allocator>
+    mapped;
+static uint8_t freebm[0x400 / 8];
+} // namespace __physmapper
+
+uint8_t* kernel::pmap(page_t pg)
+{
+    auto iter = __physmapper::mapped.find(pg);
+    if (iter) {
+        ++iter->value.ref;
+        return iter->value.ptr;
+    }
+
+    for (int i = 2; i < 0x400; ++i) {
+        if (bm_test(__physmapper::freebm, i) == 0) {
+            auto* pte = (pte_t*)(0xff001000) + i;
+            pte->v = 0x3;
+            pte->in.page = pg;
+
+            uint8_t* ptr = (uint8_t*)0xff000000 + 0x1000 * i;
+            invalidate_tlb(ptr);
+
+            bm_set(__physmapper::freebm, i);
+            __physmapper::mapped.emplace(pg,
+                __physmapper::mapped_area { 1, ptr });
+            return ptr;
+        }
+    }
+
+    return nullptr;
+}
+void kernel::pfree(page_t pg)
+{
+    auto iter = __physmapper::mapped.find(pg);
+    if (!iter)
+        return;
+
+    if (iter->value.ref > 1) {
+        --iter->value.ref;
+        return;
+    }
+
+    int i = (uint32_t)iter->value.ptr - 0xff000000;
+    i /= 0x1000;
+
+    auto* pte = (pte_t*)(0xff001000) + i;
+    pte->v = 0;
+    invalidate_tlb(iter->value.ptr);
+
+    bm_clear(__physmapper::freebm, i);
+    __physmapper::mapped.remove(iter);
+}

+ 69 - 7
src/kernel/process.cpp

@@ -9,10 +9,10 @@
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
 #include <kernel/vfs.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <types/allocator.hpp>
+#include <types/bitmap.h>
 #include <types/cplusplus.hpp>
 #include <types/elf.hpp>
 #include <types/hash_map.hpp>
@@ -45,6 +45,49 @@ struct no_irq_guard {
 
 } // namespace kernel
 
+namespace __thd {
+inline uint8_t __kstack_bmp[(0x1000000 - 0xc00000) / 0x2000 / 8];
+inline int __allocated;
+} // namespace __thd
+
+void thread::alloc_kstack(void)
+{
+    for (int i = 0; i < __thd::__allocated; ++i) {
+        if (bm_test(__thd::__kstack_bmp, i) == 0) {
+            pkstack = 0xffc00000 + THREAD_KERNEL_STACK_SIZE * (i + 1);
+            esp = reinterpret_cast<uint32_t*>(pkstack);
+
+            bm_set(__thd::__kstack_bmp, i);
+            return;
+        }
+    }
+
+    // kernel stack pt is at page#0x00005
+    kernel::paccess pa(0x00005);
+    auto pt = (pt_t)pa.ptr();
+    assert(pt);
+    pte_t* pte = *pt + __thd::__allocated * 2;
+
+    pte[0].v = 0x3;
+    pte[0].in.page = __alloc_raw_page();
+    pte[1].v = 0x3;
+    pte[1].in.page = __alloc_raw_page();
+
+    pkstack = 0xffc00000 + THREAD_KERNEL_STACK_SIZE * (__thd::__allocated + 1);
+    esp = reinterpret_cast<uint32_t*>(pkstack);
+
+    bm_set(__thd::__kstack_bmp, __thd::__allocated);
+    ++__thd::__allocated;
+}
+
+void thread::free_kstack(uint32_t p)
+{
+    p -= 0xffc00000;
+    p /= THREAD_KERNEL_STACK_SIZE;
+    p -= 1;
+    bm_clear(__thd::__kstack_bmp, p);
+}
+
 process::process(process&& val)
     : mms(types::move(val.mms))
     , thds { types::move(val.thds), this }
@@ -68,7 +111,7 @@ process::process(const process& parent)
     : process { parent.pid, parent.is_system(), types::string<>(parent.pwd) }
 {
     for (auto& area : parent.mms) {
-        if (area.is_ident())
+        if (area.is_kernel_space() || area.attr.in.system)
             continue;
 
         mms.mirror_area(area);
@@ -193,7 +236,7 @@ void NORETURN _kernel_init(void)
     // TODO: parse kernel parameters
     auto* drive = fs::vfs_open("/dev/hda1");
     assert(drive);
-    auto* _new_fs = fs::register_fs(types::_new<types::kernel_allocator, fs::fat::fat32>(drive->ind));
+    auto* _new_fs = fs::register_fs(new fs::fat::fat32(drive->ind));
     auto* mnt = fs::vfs_open("/mnt");
     assert(mnt);
     int ret = fs::fs_root->ind->fs->mount(mnt, _new_fs);
@@ -244,8 +287,27 @@ void k_new_thread(void (*func)(void*), void* data)
 
 void NORETURN init_scheduler(void)
 {
-    procs = types::pnew<types::kernel_allocator>(procs);
-    readythds = types::pnew<types::kernel_allocator>(readythds);
+    {
+        extern char __stage1_start[];
+        extern char __kinit_end[];
+
+        kernel::paccess pa(EARLY_KERNEL_PD_PAGE);
+        auto pd = (pd_t)pa.ptr();
+        assert(pd);
+        (*pd)[0].v = 0;
+
+        // free pt#0
+        __free_raw_page(0x00002);
+
+        // free .stage1 and .kinit
+        for (uint32_t i = ((uint32_t)__stage1_start >> 12);
+             i < ((uint32_t)__kinit_end >> 12); ++i) {
+            __free_raw_page(i);
+        }
+    }
+
+    procs = new proclist;
+    readythds = new readyqueue;
 
     process::filearr::init_global_file_container();
 
@@ -262,7 +324,7 @@ void NORETURN init_scheduler(void)
     readythds->push(current_thread);
 
     tss.ss0 = KERNEL_DATA_SEGMENT;
-    tss.esp0 = current_thread->kstack;
+    tss.esp0 = current_thread->pkstack;
 
     asm_switch_pd(current_process->mms.m_pd);
 
@@ -312,7 +374,7 @@ void schedule()
     auto* curr_thd = current_thread;
 
     current_thread = thd;
-    tss.esp0 = current_thread->kstack;
+    tss.esp0 = current_thread->pkstack;
 
     asm_ctx_switch(&curr_thd->esp, thd->esp);
 }

+ 2 - 1
src/kernel/syscall.cpp

@@ -10,7 +10,6 @@
 #include <kernel/syscall.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
-#include <kernel_main.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -196,6 +195,7 @@ void _syscall_wait(interrupt_stack* data)
 {
     auto* arg1 = reinterpret_cast<int*>(data->s_regs.edi);
 
+    // TODO: check valid address
     if (arg1 < (int*)0x40000000) {
         SYSCALL_SET_RETURN_VAL(-1, EINVAL);
         return;
@@ -292,6 +292,7 @@ void _syscall_getcwd(interrupt_stack* data)
     SYSCALL_SET_RETURN_VAL_EAX(buf);
 }
 
+SECTION(".text.kinit")
 void init_syscall(void)
 {
     syscall_handlers[0] = _syscall_fork;

+ 6 - 3
src/kernel/vfs.cpp

@@ -53,8 +53,10 @@ fs::vfs::dentry::dentry(dentry&& val)
     , flags { val.flags }
     , name(types::move(val.name))
 {
-    for (auto& item : *children)
-        item.parent = this;
+    if (children) {
+        for (auto& item : *children)
+            item.parent = this;
+    }
     memset(&val, 0x00, sizeof(dentry));
 }
 fs::vfs::dentry::~dentry()
@@ -589,6 +591,7 @@ static size_t console_write(fs::special_node*, const char* buf, size_t, size_t n
     return orig_n;
 }
 
+SECTION(".text.kinit")
 void init_vfs(void)
 {
     using namespace fs;
@@ -600,7 +603,7 @@ void init_vfs(void)
 
     fs_es = types::pnew<types::kernel_ident_allocator>(fs_es);
 
-    auto* rootfs = types::_new<types::kernel_allocator, tmpfs>();
+    auto* rootfs = new tmpfs;
     fs_es->push_back(rootfs);
     fs_root = rootfs->root();
 

+ 0 - 185
src/kernel_main.cpp

@@ -1,185 +0,0 @@
-#include "kernel_main.hpp"
-
-#include <asm/boot.h>
-#include <asm/port_io.h>
-#include <asm/sys.h>
-#include <assert.h>
-#include <kernel/event/event.h>
-#include <kernel/hw/keyboard.h>
-#include <kernel/hw/serial.h>
-#include <kernel/hw/timer.h>
-#include <kernel/interrupt.h>
-#include <kernel/log.hpp>
-#include <kernel/mem.h>
-#include <kernel/process.hpp>
-#include <kernel/task.h>
-#include <kernel/tty.hpp>
-#include <kernel/vga.hpp>
-#include <stdint.h>
-#include <stdio.h>
-#include <types/bitmap.h>
-#include <types/status.h>
-#include <types/types.h>
-
-#define KERNEL_MAIN_BUF_SIZE (128)
-
-#define printkf(x...)                       \
-    snprintf(buf, KERNEL_MAIN_BUF_SIZE, x); \
-    console->print(buf)
-
-typedef void (*constructor)(void);
-extern constructor start_ctors;
-extern constructor end_ctors;
-void call_constructors_for_cpp(void)
-{
-    for (constructor* ctor = &start_ctors; ctor != &end_ctors; ++ctor) {
-        (*ctor)();
-    }
-}
-
-uint8_t e820_mem_map[1024];
-uint32_t e820_mem_map_count;
-uint32_t e820_mem_map_entry_size;
-size_t kernel_size;
-struct mem_size_info mem_size_info;
-
-static inline void save_loader_data(void)
-{
-    memcpy(e820_mem_map, asm_e820_mem_map, sizeof(e820_mem_map));
-    e820_mem_map_count = asm_e820_mem_map_count;
-    e820_mem_map_entry_size = asm_e820_mem_map_entry_size;
-    kernel_size = asm_kernel_size;
-    memcpy(&mem_size_info, &asm_mem_size_info, sizeof(struct mem_size_info));
-}
-
-static inline void show_mem_info(char* buf)
-{
-    uint32_t mem_size = 0;
-    mem_size += 1024 * mem_size_info.n_1k_blks;
-    mem_size += 64 * 1024 * mem_size_info.n_64k_blks;
-
-    printkf(
-        "Memory size: %d bytes (%d MB), 16k blocks: %d, 64k blocks: %d\n",
-        mem_size,
-        mem_size / 1024 / 1024,
-        (int32_t)mem_size_info.n_1k_blks,
-        (int32_t)mem_size_info.n_64k_blks);
-
-    printkf(
-        "mem_map_entry_count: %d , mem_map_entry_size: %d \n",
-        e820_mem_map_count,
-        e820_mem_map_entry_size);
-
-    if (e820_mem_map_entry_size == 20) {
-        struct e820_mem_map_entry_20* entry = (struct e820_mem_map_entry_20*)e820_mem_map;
-        for (uint32_t i = 0; i < e820_mem_map_count; ++i, ++entry) {
-            printkf(
-                "[mem] entry %d: %llx ~ %llx, type: %d\n",
-                i,
-                entry->base,
-                entry->base + entry->len,
-                entry->type);
-        }
-    } else {
-        struct e820_mem_map_entry_24* entry = (struct e820_mem_map_entry_24*)e820_mem_map;
-        for (uint32_t i = 0; i < e820_mem_map_count; ++i, ++entry) {
-            printkf(
-                "[mem] entry %d: %lld ~ %lld, type: %d, acpi_attr: %d\n",
-                i,
-                entry->in.base,
-                entry->in.base + entry->in.len,
-                entry->in.type,
-                entry->acpi_extension_attr);
-        }
-    }
-    printkf("kernel size: %x\n", kernel_size);
-}
-
-static segment_descriptor new_gdt[6];
-struct tss32_t tss;
-
-void load_new_gdt(void)
-{
-    create_segment_descriptor(new_gdt + 0, 0, 0, 0, 0);
-    create_segment_descriptor(new_gdt + 1, 0, ~0, 0b1100, SD_TYPE_CODE_SYSTEM);
-    create_segment_descriptor(new_gdt + 2, 0, ~0, 0b1100, SD_TYPE_DATA_SYSTEM);
-    create_segment_descriptor(new_gdt + 3, 0, ~0, 0b1100, SD_TYPE_CODE_USER);
-    create_segment_descriptor(new_gdt + 4, 0, ~0, 0b1100, SD_TYPE_DATA_USER);
-    create_segment_descriptor(new_gdt + 5, (uint32_t)&tss, sizeof(tss), 0b0000, SD_TYPE_TSS);
-
-    asm_load_gdt((6 * 8 - 1) << 16, (pptr_t)new_gdt);
-    asm_load_tr((6 - 1) * 8);
-
-    asm_cli();
-}
-
-void init_bss_section(void)
-{
-    void* bss_addr = (void*)bss_section_start_addr;
-    size_t bss_size = bss_section_end_addr - bss_section_start_addr;
-    memset(bss_addr, 0x00, bss_size);
-}
-
-int init_console(const char* name)
-{
-    if (name[0] == 't' && name[1] == 't' && name[2] == 'y') {
-        if (name[3] == 'S' || name[3] == 's') {
-            if (name[4] == '0') {
-                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL0);
-                return GB_OK;
-            }
-            if (name[4] == '1') {
-                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL1);
-                return GB_OK;
-            }
-        }
-        if (name[3] == 'V' && name[3] == 'G' && name[3] == 'A') {
-            console = types::_new<types::kernel_ident_allocator, vga_tty>();
-            return GB_OK;
-        }
-    }
-    return GB_FAILED;
-}
-
-extern void init_vfs();
-extern "C" uint32_t check_a20_on(void);
-
-extern "C" void NORETURN kernel_main(void)
-{
-    int ret;
-    ret = check_a20_on();
-    assert(ret == 1);
-
-    asm_enable_sse();
-
-    init_bss_section();
-
-    save_loader_data();
-
-    load_new_gdt();
-
-    // NOTE:
-    // the initializer of c++ global objects MUST NOT contain
-    // all kinds of memory allocations
-    call_constructors_for_cpp();
-
-    char buf[KERNEL_MAIN_BUF_SIZE] = { 0 };
-
-    ret = init_serial_port(PORT_SERIAL0);
-    assert(ret == GB_OK);
-
-    init_idt();
-    init_mem();
-    init_pic();
-    init_pit();
-
-    ret = init_console("ttyS0");
-    assert(ret == GB_OK);
-
-    show_mem_info(buf);
-
-    init_vfs();
-
-    kmsg("switching execution to the scheduler...\n");
-    init_scheduler();
-}

+ 118 - 0
src/kinit.cpp

@@ -0,0 +1,118 @@
+#include <asm/port_io.h>
+#include <asm/sys.h>
+#include <assert.h>
+#include <kernel/event/event.h>
+#include <kernel/hw/keyboard.h>
+#include <kernel/hw/serial.h>
+#include <kernel/hw/timer.h>
+#include <kernel/interrupt.h>
+#include <kernel/log.hpp>
+#include <kernel/mem.h>
+#include <kernel/process.hpp>
+#include <kernel/task.h>
+#include <kernel/tty.hpp>
+#include <kernel/vga.hpp>
+#include <stdint.h>
+#include <stdio.h>
+#include <types/bitmap.h>
+#include <types/status.h>
+#include <types/types.h>
+
+typedef void (*constructor)(void);
+extern constructor const SECTION(".rodata.kinit") start_ctors;
+extern constructor const SECTION(".rodata.kinit") end_ctors;
+
+extern struct mem_size_info SECTION(".stage1") asm_mem_size_info;
+extern uint8_t SECTION(".stage1") asm_e820_mem_map[1024];
+extern uint32_t SECTION(".stage1") asm_e820_mem_map_count;
+extern uint32_t SECTION(".stage1") asm_e820_mem_map_entry_size;
+
+SECTION(".text.kinit")
+static inline void save_loader_data(void)
+{
+    memcpy(e820_mem_map, asm_e820_mem_map, sizeof(e820_mem_map));
+    e820_mem_map_count = asm_e820_mem_map_count;
+    e820_mem_map_entry_size = asm_e820_mem_map_entry_size;
+    memcpy(&mem_size_info, &asm_mem_size_info, sizeof(struct mem_size_info));
+}
+
+SECTION(".text.kinit")
+static inline void load_new_gdt(void)
+{
+    create_segment_descriptor(gdt + 0, 0, 0, 0, 0);
+    create_segment_descriptor(gdt + 1, 0, ~0, 0b1100, SD_TYPE_CODE_SYSTEM);
+    create_segment_descriptor(gdt + 2, 0, ~0, 0b1100, SD_TYPE_DATA_SYSTEM);
+    create_segment_descriptor(gdt + 3, 0, ~0, 0b1100, SD_TYPE_CODE_USER);
+    create_segment_descriptor(gdt + 4, 0, ~0, 0b1100, SD_TYPE_DATA_USER);
+    create_segment_descriptor(gdt + 5, (uint32_t)&tss, sizeof(tss), 0b0000, SD_TYPE_TSS);
+
+    asm_load_gdt((6 * 8 - 1) << 16, (pptr_t)gdt);
+    asm_load_tr((6 - 1) * 8);
+
+    asm_cli();
+}
+
+SECTION(".text.kinit")
+static inline void init_bss_section(void)
+{
+    memset(bss_addr, 0x00, bss_len);
+}
+
+SECTION(".text.kinit")
+static inline int init_console(const char* name)
+{
+    if (name[0] == 't' && name[1] == 't' && name[2] == 'y') {
+        if (name[3] == 'S' || name[3] == 's') {
+            if (name[4] == '0') {
+                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL0);
+                return GB_OK;
+            }
+            if (name[4] == '1') {
+                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL1);
+                return GB_OK;
+            }
+        }
+        if (name[3] == 'V' && name[3] == 'G' && name[3] == 'A') {
+            console = types::_new<types::kernel_ident_allocator, vga_tty>();
+            return GB_OK;
+        }
+    }
+    return GB_FAILED;
+}
+
+extern void init_vfs();
+
+extern "C" SECTION(".text.kinit") void NORETURN kernel_init(void)
+{
+    asm_enable_sse();
+
+    init_bss_section();
+
+    save_loader_data();
+
+    load_new_gdt();
+
+    // call global ctors
+    // NOTE:
+    // the initializer of global objects MUST NOT contain
+    // all kinds of memory allocations
+    for (const constructor* ctor = &start_ctors; ctor != &end_ctors; ++ctor) {
+        (*ctor)();
+    }
+
+    int ret = init_serial_port(PORT_SERIAL0);
+    assert(ret == GB_OK);
+
+    init_idt();
+    init_mem();
+    init_pic();
+    init_pit();
+
+    ret = init_console("ttyS0");
+    assert(ret == GB_OK);
+
+    init_vfs();
+
+    kmsg("switching execution to the scheduler...\n");
+    init_scheduler();
+}

+ 2 - 2
src/mbr.S

@@ -26,7 +26,7 @@ mbr_start:
     call read_data
 
 # loader start
-    jmp 0x7e00
+    jmp 0x8000
 
 read_data:
     movw $read_data_pack, %si
@@ -48,7 +48,7 @@ read_data_count:
 read_data_offset:
     .word 0x0000 # offset address
 read_data_segment:
-    .word 0x07e0 # segment address
+    .word 0x0800 # segment address
 read_data_lba:
     .long 1      # lower 4 bytes of the LBA to read
     .long 0      # higher 2 bytes of the LBA to read

+ 3 - 3
src/types/bitmap.c

@@ -7,16 +7,16 @@ size_t make_bm_size(size_t n)
     return sizeof(size_t) + (n / SZ) + ((n % SZ) ? 1 : 0);
 }
 
-int bm_test(char* bm, size_t n)
+int bm_test(uint8_t* bm, size_t n)
 {
     return (bm[n / SZ] & (1 << (n % SZ))) != 0;
 }
 
-void bm_set(char* bm, size_t n)
+void bm_set(uint8_t* bm, size_t n)
 {
     bm[n / SZ] |= (1 << (n % SZ));
 }
-void bm_clear(char* bm, size_t n)
+void bm_clear(uint8_t* bm, size_t n)
 {
     bm[n / SZ] &= (~(1 << (n % SZ)));
 }

+ 23 - 18
src/types/elf.cpp

@@ -50,7 +50,7 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
 
     size_t phents_size = hdr.phentsize * hdr.phnum;
     size_t shents_size = hdr.shentsize * hdr.shnum;
-    auto* phents = (types::elf::elf32_program_header_entry*)k_malloc(phents_size);
+    auto* phents = new types::elf::elf32_program_header_entry[hdr.phnum];
     n_read = fs::vfs_read(
         ent_exec->ind,
         (char*)phents,
@@ -59,13 +59,13 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
 
     // broken file or I/O error
     if (n_read != phents_size) {
-        k_free(phents);
+        delete[] phents;
 
         d->errcode = EINVAL;
         return GB_FAILED;
     }
 
-    auto* shents = (types::elf::elf32_section_header_entry*)k_malloc(shents_size);
+    auto* shents = new types::elf::elf32_section_header_entry[hdr.shnum];
     n_read = fs::vfs_read(
         ent_exec->ind,
         (char*)shents,
@@ -74,8 +74,8 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
 
     // broken file or I/O error
     if (n_read != shents_size) {
-        k_free(phents);
-        k_free(shents);
+        delete[] phents;
+        delete[] shents;
 
         d->errcode = EINVAL;
         return GB_FAILED;
@@ -96,8 +96,8 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     {
         auto* dent = fs::vfs_open("/dev/null");
         if (!dent) {
-            k_free(shents);
-            k_free(phents);
+            delete[] phents;
+            delete[] shents;
             kill_current(-1);
         }
         null_ind = dent->ind;
@@ -107,23 +107,28 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
         if (phents[i].type != types::elf::elf32_program_header_entry::PT_LOAD)
             continue;
 
+        auto vaddr = align_down<12>(phents[i].vaddr);
+        auto vlen = align_up<12>(phents[i].vaddr + phents[i].memsz) - vaddr;
+        auto flen = align_up<12>(phents[i].vaddr + phents[i].filesz) - vaddr;
+        auto fileoff = align_down<12>(phents[i].offset);
+
         auto ret = mmap(
-            (char*)phents[i].vaddr,
-            phents[i].filesz,
+            (char*)vaddr,
+            phents[i].filesz + (phents[i].vaddr & 0xfff),
             ent_exec->ind,
-            phents[i].offset,
+            fileoff,
             1,
             d->system);
 
         if (ret != GB_OK)
             goto error;
 
-        if (phents[i].memsz > align_up<12>(phents[i].filesz)) {
+        if (vlen > flen) {
             ret = mmap(
-                (char*)phents[i].vaddr + align_up<12>(phents[i].filesz),
-                align_up<12>(phents[i].memsz) - align_up<12>(phents[i].filesz),
+                (char*)vaddr + flen,
+                vlen - flen,
                 null_ind,
-                phents[i].offset + align_up<12>(phents[i].filesz),
+                0,
                 1,
                 d->system);
 
@@ -134,8 +139,8 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
         continue;
 
     error:
-        k_free(phents);
-        k_free(shents);
+        delete[] phents;
+        delete[] shents;
         kill_current(-1);
     }
 
@@ -187,8 +192,8 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     // push argc
     _user_push(sp, args.size());
 
-    k_free(shents);
-    k_free(phents);
+    delete[] phents;
+    delete[] shents;
 
     return GB_OK;
 }

+ 0 - 9
src/types/libstdcpp.cpp

@@ -5,15 +5,6 @@
 #include <stdio.h>
 #include <types/types.h>
 
-void operator delete(void*)
-{
-    assert(false);
-}
-void operator delete(void*, unsigned int)
-{
-    assert(false);
-}
-
 extern "C" void NORETURN __stack_chk_fail(void)
 {
     assert(false);

+ 2 - 4
user-space-program/CMakeLists.txt

@@ -1,12 +1,10 @@
 cmake_minimum_required(VERSION 3.15)
 project(user_space_program C ASM)
 
-set(CMAKE_C_FLAGS "-nostdinc -nostdlib -static -m32 -W -Wall -Wextra -Werror -mstack-protector-guard=global")
-set(CMAKE_ASM_FLAGS "-m32 -static -mstack-protector-guard=global -g0")
+set(CMAKE_C_FLAGS "-nostdlib -nostdinc -static -m32 -W -Wall -Wextra -Werror -mstack-protector-guard=global")
+set(CMAKE_ASM_FLAGS "-nostdlib -m32 -static -mstack-protector-guard=global -g0")
 
 link_libraries(gblibc)
-add_link_options(-nostdlib -T ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
-# set(LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
 
 set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "")
 set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "")

+ 0 - 27
user-space-program/script.ld

@@ -1,27 +0,0 @@
-OUTPUT_FORMAT(elf32-i386)
-OUTPUT_ARCH(i386:i386)
-
-ENTRY(_start)
-
-MEMORY
-{
-    MEM : org = 0x40000000, l = 3072M
-
-}
-
-SECTIONS
-{
-    .text 0x40000000 :
-    {
-        *(.text)
-        *(.text*)
-
-        __stack_chk_guard = .;
-        LONG(0x11451419);
-    } > MEM
-
-    /DISCARD/ :
-    {
-        *(.note.gnu.property*)
-    }
-}