Эх сурвалжийг харах

feat(process): scheduling

greatbridf 2 жил өмнө
parent
commit
be01268409

+ 9 - 0
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.

+ 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)

+ 2 - 0
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;
 };

+ 9 - 2
include/kernel/process.hpp

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <kernel/interrupt.h>
 #include <kernel/task.h>
 #include <types/types.h>
 
@@ -17,6 +18,11 @@ struct process_attr {
 struct thread {
     void* eip;
     process* owner;
+    regs_32 regs;
+    uint32_t eflags;
+    uint16_t cs;
+    uint16_t ss;
+    uint32_t esp;
 };
 
 struct process {
@@ -30,10 +36,11 @@ struct process {
 // in process.cpp
 extern process* current_process;
 
-extern "C" void NORETURN init_scheduler(tss32_t* tss);
+extern "C" void NORETURN init_scheduler();
+void context_switch(irq0_data* intrpt_data);
 
 #else
 
-void NORETURN init_scheduler(struct tss32_t* tss);
+void NORETURN init_scheduler();
 
 #endif

+ 8 - 0
include/kernel_main.h

@@ -14,3 +14,11 @@ static inline void __break_point(void)
 #define KERNEL_START_ADDR (0x00100000)
 
 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

+ 5 - 2
src/asm/sys.s

@@ -62,11 +62,14 @@ go_user_space:
     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 %ebx
 

+ 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

+ 2 - 10
src/kernel/interrupt.cpp

@@ -140,7 +140,7 @@ struct PACKED int14_data {
     struct regs_32 s_regs;
     struct page_fault_error_code error_code;
     void* v_eip;
-    uint16_t cs;
+    uint32_t cs;
     uint32_t eflags;
 };
 
@@ -214,18 +214,10 @@ kill:
     asm_hlt();
 }
 
-struct PACKED irq0_data {
-    struct regs_32 s_regs;
-    void* v_eip;
-    uint16_t cs;
-    uint32_t eflags;
-    uint32_t esp;
-    uint16_t ss;
-};
-
 extern "C" void irq0_handler(struct irq0_data* d)
 {
     inc_tick();
+    context_switch(d);
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }
 // keyboard interrupt

+ 153 - 16
src/kernel/process.cpp

@@ -1,7 +1,9 @@
+#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);
@@ -11,26 +13,33 @@ static inline void* align_down_to_16byte(void* addr)
     return (void*)((uint32_t)addr & 0xfffffff0);
 }
 
-static process* _init;
+thread* current_thread;
 process* current_process;
 
+static types::list<process>* processes;
+static types::list<thread*>* ready_thds;
+
 static inline void create_init_process(void)
 {
-    _init = types::kernel_allocator_new<process>();
+    auto init = processes->emplace_back();
+
+    init->kernel_esp = align_down_to_16byte((char*)k_malloc(THREAD_KERNEL_STACK_SIZE) + THREAD_KERNEL_STACK_SIZE);
+    memset((char*)init->kernel_esp - THREAD_KERNEL_STACK_SIZE, 0x00, THREAD_KERNEL_STACK_SIZE);
+    init->kernel_ss = 0x10;
+    init->attr.system = 0;
+    init->mms = *kernel_mms;
 
-    _init->kernel_esp = align_down_to_16byte(k_malloc(4096 * 1024));
-    _init->kernel_ss = 0x10;
-    _init->attr.system = 0;
-    _init->mms = *kernel_mms;
+    tss.esp0 = (uint32_t)init->kernel_esp;
+    tss.ss0 = init->kernel_ss;
 
     page_directory_entry* pd = alloc_pd();
     memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
 
-    for (auto& item : _init->mms) {
+    for (auto& item : init->mms) {
         item.pd = pd;
     }
 
-    auto user_mm = _init->mms.emplace_back(mm {
+    auto user_mm = init->mms.emplace_back(mm {
         .start = 0x40000000,
         .attr = {
             .read = 1,
@@ -41,16 +50,23 @@ static inline void create_init_process(void)
         .pd = pd,
     });
 
-    _init->thds.push_back(thread {
+    auto thd = init->thds.emplace_back(thread {
         .eip = (void*)0x40000000U,
-        .owner = _init,
+        .owner = init.ptr(),
+        .regs {},
+        .eflags {},
+        .cs = USER_CODE_SELECTOR,
+        .ss = USER_DATA_SELECTOR,
+        .esp = 0x40100000U,
     });
+    ready_thds->push_back(thd.ptr());
 
     for (int i = 0; i < 1 * 1024 * 1024 / PAGE_SIZE; ++i) {
         k_map(user_mm.ptr(), &empty_page, 1, 1, 0, 1);
     }
 
-    current_process = _init;
+    current_process = init.ptr();
+    current_thread = thd.ptr();
     asm_switch_pd(pd);
 
     // movl $0x01919810, %eax
@@ -64,13 +80,134 @@ static inline void create_init_process(void)
     memcpy(user_mem, instruction, sizeof(instruction));
 }
 
-void NORETURN init_scheduler(struct tss32_t* tss)
+static inline void create_test_process(void)
 {
-    create_init_process();
+    auto proc = processes->emplace_back();
+    proc->attr.system = 0;
+    proc->kernel_esp = align_down_to_16byte((char*)k_malloc(THREAD_KERNEL_STACK_SIZE) + THREAD_KERNEL_STACK_SIZE);
+    memset((char*)proc->kernel_esp - THREAD_KERNEL_STACK_SIZE, 0x00, THREAD_KERNEL_STACK_SIZE);
+    proc->kernel_ss = KERNEL_DATA_SEGMENT;
+
+    proc->mms = *kernel_mms;
+
+    page_directory_entry* pd = alloc_pd();
+    memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
+    for (auto& item : proc->mms)
+        item.pd = pd;
+
+    auto user_mm = proc->mms.emplace_back(mm {
+        .start = 0x40000000,
+        .attr = {
+            .read = 1,
+            .write = 1,
+            .system = 0,
+        },
+        .pgs = types::kernel_allocator_new<page_arr>(),
+        .pd = pd,
+    });
 
-    // TODO: fix it
-    tss->esp0 = (uint32_t)_init->kernel_esp;
-    tss->ss0 = _init->kernel_ss;
+    auto thd = proc->thds.emplace_back(thread {
+        .eip = (void*)0x40000000U,
+        .owner = proc.ptr(),
+        .regs {},
+        .eflags {},
+        .cs = USER_CODE_SELECTOR,
+        .ss = USER_DATA_SELECTOR,
+        .esp = 0x40100000U,
+    });
+    ready_thds->push_back(thd.ptr());
+
+    for (int i = 0; i < 1 * 1024 * 1024 / PAGE_SIZE; ++i)
+        k_map(user_mm.ptr(), &empty_page, 1, 1, 0, 1);
+
+    page_directory_entry* init_pd = (page_directory_entry*)p_ptr_to_v_ptr(current_pd());
+
+    auto old_proc = current_process;
+    auto old_thd = current_thread;
+
+    current_process = proc.ptr();
+    current_thread = thd.ptr();
+    asm_switch_pd(pd);
 
+    unsigned char instruction[] = {
+        0xb8, 0x00, 0x81, 0x19, 0x19, 0xbb, 0x00, 0x14, 0x45, 0x11, 0xeb, 0xfe
+    };
+
+    void* user_mem = (void*)0x40000000U;
+    memcpy(user_mem, instruction, sizeof(instruction));
+
+    current_process = old_proc;
+    current_thread = old_thd;
+    asm_switch_pd(init_pd);
+}
+
+static bool is_scheduler_ready;
+
+void NORETURN init_scheduler()
+{
+    processes = types::kernel_allocator_new<types::list<process>>();
+    ready_thds = types::kernel_allocator_new<types::list<thread*>>();
+
+    create_init_process();
+    create_test_process();
+
+    asm_cli();
+    is_scheduler_ready = true;
     go_user_space((void*)0x40000000U);
 }
+
+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) {
+            current_process->kernel_esp = (void*)tss.esp0;
+            current_process->kernel_ss = tss.ss0;
+
+            tss.esp0 = (uint32_t)pro->kernel_esp;
+            tss.ss0 = pro->kernel_ss;
+        }
+
+        current_process = pro;
+        asm_switch_pd(pro->mms.begin()->pd);
+    }
+
+    // save current thread info
+    current_thread->cs = intrpt_data->cs;
+    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->cs = thd->cs;
+    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;
+        current_thread->ss = intrpt_data->ss;
+
+        intrpt_data->ss = thd->ss;
+        intrpt_data->esp = thd->esp;
+    }
+
+    ready_thds->erase(ready_thds->begin());
+    // check if the thread is ready
+    ready_thds->push_back(thd);
+
+    current_thread = thd;
+}

+ 3 - 3
src/kernel_main.c

@@ -118,7 +118,7 @@ static inline void show_mem_info(char* buf)
 }
 
 static segment_descriptor new_gdt[6];
-static struct tss32_t _tss;
+struct tss32_t tss;
 
 void load_new_gdt(void)
 {
@@ -127,7 +127,7 @@ 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);
-    create_segment_descriptor(new_gdt + 5, (uint32_t)&_tss, sizeof(_tss), 0b0000, SD_TYPE_TSS);
+    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);
@@ -200,5 +200,5 @@ void NORETURN kernel_main(void)
     vfs_read(init, buf, 128, 1, 10);
 
     printkf("switching execution to the scheduler...");
-    init_scheduler(&_tss);
+    init_scheduler(&tss);
 }