greatbridf пре 2 година
родитељ
комит
0de053a20f

+ 2 - 2
CMakeLists.txt

@@ -42,7 +42,7 @@ include_directories(${PROJECT_SOURCE_DIR}/include)
 set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         src/kernel/errno.c
                         src/kernel/interrupt.cpp
-                        src/kernel/process.c
+                        src/kernel/process.cpp
                         src/kernel/tty.c
                         src/kernel/stdio.c
                         src/kernel/mem.cpp
@@ -61,7 +61,7 @@ set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         include/kernel/errno.h
                         include/kernel/tty.h
                         include/kernel/interrupt.h
-                        include/kernel/process.h
+                        include/kernel/process.hpp
                         include/kernel/stdio.h
                         include/kernel/mem.h
                         include/kernel/mm.hpp

+ 12 - 0
doc/mem_layout.txt

@@ -0,0 +1,12 @@
+0x00000000 - 0x00001000 kernel pd
+0x00001000 - 0x00005000 kernel pt
+0x00005000 - 0x00006000 empty page
+
+....
+
+0x00100000 - 0x???????? kernel code, data, bss
+0x???????? - 0x01000000 kernel early stack
+
+....
+
+0x30000000 - 0x40000000 kernel heap

+ 1 - 0
include/asm/sys.h

@@ -7,6 +7,7 @@
 extern "C" {
 #endif
 
+void asm_switch_pd(page_directory_entry* pd_addr);
 void asm_enable_paging(page_directory_entry* pd_addr);
 
 phys_ptr_t current_pd(void);

+ 9 - 25
include/kernel/interrupt.h

@@ -21,6 +21,15 @@ struct regs_32 {
     uint32_t eax;
 };
 
+struct PACKED irq0_data {
+    struct regs_32 s_regs;
+    void* v_eip;
+    uint32_t cs;
+    uint32_t eflags;
+    uint32_t esp;
+    uint32_t ss;
+};
+
 // present: When set, the page fault was caused by a page-protection violation.
 //          When not set, it was caused by a non-present page.
 // write:   When set, the page fault was caused by a write access.
@@ -84,31 +93,6 @@ void int13_handler(
     uint16_t cs,
     uint32_t eflags);
 
-void int14_handler(
-    linr_ptr_t l_addr,
-    struct regs_32 s_regs,
-    struct page_fault_error_code error_code,
-    void* v_eip,
-    uint16_t cs,
-    uint32_t eflags);
-
-void irq0_handler(void);
-void irq1_handler(void);
-void irq2_handler(void);
-void irq3_handler(void);
-void irq4_handler(void);
-void irq5_handler(void);
-void irq6_handler(void);
-void irq7_handler(void);
-void irq8_handler(void);
-void irq9_handler(void);
-void irq10_handler(void);
-void irq11_handler(void);
-void irq12_handler(void);
-void irq13_handler(void);
-void irq14_handler(void);
-void irq15_handler(void);
-
 void int0(void);
 void int1(void);
 void int2(void);

+ 2 - 0
include/kernel/mem.h

@@ -117,6 +117,8 @@ void init_mem(void);
 #define KERNEL_DATA_SEGMENT (0x10)
 #define USER_CODE_SEGMENT (0x18)
 #define USER_DATA_SEGMENT (0x20)
+#define USER_CODE_SELECTOR (USER_CODE_SEGMENT | 3)
+#define USER_DATA_SELECTOR (USER_DATA_SEGMENT | 3)
 
 #define SD_TYPE_CODE_SYSTEM (0x9a)
 #define SD_TYPE_DATA_SYSTEM (0x92)

+ 13 - 2
include/kernel/mm.hpp

@@ -6,6 +6,8 @@
 #include <types/types.h>
 #include <types/vector.hpp>
 
+constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
+
 struct page_attr {
     uint32_t cow : 1;
 };
@@ -24,17 +26,23 @@ struct mm_attr {
     uint32_t system : 1;
 };
 
-struct mm {
+class mm {
+public:
     linr_ptr_t start;
     struct mm_attr attr;
-    page_arr* pgs;
     page_directory_entry* pd;
+    page_arr* pgs;
+
+public:
+    mm(const mm& val);
+    mm(linr_ptr_t start, page_directory_entry* pd, bool write, bool system);
 };
 
 using mm_list = types::list<mm, types::kernel_ident_allocator>;
 
 // in mem.cpp
 extern mm_list* kernel_mms;
+extern page empty_page;
 
 // translate physical address to virtual(mapped) address
 void* p_ptr_to_v_ptr(phys_ptr_t p_ptr);
@@ -137,3 +145,6 @@ page_t alloc_raw_page(void);
 
 // allocate a struct page together with the raw page
 struct page allocate_page(void);
+
+page_directory_entry* alloc_pd(void);
+page_table_entry* alloc_pt(void);

+ 0 - 15
include/kernel/process.h

@@ -1,15 +0,0 @@
-#pragma once
-
-#include <kernel/mem.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct process {
-    struct mm* mm;
-};
-
-#ifdef __cplusplus
-}
-#endif

+ 49 - 0
include/kernel/process.hpp

@@ -0,0 +1,49 @@
+#pragma once
+
+#include <kernel/interrupt.h>
+#include <kernel/task.h>
+#include <types/types.h>
+
+#ifdef __cplusplus
+#include <kernel/mm.hpp>
+#include <types/list.hpp>
+
+struct process;
+struct thread;
+
+struct process_attr {
+    uint16_t system : 1;
+};
+
+struct thread {
+    void* eip;
+    process* owner;
+    regs_32 regs;
+    uint32_t eflags;
+    uint32_t esp;
+};
+
+class process {
+public:
+    mm_list mms;
+    types::list<thread> thds;
+    void* k_esp;
+    process_attr attr;
+
+public:
+    process(process&& val);
+    process(const process&) = delete;
+    process(void* start_eip, uint8_t* image, size_t image_size, bool system);
+};
+
+// in process.cpp
+extern process* current_process;
+
+extern "C" void NORETURN init_scheduler();
+void context_switch(irq0_data* intrpt_data);
+
+#else
+
+void NORETURN init_scheduler();
+
+#endif

+ 2 - 0
include/kernel/task.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <types/types.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 10 - 1
include/kernel_main.h

@@ -1,4 +1,5 @@
 #pragma once
+#include <types/types.h>
 
 static inline void __break_point(void)
 {
@@ -12,4 +13,12 @@ static inline void __break_point(void)
 
 #define KERNEL_START_ADDR (0x00100000)
 
-void kernel_main(void);
+void NORETURN kernel_main(void);
+
+#ifdef __cplusplus
+// in kernel_main.c
+extern "C" struct tss32_t tss;
+#else
+// in kernel_main.c
+extern struct tss32_t tss;
+#endif

+ 9 - 8
include/types/allocator.hpp

@@ -1,5 +1,6 @@
 #pragma once
 #include <kernel/mem.h>
+#include <types/cplusplus.hpp>
 #include <types/types.h>
 
 inline void* operator new(size_t, void* ptr)
@@ -45,15 +46,15 @@ public:
 };
 
 template <typename T, typename... Args>
-T* kernel_allocator_new(Args... args)
+T* kernel_allocator_new(Args&&... args)
 {
-    return allocator_traits<kernel_allocator<T>>::allocate_and_construct(args...);
+    return allocator_traits<kernel_allocator<T>>::allocate_and_construct(forward<Args>(args)...);
 }
 
 template <typename T, typename... Args>
-T* kernel_ident_allocator_new(Args... args)
+T* kernel_ident_allocator_new(Args&&... args)
 {
-    return allocator_traits<kernel_ident_allocator<T>>::allocate_and_construct(args...);
+    return allocator_traits<kernel_ident_allocator<T>>::allocate_and_construct(forward<Args>(args)...);
 }
 
 template <typename Allocator>
@@ -69,17 +70,17 @@ public:
     }
 
     template <typename... Args>
-    static value_type* construct(value_type* ptr, Args... args)
+    static value_type* construct(value_type* ptr, Args&&... args)
     {
-        new (ptr) value_type(args...);
+        new (ptr) value_type(forward<Args>(args)...);
         return ptr;
     }
 
     template <typename... Args>
-    static value_type* allocate_and_construct(Args... args)
+    static value_type* allocate_and_construct(Args&&... args)
     {
         auto* ptr = allocate(1);
-        construct(ptr, args...);
+        construct(ptr, forward<Args>(args)...);
         return ptr;
     }
 

+ 14 - 0
include/types/cplusplus.hpp

@@ -48,6 +48,20 @@ struct add_reference {
     using type = T&;
 };
 
+} // namespace types::traits
+
+namespace types {
+template <typename T>
+T&& move(T& val)
+{
+    return static_cast<T&&>(val);
+}
+template <typename T>
+T&& forward(typename traits::remove_reference<T>::type& val)
+{
+    return static_cast<T&&>(val);
+}
+
 } // namespace types
 
 #endif

+ 84 - 16
include/types/list.hpp

@@ -52,7 +52,7 @@ private:
         }
 
         explicit node(NodeValue&& v) noexcept
-            : value(v)
+            : value(move(v))
         {
         }
 
@@ -75,6 +75,13 @@ public:
         iterator(iterator&& iter) noexcept
             : n(iter.n)
         {
+            iter.n = nullptr;
+        }
+
+        iterator& operator=(const iterator& iter)
+        {
+            n = iter.n;
+            return *this;
         }
 
         explicit iterator(node_base* _n) noexcept
@@ -156,6 +163,15 @@ private:
         return (static_cast<sentry_node_type*>(head))->value;
     }
 
+    void destroy(void)
+    {
+        if (!head || !tail)
+            return;
+        clear();
+        allocator_traits<sentry_allocator_type>::deconstruct_and_deallocate(static_cast<sentry_node_type*>(head));
+        allocator_traits<sentry_allocator_type>::deconstruct_and_deallocate(static_cast<sentry_node_type*>(tail));
+    }
+
 public:
     list() noexcept
         // size is stored in the 'head' node
@@ -166,13 +182,44 @@ public:
         tail->connect(head);
     }
 
+    list(const list& v)
+        : list()
+    {
+        for (const auto& item : v)
+            push_back(item);
+    }
+
+    list(list&& v)
+        : head(v.head)
+        , tail(v.tail)
+    {
+        v.head = nullptr;
+        v.tail = nullptr;
+    }
+
+    list& operator=(const list& v)
+    {
+        clear();
+        for (const auto& item : v)
+            push_back(item);
+        return *this;
+    }
+
+    list& operator=(list&& v)
+    {
+        destroy();
+
+        head = v.head;
+        tail = v.tail;
+        v.head = nullptr;
+        v.tail = nullptr;
+
+        return *this;
+    }
+
     ~list() noexcept
     {
-        for (auto iter = begin(); iter != end(); ++iter) {
-            erase(iter);
-        }
-        allocator_traits<sentry_allocator_type>::deconstruct_and_deallocate(static_cast<sentry_node_type*>(head));
-        allocator_traits<sentry_allocator_type>::deconstruct_and_deallocate(static_cast<sentry_node_type*>(tail));
+        destroy();
     }
 
     iterator_type find(const value_type& v) noexcept
@@ -183,32 +230,44 @@ public:
     }
 
     // erase the node which iter points to
-    void erase(const iterator_type& iter) noexcept
+    iterator_type erase(const iterator_type& iter) noexcept
     {
         node_base_type* current_node = iter._node();
+        iterator_type ret(current_node->next);
         current_node->prev->connect(current_node->next);
         allocator_traits<allocator_type>::deconstruct_and_deallocate(static_cast<node_type*>(current_node));
         --_size();
+        return ret;
+    }
+
+    void clear(void)
+    {
+        for (auto iter = begin(); iter != end();)
+            iter = erase(iter);
     }
 
     // insert the value v in front of the given iterator
-    void insert(const iterator_type& iter, const value_type& v) noexcept
+    iterator_type insert(const iterator_type& iter, const value_type& v) noexcept
     {
         node_base_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(v);
+        iterator_type ret(new_node);
         iter._node()->prev->connect(new_node);
         new_node->connect(iter._node());
 
         ++_size();
+        return ret;
     }
 
     // insert the value v in front of the given iterator
-    void insert(const iterator_type& iter, value_type&& v) noexcept
+    iterator_type insert(const iterator_type& iter, value_type&& v) noexcept
     {
-        node_base_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(v);
-        iter._node().prev->connect(new_node);
+        node_base_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(move(v));
+        iterator_type ret(new_node);
+        iter._node()->prev->connect(new_node);
         new_node->connect(iter._node());
 
         ++_size();
+        return ret;
     }
 
     void push_back(const value_type& v) noexcept
@@ -218,7 +277,13 @@ public:
 
     void push_back(value_type&& v) noexcept
     {
-        insert(end(), v);
+        insert(end(), move(v));
+    }
+
+    template <typename... Args>
+    iterator_type emplace_back(Args&&... args)
+    {
+        return insert(end(), value_type(forward<Args>(args)...));
     }
 
     void push_front(const value_type& v) noexcept
@@ -228,7 +293,13 @@ public:
 
     void push_front(value_type&& v) noexcept
     {
-        insert(begin(), v);
+        insert(begin(), move(v));
+    }
+
+    template <typename... Args>
+    iterator_type emplace_front(Args&&... args)
+    {
+        return insert(begin(), value_type(forward<Args>(args)...));
     }
 
     size_t size(void) const noexcept
@@ -272,9 +343,6 @@ public:
     }
 
     // TODO
-    // iterator_type cstart() noexcept;
-    // iterator_type cend() noexcept;
-
     // iterator_type r_start() noexcept;
     // iterator_type r_end() noexcept;
 

+ 6 - 0
include/types/size.h

@@ -2,6 +2,12 @@
 
 #include "stdint.h"
 
+#ifdef __GNUC__
+#define PACKED __attribute__((__packed__))
+#else
+#error "no definition for ((PACKED))"
+#endif
+
 #define __32bit_system
 
 #ifdef __32bit_system

+ 12 - 0
include/types/string.hpp

@@ -31,6 +31,10 @@ public:
         : inner_vector_type((const inner_vector_type&)str)
     {
     }
+    string(string&& str)
+        : inner_vector_type((inner_vector_type &&) move(str))
+    {
+    }
     string& append(const char* str, size_type n = npos)
     {
         this->pop_back();
@@ -47,6 +51,10 @@ public:
     {
         return this->append(str.data());
     }
+    string& append(string&& str)
+    {
+        return this->append(str.data());
+    }
     string& operator+=(const char c)
     {
         *this->back() = c;
@@ -61,6 +69,10 @@ public:
     {
         return this->append(str);
     }
+    string& operator+=(string&& str)
+    {
+        return this->append(move(str));
+    }
     string substr(size_type pos, size_type n = npos)
     {
         return string(this->m_arr + pos, n);

+ 17 - 0
include/types/types.h

@@ -5,3 +5,20 @@
 #include "size.h"
 #include "status.h"
 #include "stdint.h"
+
+#ifdef __GNUC__
+#define NORETURN __attribute__((noreturn))
+#else
+#error "no definition for ((NORETURN))"
+#endif
+
+#ifdef __GNUC__
+#define SECTION(x) __attribute__((section(x)))
+#else
+#error "no definition for ((SECTION))"
+#endif
+
+#ifdef __cplusplus
+#include <types/allocator.hpp>
+#include <types/cplusplus.hpp>
+#endif

+ 27 - 2
include/types/vector.hpp

@@ -38,6 +38,13 @@ public:
         iterator(iterator&& iter) noexcept
             : p(iter.p)
         {
+            iter.p = nullptr;
+        }
+
+        iterator& operator=(const iterator& iter)
+        {
+            p = iter.p;
+            return *this;
         }
 
         explicit iterator(Pointer p) noexcept
@@ -115,13 +122,24 @@ public:
         resize(capacity);
     }
 
-    vector(const vector<T, Allocator>& arr) noexcept
+    vector(const vector& arr) noexcept
         : vector(arr.capacity())
     {
         for (const auto& item : arr)
             push_back(item);
     }
 
+    vector(vector&& arr) noexcept
+    {
+        m_arr = arr.m_arr;
+        m_capacity = arr.m_capacity;
+        m_size = arr.m_size;
+
+        arr.m_arr = nullptr;
+        arr.m_capacity = 0;
+        arr.m_size = 0;
+    }
+
     ~vector() noexcept
     {
         resize(0);
@@ -220,10 +238,17 @@ public:
     {
         if (m_size == m_capacity)
             resize(m_capacity * 2);
-        allocator_traits<allocator_type>::construct(m_arr + m_size, v);
+        allocator_traits<allocator_type>::construct(m_arr + m_size, move(v));
         ++m_size;
     }
 
+    template <typename... Args>
+    iterator_type emplace_back(Args&&... args)
+    {
+        push_back(value_type(forward<Args>(args)...));
+        return back();
+    }
+
     void pop_back(void) noexcept
     {
         allocator_traits<allocator_type>::deconstruct(&*back());

+ 25 - 3
src/asm/interrupt.s

@@ -2,26 +2,27 @@
 
 .text
 
+# TODO: stack alignment
 .globl int6
 .type  int6 @function
 int6:
-    xchgw %bx, %bx
     pushal
     call int6_handler
     popal
 
     iret
 
+# TODO: stack alignment
 .globl int8
 .type  int8 @function
 int8:
     nop
     iret
 
+# TODO: stack alignment
 .globl int13
 .type  int13 @function
 int13:
-    xchgw %bx, %bx
     pushal
     call int13_handler
     popal
@@ -33,11 +34,21 @@ int13:
 .globl int14
 .type  int14 @function
 int14:
-    xchgw %bx, %bx
     pushal
     movl %cr2, %eax
     pushl %eax
+
+    # stack alignment and push *data
+    movl %esp, %eax
+    subl $0x4, %esp
+    andl $0xfffffff0, %esp
+    movl %eax, (%esp)
+
     call int14_handler
+
+    # restore stack
+    popl %esp
+
     popl %eax
     popal
 
@@ -49,7 +60,18 @@ int14:
 .type  irq0 @function
 irq0:
     pushal
+
+    # stack alignment and push *data
+    movl %esp, %eax
+    subl $0x4, %esp
+    andl $0xfffffff0, %esp
+    movl %eax, (%esp)
+
     call irq0_handler
+
+    # restore stack
+    popl %esp
+
     popal
     iret
 

+ 17 - 17
src/asm/sys.s

@@ -2,6 +2,13 @@
 
 .text
 
+.global asm_switch_pd
+.type   asm_switch_pd @function
+asm_switch_pd:
+    movl 4(%esp), %eax
+    movl %eax, %cr3
+    ret
+
 .global asm_enable_paging
 .type   asm_enable_paging @function
 asm_enable_paging:
@@ -34,7 +41,6 @@ _asm_load_gdt_fin:
 	movw 4(%esp), %ax
 	cmpw $0, %ax
 	je _asm_load_gdt_fin_ret
-    sti
 _asm_load_gdt_fin_ret:
     ret
 
@@ -45,32 +51,26 @@ asm_load_tr:
     movl 4(%esp), %eax
     orl $0, %eax
     ltr %ax
-    sti
     ret
 
-
-# examples for going ring 3
-_test_user_space_program:
-    movl $0x1919810, %eax
-    movl $0xc48c, %ecx
-_reap:
-    cmpl $1000, (%ecx)
-    jl _reap
-_fault:
-    cli
-
-go_user_space_example:
+.globl go_user_space
+.type  go_user_space @function
+go_user_space:
     movl $((4 * 8) | 3), %eax
     movw %ax, %ds
     movw %ax, %es
     movw %ax, %fs
     movw %ax, %gs
 
-    movl %esp, %eax
+    movl 4(%esp), %ebx
     pushl $((4 * 8) | 3)
-    pushl %eax
+    pushl $0x40100000
     pushf
+    # allow interrupts in user mode
+    movl (%esp), %eax
+    orl $0x200, %eax
+    movl %eax, (%esp)
     pushl $((3 * 8) | 3)
-    pushl $_test_user_space_program
+    pushl %ebx
 
     iret

+ 1 - 1
src/boot.s

@@ -41,7 +41,7 @@ read_data_pack:
     .byte 0x10, 0
 # TODO!!!
 # read more!
-    .word 64     # block count (read 32k)
+    .word 128    # block count (read 64k)
     .word 0x0000 # offset address
     .word 0x07e0 # segment address
     .long 1      # LBA to read

+ 44 - 32
src/kernel/interrupt.cpp

@@ -6,6 +6,7 @@
 #include <kernel/interrupt.h>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
+#include <kernel/process.hpp>
 #include <kernel/stdio.h>
 #include <kernel/tty.h>
 #include <kernel/vga.h>
@@ -102,7 +103,7 @@ extern "C" void int6_handler(
 }
 
 // general protection
-void int13_handler(
+extern "C" void int13_handler(
     struct regs_32 s_regs,
     uint32_t error_code,
     ptr_t eip,
@@ -131,40 +132,50 @@ void int13_handler(
     asm_hlt();
 }
 
+// TODO: remove debug variable
 static size_t page_fault_times;
 
+struct PACKED int14_data {
+    linr_ptr_t l_addr;
+    struct regs_32 s_regs;
+    struct page_fault_error_code error_code;
+    void* v_eip;
+    uint32_t cs;
+    uint32_t eflags;
+};
+
 // page fault
-void int14_handler(
-    linr_ptr_t l_addr,
-    struct regs_32 s_regs,
-    struct page_fault_error_code error_code,
-    void* v_eip,
-    uint16_t cs,
-    uint32_t eflags)
+extern "C" void int14_handler(struct int14_data* d)
 {
     char buf[512];
+    mm_list* mms = nullptr;
+    if (current_process)
+        mms = &current_process->mms;
+    else
+        mms = kernel_mms;
 
+    // TODO: remove debug variable
     ++page_fault_times;
 
     // not present page, possibly mapped but not loaded
     // or invalid address or just invalid address
     // TODO: mmapping and swapping
-    if (error_code.present == 0) {
+    if (d->error_code.present == 0) {
         goto kill;
     }
 
     // kernel code
-    if (cs == KERNEL_CODE_SEGMENT) {
-        if (is_l_ptr_valid(kernel_mms, l_addr) != GB_OK) {
+    if (d->cs == KERNEL_CODE_SEGMENT) {
+        if (is_l_ptr_valid(mms, d->l_addr) != GB_OK) {
             goto kill;
         }
-        struct page* page = find_page_by_l_ptr(kernel_mms, l_addr);
+        struct page* page = find_page_by_l_ptr(mms, d->l_addr);
 
         // copy on write
-        if (error_code.write == 1 && page->attr.cow == 1) {
-            page_directory_entry* pde = mms_get_pd(kernel_mms) + linr_addr_to_pd_i(l_addr);
+        if (d->error_code.write == 1 && page->attr.cow == 1) {
+            page_directory_entry* pde = mms_get_pd(mms) + linr_addr_to_pd_i(d->l_addr);
             page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
-            pte += linr_addr_to_pt_i(l_addr);
+            pte += linr_addr_to_pt_i(d->l_addr);
 
             // if it is a dying page
             if (*page->ref_count == 1) {
@@ -195,7 +206,7 @@ void int14_handler(
 kill:
     snprintf(
         buf, 512,
-        "killed: segmentation fault (eip: %x, cr2: %x, error_code: %x)", v_eip, l_addr, error_code);
+        "killed: segmentation fault (eip: %x, cr2: %x, error_code: %x)", d->v_eip, d->l_addr, d->error_code);
     tty_print(console, buf);
 
     MAKE_BREAK_POINT();
@@ -203,77 +214,78 @@ kill:
     asm_hlt();
 }
 
-void irq0_handler(void)
+extern "C" void irq0_handler(struct irq0_data* d)
 {
     inc_tick();
+    context_switch(d);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
 // keyboard interrupt
-void irq1_handler(void)
+extern "C" void irq1_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
     handle_keyboard_interrupt();
 }
-void irq2_handler(void)
+extern "C" void irq2_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq3_handler(void)
+extern "C" void irq3_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq4_handler(void)
+extern "C" void irq4_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq5_handler(void)
+extern "C" void irq5_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq6_handler(void)
+extern "C" void irq6_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq7_handler(void)
+extern "C" void irq7_handler(void)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq8_handler(void)
+extern "C" void irq8_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq9_handler(void)
+extern "C" void irq9_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq10_handler(void)
+extern "C" void irq10_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq11_handler(void)
+extern "C" void irq11_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq12_handler(void)
+extern "C" void irq12_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq13_handler(void)
+extern "C" void irq13_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq14_handler(void)
+extern "C" void irq14_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
-void irq15_handler(void)
+extern "C" void irq15_handler(void)
 {
     asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);

+ 48 - 17
src/kernel/mem.cpp

@@ -319,6 +319,24 @@ static inline void make_page_table(page_table_entry* pt)
     memset(pt, 0x00, sizeof(page_table_entry) * 1024);
 }
 
+page_directory_entry* alloc_pd(void)
+{
+    // TODO: alloc page in low mem and gen struct page for it
+    page_t pd_page = alloc_raw_page();
+    page_directory_entry* pd = (page_directory_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pd_page));
+    memset(pd, 0x00, PAGE_SIZE);
+    return pd;
+}
+
+page_table_entry* alloc_pt(void)
+{
+    // TODO: alloc page in low mem and gen struct page for it
+    page_t pt_page = alloc_raw_page();
+    page_table_entry* pt = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pt_page));
+    make_page_table(pt);
+    return pt;
+}
+
 static inline void init_mem_layout(void)
 {
     mem_size = 1024 * mem_size_info.n_1k_blks;
@@ -382,7 +400,7 @@ static inline void map_raw_page_to_pte(
     // set P bit
     pte->v = 0x00000001;
     pte->in.rw = (rw == 1);
-    pte->in.us = (priv == 1);
+    pte->in.us = (priv == 0);
     pte->in.page = page;
 }
 
@@ -402,7 +420,7 @@ int k_map(
         // allocate a page for the page table
         pde->in.p = 1;
         pde->in.rw = 1;
-        pde->in.us = 0;
+        pde->in.us = (priv == 0);
         pde->in.pt_page = alloc_raw_page();
 
         make_page_table((page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page)));
@@ -456,7 +474,7 @@ static inline void init_paging_map_low_mem_identically(void)
     }
 }
 
-static page empty_page;
+page empty_page;
 
 void init_mem(void)
 {
@@ -466,16 +484,7 @@ void init_mem(void)
     init_paging_map_low_mem_identically();
 
     kernel_mms = types::kernel_ident_allocator_new<mm_list>();
-    kernel_mms->push_back(mm {
-        .start = (linr_ptr_t)KERNEL_HEAP_START,
-        .attr = {
-            .read = 1,
-            .write = 1,
-            .system = 1,
-        },
-        .pgs = types::kernel_ident_allocator_new<page_arr>(),
-        .pd = KERNEL_PAGE_DIRECTORY_ADDR,
-    });
+    auto heap_mm = kernel_mms->emplace_back((linr_ptr_t)KERNEL_HEAP_START, KERNEL_PAGE_DIRECTORY_ADDR, 1, 1);
 
     page heap_first_page {
         .phys_page_id = alloc_raw_page(),
@@ -485,9 +494,7 @@ void init_mem(void)
         },
     };
 
-    mm* heap_mm = kernel_mms->begin().ptr();
-
-    k_map(heap_mm, &heap_first_page, 1, 1, 1, 0);
+    k_map(heap_mm.ptr(), &heap_first_page, 1, 1, 1, 0);
     memset(KERNEL_HEAP_START, 0x00, PAGE_SIZE);
     kernel_heap_allocator = types::kernel_ident_allocator_new<brk_memory_allocator>(KERNEL_HEAP_START,
         (uint32_t)KERNEL_HEAP_LIMIT - (uint32_t)KERNEL_HEAP_START);
@@ -501,7 +508,7 @@ void init_mem(void)
     // while (kernel_mm_head->len < 256 * 1024 * 1024 / PAGE_SIZE) {
     while (heap_mm->pgs->size() < 256 * 1024 * 1024 / PAGE_SIZE) {
         k_map(
-            heap_mm, &empty_page,
+            heap_mm.ptr(), &empty_page,
             1, 1, 1, 1);
     }
 }
@@ -521,3 +528,27 @@ void create_segment_descriptor(
     sd->access = access;
     sd->flags = flags;
 }
+
+mm::mm(linr_ptr_t start, page_directory_entry* pd, bool write, bool system)
+    : start(start)
+    , attr({
+          .read { 1 },
+          .write { write },
+          .system { system },
+      })
+    , pd(pd)
+    , pgs(types::kernel_ident_allocator_new<page_arr>())
+{
+}
+
+mm::mm(const mm& val)
+    : start(val.start)
+    , attr({
+          .read { val.attr.read },
+          .write { val.attr.write },
+          .system { val.attr.system },
+      })
+    , pd(val.pd)
+    , pgs(val.pgs)
+{
+}

+ 0 - 0
src/kernel/process.c


+ 172 - 0
src/kernel/process.cpp

@@ -0,0 +1,172 @@
+#include <asm/port_io.h>
+#include <asm/sys.h>
+#include <kernel/mm.hpp>
+#include <kernel/process.hpp>
+#include <kernel/stdio.h>
+#include <kernel_main.h>
+#include <types/types.h>
+
+extern "C" void NORETURN go_user_space(void* eip);
+
+static inline void* align_down_to_16byte(void* addr)
+{
+    return (void*)((uint32_t)addr & 0xfffffff0);
+}
+
+static bool is_scheduler_ready;
+static types::list<process>* processes;
+static types::list<thread*>* ready_thds;
+
+thread* current_thread;
+process* current_process;
+
+process::process(process&& val)
+    : mms(types::move(val.mms))
+    , thds(types::move(val.thds))
+{
+    if (current_process == &val)
+        current_process = this;
+
+    attr.system = val.attr.system;
+    k_esp = val.k_esp;
+
+    for (auto& item : thds) {
+        item.owner = this;
+    }
+
+    val.k_esp = nullptr;
+    val.attr.system = 0;
+}
+
+process::process(void* start_eip, uint8_t* image, size_t image_size, bool system)
+    : mms(*kernel_mms)
+    , thds {}
+    , attr { .system = system }
+{
+    k_esp = align_down_to_16byte((char*)k_malloc(THREAD_KERNEL_STACK_SIZE) + THREAD_KERNEL_STACK_SIZE);
+    memset((char*)k_esp - THREAD_KERNEL_STACK_SIZE, 0x00, THREAD_KERNEL_STACK_SIZE);
+
+    page_directory_entry* pd = alloc_pd();
+    memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
+    for (auto& item : mms)
+        item.pd = pd;
+
+    auto user_mm = mms.emplace_back(0x40000000U, pd, 1, system);
+
+    auto thd = thds.emplace_back(thread {
+        .eip = start_eip,
+        .owner = this,
+        .regs {},
+        .eflags {},
+        // TODO: change this
+        .esp = 0x40100000U,
+    });
+    ready_thds->push_back(thd.ptr());
+
+    // TODO: change this
+    for (int i = 0; i < 1 * 1024 * 1024 / PAGE_SIZE; ++i)
+        k_map(user_mm.ptr(), &empty_page, 1, 1, 0, 1);
+
+    auto* old_pd = reinterpret_cast<page_directory_entry*>(p_ptr_to_v_ptr(current_pd()));
+    auto* old_proc = current_process;
+    auto* old_thd = current_thread;
+
+    current_process = this;
+    current_thread = thd.ptr();
+    asm_switch_pd(pd);
+
+    // TODO: change this
+    memcpy((void*)0x40000000U, image, image_size);
+
+    current_process = old_proc;
+    current_thread = old_thd;
+    asm_switch_pd(old_pd);
+}
+
+void NORETURN init_scheduler()
+{
+    processes = types::kernel_allocator_new<types::list<process>>();
+    ready_thds = types::kernel_allocator_new<types::list<thread*>>();
+
+    // movl $0x01919810, %eax
+    // movl $0x00114514, %ebx
+    // jmp $.
+    unsigned char instruction1[] = {
+        0xb8, 0x10, 0x98, 0x91, 0x01, 0xbb, 0x14, 0x45, 0x11, 0x00, 0xeb, 0xfe
+    };
+
+    uint8_t instruction2[] = {
+        0xb8, 0x00, 0x81, 0x19, 0x19, 0xbb, 0x00, 0x14, 0x45, 0x11, 0xeb, 0xfe
+    };
+
+    void* user_space_start = reinterpret_cast<void*>(0x40000000U);
+
+    processes->emplace_back(user_space_start, instruction1, sizeof(instruction1), false);
+    processes->emplace_back(user_space_start, instruction2, sizeof(instruction2), false);
+
+    // we need interrupts enabled for cow mapping
+    asm_cli();
+
+    auto init_process = processes->begin();
+    current_process = init_process.ptr();
+    current_thread = init_process->thds.begin().ptr();
+    tss.ss0 = KERNEL_DATA_SEGMENT;
+    tss.esp0 = (uint32_t)init_process->k_esp;
+    asm_switch_pd(mms_get_pd(&current_process->mms));
+
+    is_scheduler_ready = true;
+    go_user_space(user_space_start);
+}
+
+void context_switch(irq0_data* intrpt_data)
+{
+    if (!is_scheduler_ready)
+        return;
+
+    thread* thd = *ready_thds->begin();
+    if (current_thread == thd) {
+        ready_thds->erase(ready_thds->begin());
+        // check if the thread is ready
+        ready_thds->push_back(thd);
+        return;
+    }
+
+    process* pro = thd->owner;
+    if (current_process != pro) {
+        if (!pro->attr.system) {
+            tss.esp0 = (uint32_t)pro->k_esp;
+        }
+
+        current_process = pro;
+        asm_switch_pd(pro->mms.begin()->pd);
+    }
+
+    // save current thread info
+    current_thread->eflags = intrpt_data->eflags;
+    current_thread->eip = intrpt_data->v_eip;
+    memcpy(&current_thread->regs, &intrpt_data->s_regs, sizeof(regs_32));
+
+    // load ready thread info
+    intrpt_data->eflags = thd->eflags;
+    intrpt_data->eflags |= 0x200; // sti
+    intrpt_data->v_eip = thd->eip;
+    memcpy(&intrpt_data->s_regs, &thd->regs, sizeof(regs_32));
+
+    if (!pro->attr.system) {
+        // user mode
+        current_thread->esp = intrpt_data->esp;
+
+        intrpt_data->cs = USER_CODE_SELECTOR;
+        intrpt_data->ss = USER_DATA_SELECTOR;
+        intrpt_data->esp = thd->esp;
+    } else {
+        // supervisor mode
+        intrpt_data->cs = KERNEL_CODE_SEGMENT;
+    }
+
+    ready_thds->erase(ready_thds->begin());
+    // check if the thread is ready
+    ready_thds->push_back(thd);
+
+    current_thread = thd;
+}

+ 14 - 15
src/kernel_main.c

@@ -9,7 +9,9 @@
 #include <kernel/hw/timer.h>
 #include <kernel/interrupt.h>
 #include <kernel/mem.h>
+#include <kernel/process.hpp>
 #include <kernel/stdio.h>
+#include <kernel/task.h>
 #include <kernel/tty.h>
 #include <kernel/vfs.h>
 #include <kernel/vga.h>
@@ -115,7 +117,8 @@ static inline void show_mem_info(char* buf)
     printkf("kernel size: %x\n", kernel_size);
 }
 
-static segment_descriptor new_gdt[5];
+static segment_descriptor new_gdt[6];
+struct tss32_t tss;
 
 void load_new_gdt(void)
 {
@@ -124,7 +127,11 @@ void load_new_gdt(void)
     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);
-    asm_load_gdt((5 * 8 - 1) << 16, (phys_ptr_t)new_gdt);
+    create_segment_descriptor(new_gdt + 5, (uint32_t)&tss, sizeof(tss), 0b0000, SD_TYPE_TSS);
+
+    asm_load_gdt((6 * 8 - 1) << 16, (phys_ptr_t)new_gdt);
+    asm_load_tr((6 - 1) * 8);
+
     asm_cli();
 }
 
@@ -135,7 +142,9 @@ void init_bss_section(void)
     memset(bss_addr, 0x00, bss_size);
 }
 
-void kernel_main(void)
+static struct tty early_console;
+
+void NORETURN kernel_main(void)
 {
     // MAKE_BREAK_POINT();
     asm_enable_sse();
@@ -150,7 +159,6 @@ void kernel_main(void)
 
     init_serial_port(PORT_SERIAL0);
 
-    struct tty early_console;
     if (make_serial_tty(&early_console, PORT_SERIAL0) != GB_OK) {
         halt_on_init_error();
     }
@@ -191,15 +199,6 @@ void kernel_main(void)
     struct inode* init = vfs_open("/init");
     vfs_read(init, buf, 128, 1, 10);
 
-    printkf("No work to do, halting...\n");
-
-    while (1) {
-        // disable interrupt
-        asm_cli();
-
-        dispatch_event();
-
-        asm_sti();
-        asm_hlt();
-    }
+    printkf("switching execution to the scheduler...");
+    init_scheduler(&tss);
 }