Browse Source

refactor(scheduling): switch ctx. with schedule()

greatbridf 2 years ago
parent
commit
6953011b53

+ 9 - 9
include/kernel/interrupt.h

@@ -27,8 +27,8 @@ struct PACKED interrupt_stack {
     void* v_eip;
     uint32_t cs;
     uint32_t eflags;
-    const uint32_t esp;
-    const uint32_t ss;
+    uint32_t esp;
+    uint32_t ss;
 };
 
 // present: When set, the page fault was caused by a page-protection violation.
@@ -56,15 +56,15 @@ struct page_fault_error_code {
     SET_IDT_ENTRY(0x20 + (N), (addr_irq##N), (SELECTOR), KERNEL_INTERRUPT_GATE_TYPE);
 
 #define SET_IDT_ENTRY_FN(N, FUNC_NAME, SELECTOR, TYPE) \
-    extern void FUNC_NAME();                     \
-    ptr_t addr_##FUNC_NAME = (ptr_t)FUNC_NAME;   \
+    extern void FUNC_NAME();                           \
+    ptr_t addr_##FUNC_NAME = (ptr_t)FUNC_NAME;         \
     SET_IDT_ENTRY((N), (addr_##FUNC_NAME), (SELECTOR), (TYPE));
 
-#define SET_IDT_ENTRY(N, ADDR, SELECTOR, TYPE)      \
-    IDT[(N)].offset_low = (ADDR)&0x0000ffff;  \
-    IDT[(N)].selector = (SELECTOR);           \
-    IDT[(N)].zero = 0;                        \
-    IDT[(N)].type_attr = (TYPE); \
+#define SET_IDT_ENTRY(N, ADDR, SELECTOR, TYPE) \
+    IDT[(N)].offset_low = (ADDR)&0x0000ffff;   \
+    IDT[(N)].selector = (SELECTOR);            \
+    IDT[(N)].zero = 0;                         \
+    IDT[(N)].type_attr = (TYPE);               \
     IDT[(N)].offset_high = ((ADDR)&0xffff0000) >> 16
 
 struct IDT_entry {

+ 71 - 18
include/kernel/process.hpp

@@ -5,6 +5,7 @@
 #include <kernel/task.h>
 #include <types/hash_map.hpp>
 #include <types/list.hpp>
+#include <types/stdint.h>
 #include <types/types.h>
 
 typedef size_t pid_t;
@@ -23,19 +24,63 @@ struct thread_attr {
 };
 
 struct thread {
-    void* eip;
+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);
+    }
+
+public:
+    uint32_t* esp;
+    pptr_t kstack;
     process* owner;
-    regs_32 regs;
-    uint32_t eflags;
     thread_attr attr;
+
+    explicit inline thread(process* _owner, bool system)
+        : owner { _owner }
+        , attr {
+            .system = system,
+            .ready = 1,
+            .wait = 0,
+        }
+    {
+        alloc_kstack();
+    }
+
+    constexpr thread(thread&& val)
+        : esp { val.esp }
+        , kstack { val.kstack }
+        , owner { val.owner }
+        , attr { val.attr }
+    {
+        val.attr = {};
+        val.esp = 0;
+        val.kstack = 0;
+        val.owner = nullptr;
+    }
+
+    inline thread(const thread& val)
+        : owner { val.owner }
+        , attr { val.attr }
+    {
+        alloc_kstack();
+    }
+
+    constexpr ~thread()
+    {
+        if (kstack)
+            free_n_raw_pages(to_page(kstack), 2);
+        memset(this, 0x00, sizeof(thread));
+    }
 };
 
 class process {
 public:
-    kernel::mm_list mms;
+    mutable kernel::mm_list mms;
     types::list<thread> thds;
-    // TODO: allocate a kernel stack for EVERY THREAD
-    void* k_esp;
     process_attr attr;
     pid_t pid;
     pid_t ppid;
@@ -43,25 +88,36 @@ public:
 public:
     process(process&& val);
     process(const process&) = delete;
-    process(process& proc, const thread& main_thread);
+    process(const process& proc, const thread& main_thread);
 
     // only used for system initialization
-    process(void* start_eip);
+    explicit process(void);
+    explicit process(void (*func_in_kernel_space)(void), pid_t ppid);
+
+private:
+    static inline pid_t max_pid;
+
+    static inline pid_t alloc_pid(void)
+    {
+        return ++max_pid;
+    }
 };
 
+constexpr uint32_t push_stack(uint32_t** stack, uint32_t val)
+{
+    --*stack;
+    **stack = val;
+    return val;
+}
+
 inline process* volatile current_process;
 inline thread* volatile current_thread;
 inline typename types::hash_map<pid_t, types::list<pid_t>, types::linux_hasher<pid_t>>* idx_child_processes;
 
 extern "C" void NORETURN init_scheduler();
-void do_scheduling(interrupt_stack* intrpt_data);
+void schedule(void);
 
-void thread_context_save(interrupt_stack* int_stack, thread* thd);
-void thread_context_load(interrupt_stack* int_stack, thread* thd);
-void process_context_save(interrupt_stack*, process*);
-void process_context_load(interrupt_stack*, process* proc);
-
-void add_to_process_list(process&& proc);
+pid_t add_to_process_list(process&& proc);
 
 void add_to_ready_list(thread* thd);
 void remove_from_ready_list(thread* thd);
@@ -76,9 +132,6 @@ inline void next_task(types::list<thread*>::iterator_type target)
         add_to_ready_list(ptr);
 }
 
-extern "C" void NORETURN to_kernel(interrupt_stack* ret_stack);
-extern "C" void NORETURN to_user(interrupt_stack* ret_stack);
-
 process* findproc(pid_t pid);
 
 void k_new_thread(void (*func)(void*), void* data);

+ 10 - 1
include/types/elf.hpp

@@ -109,7 +109,16 @@ struct PACKED elf32_program_header_entry {
     uint32_t align;
 };
 
+struct elf32_load_data {
+    const char* exec;
+    const char** argv;
+    int errcode;
+    void* eip;
+    uint32_t* sp;
+    bool system;
+};
+
 // TODO: environment variables
-int elf32_load(const char* exec, const char** argv, interrupt_stack* intrpt_stack, bool system);
+int elf32_load(elf32_load_data* data);
 
 } // namespace types::elf

+ 68 - 45
src/asm/interrupt.s

@@ -215,15 +215,54 @@ syscall_stub:
     # restore stack
     popl %esp
 
+.globl _syscall_stub_fork_return
+.type  _syscall_stub_fork_return @function
+_syscall_stub_fork_return:
     popal
 syscall_stub_end:
     iret
 
-# parameters:
-# interrupt_stack* ret_stack
-.globl to_kernel
-.type  to_kernel @function
-to_kernel:
+# parameters
+# #1: uint32_t* curr_esp
+# #2: uint32_t next_esp
+.globl asm_ctx_switch
+.type  asm_ctx_switch @function
+asm_ctx_switch:
+    movl 4(%esp), %ecx
+    movl 8(%esp), %eax
+
+    push $_ctx_switch_return
+    push %ebx
+    push %edi
+    push %esi
+    push %ebp
+    pushfl
+
+    movl %esp, (%ecx)
+    movl %eax, %esp
+
+    popfl
+    pop %ebp
+    pop %esi
+    pop %edi
+    pop %ebx
+
+    ret
+
+_ctx_switch_return:
+    ret
+
+# param:
+# #1: uint32_t esp
+# #2: void (*k_init)()
+.globl go_kernel
+.type  go_kernel @function
+go_kernel:
+    movl 4(%esp), %eax
+    movl 8(%esp), %ecx
+    movl %eax, %esp
+    pushl %ecx
+
     movw $0x10, %ax
     movw %ax, %ss
     movw %ax, %ds
@@ -231,55 +270,39 @@ to_kernel:
     movw %ax, %fs
     movw %ax, %gs
 
-    movl 4(%esp), %eax
-
-    movl (%eax), %edi
-    movl 4(%eax), %esi
-    movl 8(%eax), %ebp
-    movl 12(%eax), %esp # %esp is the dst stack
-    movl 16(%eax), %ebx
-    movl 20(%eax), %edx
-    movl 24(%eax), %ecx
-#   TODO: optimize for caching
-#   movl 28(%eax), %eax # we deal with %eax later
+    xorl %eax, %eax
+    xorl %ebx, %ebx
+    xorl %ecx, %ecx
+    xorl %edx, %edx
+    xorl %esi, %esi
+    xorl %edi, %edi
+    xorl %ebp, %ebp
 
-    pushl 40(%eax) # %eflags
-    pushl $0x08    # %cs
-    pushl 32(%eax) # %eip
+# eflags: IN
+    pushl $0x200
+    popfl
 
-    movl 28(%eax), %eax
-
-    iret
+    ret
 
-# parameters:
-# interrupt_stack* ret_stack
-.globl to_user
-.type  to_user @function
-to_user:
+# parameters
+# #1: eip
+# #2: esp
+.globl go_user
+.type  go_user @function
+go_user:
     movw $0x23, %ax
     movw %ax, %ds
     movw %ax, %es
     movw %ax, %fs
     movw %ax, %gs
 
-    movl 4(%esp), %edi
-
-    movl 40(%edi), %ebp # save eflags
-    movl 32(%edi), %esi # save eip
-
-    movl 28(%edi), %eax
-    movl 24(%edi), %ecx
-    movl 20(%edi), %edx
-    movl 16(%edi), %ebx
-
-    pushl $0x23    # %ss
-    pushl 12(%edi) # %esp
-    pushl %ebp     # %eflags
-    pushl $0x1b    # %cs
-    pushl %esi     # %eip
+    movl 4(%esp), %eax
+    movl 8(%esp), %ecx
 
-    movl 8(%edi), %ebp
-    movl 4(%edi), %esi
-    movl (%edi), %edi
+    pushl $0x23
+    pushl %ecx
+    pushl $0x200
+    pushl $0x1b
+    pushl %eax
 
     iret

+ 2 - 2
src/kernel/interrupt.cpp

@@ -219,11 +219,11 @@ extern "C" void int14_handler(int14_data* d)
     }
 }
 
-extern "C" void irq0_handler(struct interrupt_stack* d)
+extern "C" void irq0_handler(interrupt_stack*)
 {
     inc_tick();
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    do_scheduling(d);
+    schedule();
 }
 // keyboard interrupt
 extern "C" void irq1_handler(void)

+ 125 - 139
src/kernel/process.cpp

@@ -7,27 +7,46 @@
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
 #include <kernel/stdio.h>
-#include <kernel/syscall.hpp>
 #include <kernel/tty.h>
 #include <kernel/vfs.hpp>
 #include <kernel_main.h>
 #include <types/allocator.hpp>
+#include <types/assert.h>
 #include <types/elf.hpp>
 #include <types/hash_map.hpp>
 #include <types/list.hpp>
 #include <types/lock.hpp>
 #include <types/status.h>
+#include <types/stdint.h>
 #include <types/types.h>
 
 static bool is_scheduler_ready;
 static types::list<process>* processes;
 static typename types::hash_map<pid_t, types::list<process>::iterator_type, types::linux_hasher<pid_t>>* idx_processes;
 static types::list<thread*>* ready_thds;
-static pid_t max_pid;
 static void (*volatile kthreadd_new_thd_func)(void*);
 static void* volatile kthreadd_new_thd_data;
 static types::mutex kthreadd_mtx;
 
+namespace kernel {
+
+struct no_irq_guard {
+    explicit no_irq_guard()
+    {
+        asm_cli();
+    }
+
+    no_irq_guard(const no_irq_guard&) = delete;
+    no_irq_guard& operator=(const no_irq_guard&) = delete;
+
+    ~no_irq_guard()
+    {
+        asm_sti();
+    }
+};
+
+} // namespace kernel
+
 process::process(process&& val)
     : mms(types::move(val.mms))
     , thds(types::move(val.thds))
@@ -38,116 +57,82 @@ process::process(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(process& val, const thread& main_thd)
+process::process(const process& val, const thread& main_thd)
     : mms(*kernel_mms)
     , attr { .system = val.attr.system }
-    , pid { ++max_pid }
+    , pid { process::alloc_pid() }
     , ppid { val.pid }
 {
     auto iter_thd = thds.emplace_back(main_thd);
     iter_thd->owner = this;
 
-    // TODO: allocate low mem
-    k_esp = (void*)to_pp(alloc_n_raw_pages(2));
-    memcpy(k_esp, (char*)main_thd.owner->k_esp - THREAD_KERNEL_STACK_SIZE, THREAD_KERNEL_STACK_SIZE);
-    k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
-
-    if (val.attr.system) {
-        auto orig_k_esp = (uint32_t)main_thd.owner->k_esp;
-
-        iter_thd->regs.ebp -= orig_k_esp;
-        iter_thd->regs.ebp += (uint32_t)k_esp;
+    for (auto& area : val.mms) {
+        if (area.is_ident())
+            continue;
 
-        iter_thd->regs.esp -= orig_k_esp;
-        iter_thd->regs.esp += (uint32_t)k_esp;
-    } else {
-        for (auto& area : val.mms) {
-            if (area.is_ident())
-                continue;
-
-            mms.mirror_area(area);
-        }
+        mms.mirror_area(area);
     }
 }
 
-process::process(void* start_eip)
+process::process(void)
     : mms(*kernel_mms)
     , thds {}
     , attr { .system = 1 }
-    , pid { ++max_pid }
+    , pid { process::alloc_pid() }
     , ppid { 1 }
 {
-    // TODO: allocate low mem
-    k_esp = (void*)to_pp(alloc_n_raw_pages(2));
-    memset((char*)k_esp, 0x00, THREAD_KERNEL_STACK_SIZE);
-    k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
-
-    auto thd = thds.emplace_back(thread {
-        .eip = start_eip,
-        .owner = this,
-        .regs {
-            .edi {},
-            .esi {},
-            .ebp = reinterpret_cast<uint32_t>(k_esp),
-            .esp = reinterpret_cast<uint32_t>(k_esp),
-            .ebx {},
-            .edx {},
-            .ecx {},
-            .eax {},
-        },
-        .eflags {},
-        .attr {
-            .system = 1,
-            .ready = 1,
-            .wait = 0,
-        },
-    });
-    ready_thds->push_back(thd.ptr());
+    auto thd = thds.emplace_back(this, true);
+
+    add_to_ready_list(thd.ptr());
 }
 
-void NORETURN _kernel_init(void)
+process::process(void (*func)(void), pid_t _ppid)
+    : mms(*kernel_mms)
+    , thds {}
+    , attr { .system = 1 }
+    , pid { process::alloc_pid() }
+    , ppid { _ppid }
 {
-    // TODO: parse kernel parameters
-    auto* _new_fs = fs::register_fs(types::kernel_allocator_new<fs::fat::fat32>(fs::vfs_open("/dev/hda1")->ind));
-    int ret = fs::fs_root->ind->fs->mount(fs::vfs_open("/mnt"), _new_fs);
-    if (unlikely(ret != GB_OK))
-        syscall(0x03);
-
-    interrupt_stack intrpt_stack {};
-    intrpt_stack.eflags = 0x200; // STI
-    const char* argv[] = { "/mnt/INIT.ELF", nullptr };
-    types::elf::elf32_load("/mnt/INIT.ELF", argv, &intrpt_stack, 0);
+    auto thd = thds.emplace_back(this, true);
+
+    add_to_ready_list(thd.ptr());
+
+    auto* esp = &thd->esp;
+
+    // return(start) address
+    push_stack(esp, (uint32_t)func);
+    // ebx
+    push_stack(esp, 0);
+    // edi
+    push_stack(esp, 0);
+    // esi
+    push_stack(esp, 0);
+    // ebp
+    push_stack(esp, 0);
+    // eflags
+    push_stack(esp, 0x200);
+}
 
-    asm_cli();
-    current_process->attr.system = 0;
-    current_thread->attr.system = 0;
-    to_user(&intrpt_stack);
+inline void NORETURN _noreturn_crash(void)
+{
+    for (;;)
+        assert(false);
 }
 
+extern "C" void NORETURN go_kernel(uint32_t* kstack, void (*k_main)(void));
+extern "C" void NORETURN go_user(void* eip, uint32_t* esp);
+
 void kernel_threadd_main(void)
 {
     tty_print(console, "kernel thread daemon started\n");
 
-    // fork
-    int ret = syscall(0x00);
-
-    // pid 1
-    if (ret) {
-        hw::init_ata();
-        _kernel_init();
-        // noreturn
-        syscall(0x03);
-    }
-
     for (;;) {
         if (kthreadd_new_thd_func) {
             void (*func)(void*) = nullptr;
@@ -157,23 +142,61 @@ void kernel_threadd_main(void)
                 types::lock_guard lck(kthreadd_mtx);
                 func = kthreadd_new_thd_func;
                 data = kthreadd_new_thd_data;
+
+                kthreadd_new_thd_func = nullptr;
+                kthreadd_new_thd_data = nullptr;
             }
 
-            // syscall_fork
-            int ret = syscall(0x00);
+            // TODO
+            (void)func, (void)data;
+            assert(false);
 
-            if (ret == 0) {
-                // child process
-                func(data);
-                // the function shouldn't return here
-                syscall(0x03);
-            }
+            // syscall_fork
+            // int ret = syscall(0x00);
+
+            // if (ret == 0) {
+            //     // child process
+            //     func(data);
+            //     // the function shouldn't return here
+            //     assert(false);
+            // }
         }
         // TODO: sleep here to wait for new_kernel_thread event
         asm_hlt();
     }
 }
 
+void NORETURN _kernel_init(void)
+{
+    {
+        kernel::no_irq_guard grd;
+
+        add_to_process_list(process { kernel_threadd_main, 1 });
+    }
+    hw::init_ata();
+
+    // TODO: parse kernel parameters
+    auto* _new_fs = fs::register_fs(types::kernel_allocator_new<fs::fat::fat32>(fs::vfs_open("/dev/hda1")->ind));
+    int ret = fs::fs_root->ind->fs->mount(fs::vfs_open("/mnt"), _new_fs);
+    assert_likely(ret == GB_OK);
+
+    current_process->attr.system = 0;
+    current_thread->attr.system = 0;
+
+    const char* argv[] = { "/mnt/INIT.ELF", nullptr };
+
+    types::elf::elf32_load_data d;
+    d.exec = "/mnt/INIT.ELF";
+    d.argv = argv;
+    d.system = false;
+
+    assert(types::elf::elf32_load(&d) == GB_OK);
+
+    is_scheduler_ready = true;
+
+    go_user(d.eip, d.sp);
+}
+
 void k_new_thread(void (*func)(void*), void* data)
 {
     types::lock_guard lck(kthreadd_mtx);
@@ -188,8 +211,8 @@ void NORETURN init_scheduler()
     idx_processes = types::kernel_allocator_pnew(idx_processes);
     idx_child_processes = types::kernel_allocator_pnew(idx_child_processes);
 
-    add_to_process_list(process((void*)kernel_threadd_main));
-    auto init = findproc(1);
+    auto pid = add_to_process_list(process {});
+    auto init = findproc(pid);
 
     // we need interrupts enabled for cow mapping so now we disable it
     // in case timer interrupt mess things up
@@ -199,50 +222,14 @@ void NORETURN init_scheduler()
     current_thread = init->thds.begin().ptr();
 
     tss.ss0 = KERNEL_DATA_SEGMENT;
-    tss.esp0 = (uint32_t)init->k_esp;
+    tss.esp0 = current_thread->kstack;
 
     asm_switch_pd(current_process->mms.m_pd);
 
-    is_scheduler_ready = true;
-
-    interrupt_stack intrpt_stack {};
-    process_context_load(&intrpt_stack, current_process);
-    thread_context_load(&intrpt_stack, current_thread);
-    to_kernel(&intrpt_stack);
-}
-
-void thread_context_save(interrupt_stack* int_stack, thread* thd)
-{
-    thd->eflags = int_stack->eflags;
-    thd->eip = int_stack->v_eip;
-    memcpy(&thd->regs, &int_stack->s_regs, sizeof(regs_32));
-    if (thd->attr.system)
-        thd->regs.esp = int_stack->s_regs.esp + 0x0c;
-    else
-        thd->regs.esp = int_stack->esp;
-}
-
-void thread_context_load(interrupt_stack* int_stack, thread* thd)
-{
-    int_stack->eflags = (thd->eflags | 0x200); // OR $STI
-    int_stack->v_eip = thd->eip;
-    memcpy(&int_stack->s_regs, &thd->regs, sizeof(regs_32));
-    current_thread = thd;
+    go_kernel(current_thread->esp, _kernel_init);
 }
 
-void process_context_save(interrupt_stack*, process*)
-{
-}
-
-void process_context_load(interrupt_stack*, process* proc)
-{
-    if (!proc->attr.system)
-        tss.esp0 = (uint32_t)proc->k_esp;
-    asm_switch_pd(proc->mms.m_pd);
-    current_process = proc;
-}
-
-void add_to_process_list(process&& proc)
+pid_t add_to_process_list(process&& proc)
 {
     auto iter = processes->emplace_back(types::move(proc));
     idx_processes->insert(iter->pid, iter);
@@ -254,6 +241,8 @@ void add_to_process_list(process&& proc)
     }
 
     children->value.push_back(iter->pid);
+
+    return iter->pid;
 }
 
 void add_to_ready_list(thread* thd)
@@ -283,7 +272,8 @@ process* findproc(pid_t pid)
     return idx_processes->find(pid)->value.ptr();
 }
 
-void do_scheduling(interrupt_stack* intrpt_data)
+extern "C" void asm_ctx_switch(uint32_t** curr_esp, uint32_t* next_esp);
+void schedule()
 {
     if (unlikely(!is_scheduler_ready))
         return;
@@ -298,19 +288,15 @@ void do_scheduling(interrupt_stack* intrpt_data)
 
     process* proc = thd->owner;
     if (current_process != proc) {
-        if (current_process)
-            process_context_save(intrpt_data, current_process);
-        process_context_load(intrpt_data, proc);
+        asm_switch_pd(proc->mms.m_pd);
+        current_process = proc;
     }
 
-    if (current_thread)
-        thread_context_save(intrpt_data, current_thread);
-    thread_context_load(intrpt_data, thd);
+    auto* curr_thd = current_thread;
 
+    current_thread = thd;
+    tss.esp0 = current_thread->kstack;
     next_task(iter_thd);
 
-    if (thd->attr.system)
-        to_kernel(intrpt_data);
-    else
-        to_user(intrpt_data);
+    asm_ctx_switch(&curr_thd->esp, thd->esp);
 }

+ 73 - 29
src/kernel/syscall.cpp

@@ -1,46 +1,83 @@
 #include <asm/port_io.h>
+#include <asm/sys.h>
 #include <kernel/interrupt.h>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
 #include <kernel/syscall.hpp>
 #include <kernel/tty.h>
+#include <kernel_main.h>
 #include <types/allocator.hpp>
+#include <types/assert.h>
 #include <types/elf.hpp>
+#include <types/status.h>
+#include <types/stdint.h>
+
+#define SYSCALL_SET_RETURN_VAL_EAX(_eax) \
+    data->s_regs.eax = ((decltype(data->s_regs.eax))(_eax))
+
+#define SYSCALL_SET_RETURN_VAL_EDX(_edx) \
+    data->s_regs.edx = ((decltype(data->s_regs.edx))(_edx))
+
+#define SYSCALL_SET_RETURN_VAL(_eax, _edx) \
+    SYSCALL_SET_RETURN_VAL_EAX(_eax);      \
+    SYSCALL_SET_RETURN_VAL_EDX(_edx)
 
 syscall_handler syscall_handlers[8];
 
 void _syscall_not_impl(interrupt_stack* data)
 {
-    data->s_regs.eax = 0xffffffff;
-    data->s_regs.edx = 0xffffffff;
+    SYSCALL_SET_RETURN_VAL(0xffffffff, 0xffffffff);
 }
 
+extern "C" void _syscall_stub_fork_return(void);
 void _syscall_fork(interrupt_stack* data)
 {
-    thread_context_save(data, current_thread);
-    process_context_save(data, current_process);
-
-    process new_proc(*current_process, *current_thread);
-    thread* new_thd = new_proc.thds.begin().ptr();
-
-    // return value
-    new_thd->regs.eax = 0;
-    data->s_regs.eax = new_proc.pid;
-
-    new_thd->regs.edx = 0;
-    data->s_regs.edx = 0;
-
-    add_to_process_list(types::move(new_proc));
-    add_to_ready_list(new_thd);
+    auto newpid = add_to_process_list(process { *current_process, *current_thread });
+    auto* newproc = findproc(newpid);
+    thread* newthd = newproc->thds.begin().ptr();
+    add_to_ready_list(newthd);
+
+    // create fake interrupt stack
+    push_stack(&newthd->esp, data->ss);
+    push_stack(&newthd->esp, data->esp);
+    push_stack(&newthd->esp, data->eflags);
+    push_stack(&newthd->esp, data->cs);
+    push_stack(&newthd->esp, (uint32_t)data->v_eip);
+
+    // eax
+    push_stack(&newthd->esp, 0);
+    push_stack(&newthd->esp, data->s_regs.ecx);
+    // edx
+    push_stack(&newthd->esp, 0);
+    push_stack(&newthd->esp, data->s_regs.ebx);
+    push_stack(&newthd->esp, data->s_regs.esp);
+    push_stack(&newthd->esp, data->s_regs.ebp);
+    push_stack(&newthd->esp, data->s_regs.esi);
+    push_stack(&newthd->esp, data->s_regs.edi);
+
+    // ctx_switch stack
+    // return address
+    push_stack(&newthd->esp, (uint32_t)_syscall_stub_fork_return);
+    // ebx
+    push_stack(&newthd->esp, 0);
+    // edi
+    push_stack(&newthd->esp, 0);
+    // esi
+    push_stack(&newthd->esp, 0);
+    // ebp
+    push_stack(&newthd->esp, 0);
+    // eflags
+    push_stack(&newthd->esp, 0);
+
+    SYSCALL_SET_RETURN_VAL(newpid, 0);
 }
 
 void _syscall_write(interrupt_stack* data)
 {
     tty_print(console, reinterpret_cast<const char*>(data->s_regs.edi));
 
-    data->s_regs.eax = 0;
-    data->s_regs.edx = 0;
+    SYSCALL_SET_RETURN_VAL(0, 0);
 }
 
 void _syscall_sleep(interrupt_stack* data)
@@ -48,10 +85,9 @@ void _syscall_sleep(interrupt_stack* data)
     current_thread->attr.ready = 0;
     current_thread->attr.wait = 1;
 
-    data->s_regs.eax = 0;
-    data->s_regs.edx = 0;
+    SYSCALL_SET_RETURN_VAL(0, 0);
 
-    do_scheduling(data);
+    schedule();
 }
 
 void _syscall_crash(interrupt_stack*)
@@ -71,7 +107,15 @@ void _syscall_exec(interrupt_stack* data)
 
     current_process->mms.clear_user();
 
-    types::elf::elf32_load(exec, argv, data, current_process->attr.system);
+    types::elf::elf32_load_data d;
+    d.argv = argv;
+    d.exec = exec;
+    d.system = false;
+
+    assert(types::elf::elf32_load(&d) == GB_OK);
+
+    data->v_eip = d.eip;
+    data->esp = (uint32_t)d.sp;
 }
 
 // @param exit_code
@@ -86,10 +130,9 @@ void _syscall_exit(interrupt_stack* data)
 
     // terminating a whole process:
 
-    // clear threads
+    // remove this thread from ready list
+    current_thread->attr.ready = 0;
     remove_from_ready_list(current_thread);
-    current_process->thds.clear();
-    current_thread = nullptr;
 
     // TODO: write back mmap'ped files and close them
 
@@ -104,12 +147,13 @@ void _syscall_exit(interrupt_stack* data)
         idx_child_processes->remove(children);
     }
 
-    current_process = nullptr;
-
     // TODO: notify parent process and init
 
     // switch to new process and continue
-    do_scheduling(data);
+    schedule();
+
+    // we should not return to here
+    MAKE_BREAK_POINT();
 }
 
 void init_syscall(void)

+ 23 - 28
src/types/elf.cpp

@@ -1,21 +1,21 @@
+#include <kernel/errno.h>
 #include <kernel/stdio.h>
-#include <kernel/syscall.hpp>
+#include <types/assert.h>
 #include <types/elf.hpp>
 #include <types/stdint.h>
 
 template <typename T>
-constexpr void _user_push(uint32_t& sp, T d)
+constexpr void _user_push(uint32_t** sp, T d)
 {
-    sp -= sizeof(T);
-    *(T*)sp = d;
+    *sp -= sizeof(T);
+    *(T*)*sp = d;
 }
 
-int types::elf::elf32_load(const char* exec, const char** argv, interrupt_stack* intrpt_stack, bool system)
+int types::elf::elf32_load(types::elf::elf32_load_data* d)
 {
-    auto* ent_exec = fs::vfs_open(exec);
+    auto* ent_exec = fs::vfs_open(d->exec);
     if (!ent_exec) {
-        intrpt_stack->s_regs.eax = ENOENT;
-        intrpt_stack->s_regs.edx = 0;
+        d->errcode = ENOENT;
         return GB_FAILED;
     }
 
@@ -28,8 +28,7 @@ int types::elf::elf32_load(const char* exec, const char** argv, interrupt_stack*
         0, sizeof(types::elf::elf32_header));
 
     if (n_read != sizeof(types::elf::elf32_header)) {
-        intrpt_stack->s_regs.eax = EINVAL;
-        intrpt_stack->s_regs.edx = 0;
+        d->errcode = EINVAL;
         return GB_FAILED;
     }
 
@@ -43,8 +42,7 @@ int types::elf::elf32_load(const char* exec, const char** argv, interrupt_stack*
 
     // broken file or I/O error
     if (n_read != phents_size) {
-        intrpt_stack->s_regs.eax = EINVAL;
-        intrpt_stack->s_regs.edx = 0;
+        d->errcode = EINVAL;
         return GB_FAILED;
     }
 
@@ -52,10 +50,9 @@ int types::elf::elf32_load(const char* exec, const char** argv, interrupt_stack*
         if (phents->type != types::elf::elf32_program_header_entry::PT_LOAD)
             continue;
 
-        auto ret = mmap((void*)phents->vaddr, phents->memsz, ent_exec->ind, phents->offset, 1, system);
+        auto ret = mmap((void*)phents->vaddr, phents->memsz, ent_exec->ind, phents->offset, 1, d->system);
         if (ret != GB_OK) {
-            intrpt_stack->s_regs.eax = ret;
-            intrpt_stack->s_regs.edx = 0;
+            d->errcode = ret;
             return GB_FAILED;
         }
 
@@ -64,32 +61,30 @@ int types::elf::elf32_load(const char* exec, const char** argv, interrupt_stack*
 
     // map stack area
     auto ret = mmap((void*)types::elf::ELF_STACK_TOP, types::elf::ELF_STACK_SIZE, fs::vfs_open("/dev/null")->ind, 0, 1, 0);
-    if (ret != GB_OK)
-        syscall(0x03);
+    assert_likely(ret == GB_OK);
 
-    intrpt_stack->v_eip = (void*)hdr.entry;
-    memset((void*)&intrpt_stack->s_regs, 0x00, sizeof(regs_32));
+    d->eip = (void*)hdr.entry;
+    d->sp = reinterpret_cast<uint32_t*>(types::elf::ELF_STACK_BOTTOM);
 
-    auto* sp = &intrpt_stack->s_regs.esp;
-    *sp = types::elf::ELF_STACK_BOTTOM;
+    auto* sp = &d->sp;
 
     types::vector<const char*> arr;
-    for (const char** ptr = argv; *ptr != nullptr; ++ptr) {
+    for (const char** ptr = d->argv; *ptr != nullptr; ++ptr) {
         auto len = strlen(*ptr);
         *sp -= (len + 1);
-        *sp = ((*sp >> 4) << 4);
+        *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
         memcpy((char*)*sp, *ptr, len + 1);
         arr.push_back((const char*)*sp);
     }
 
     *sp -= sizeof(const char*) * arr.size();
-    *sp = ((*sp >> 4) << 4);
+    *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
     memcpy((char*)*sp, arr.data(), sizeof(const char*) * arr.size());
 
-    _user_push(*sp, 0);
-    _user_push(*sp, 0);
-    _user_push(*sp, *sp + 8);
-    _user_push(*sp, arr.size());
+    _user_push(sp, 0);
+    _user_push(sp, 0);
+    _user_push(sp, *sp + 8);
+    _user_push(sp, arr.size());
 
     return GB_OK;
 }