Prechádzať zdrojové kódy

feat(process): enter user mode

greatbridf 2 rokov pred
rodič
commit
342ecc0e21

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

+ 4 - 0
include/kernel/mm.hpp

@@ -35,6 +35,7 @@ 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 +138,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

+ 26 - 0
include/kernel/process.hpp

@@ -0,0 +1,26 @@
+#pragma once
+
+#include <kernel/task.h>
+#include <types/types.h>
+
+#ifdef __cplusplus
+#include <kernel/mm.hpp>
+
+struct process {
+    mm_list* mms;
+    void* kernel_esp;
+    void* eip;
+    uint16_t kernel_ss;
+    uint16_t cs;
+};
+
+// in process.cpp
+extern process* current_process;
+
+extern "C" void NORETURN init_scheduler(tss32_t* tss);
+
+#else
+
+void NORETURN init_scheduler(struct tss32_t* tss);
+
+#endif

+ 2 - 0
include/kernel/task.h

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

+ 2 - 1
include/kernel_main.h

@@ -1,4 +1,5 @@
 #pragma once
+#include <types/types.h>
 
 static inline void __break_point(void)
 {
@@ -12,4 +13,4 @@ static inline void __break_point(void)
 
 #define KERNEL_START_ADDR (0x00100000)
 
-void kernel_main(void);
+void NORETURN kernel_main(void);

+ 7 - 0
include/types/list.hpp

@@ -166,6 +166,13 @@ public:
         tail->connect(head);
     }
 
+    list(const list<T, Allocator>& v)
+        : list()
+    {
+        for (const auto& item : v)
+            push_back(item);
+    }
+
     ~list() noexcept
     {
         for (auto iter = begin(); iter != end(); ++iter) {

+ 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

+ 12 - 15
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,21 +51,11 @@ 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
@@ -67,10 +63,11 @@ go_user_space_example:
     movw %ax, %gs
 
     movl %esp, %eax
+    movl 4(%esp), %ebx
     pushl $((4 * 8) | 3)
     pushl %eax
     pushf
     pushl $((3 * 8) | 3)
-    pushl $_test_user_space_program
+    pushl %ebx
 
     iret

+ 9 - 3
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>
@@ -147,6 +148,11 @@ struct PACKED int14_data {
 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;
@@ -160,14 +166,14 @@ extern "C" void int14_handler(struct int14_data* d)
 
     // kernel code
     if (d->cs == KERNEL_CODE_SEGMENT) {
-        if (is_l_ptr_valid(kernel_mms, d->l_addr) != GB_OK) {
+        if (is_l_ptr_valid(mms, d->l_addr) != GB_OK) {
             goto kill;
         }
-        struct page* page = find_page_by_l_ptr(kernel_mms, d->l_addr);
+        struct page* page = find_page_by_l_ptr(mms, d->l_addr);
 
         // copy on write
         if (d->error_code.write == 1 && page->attr.cow == 1) {
-            page_directory_entry* pde = mms_get_pd(kernel_mms) + linr_addr_to_pd_i(d->l_addr);
+            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(d->l_addr);
 

+ 21 - 3
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)
 {

+ 0 - 0
src/kernel/process.c


+ 69 - 0
src/kernel/process.cpp

@@ -0,0 +1,69 @@
+#include <asm/sys.h>
+#include <kernel/mm.hpp>
+#include <kernel/process.hpp>
+#include <kernel/stdio.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 struct process _init;
+process* current_process;
+
+static inline void create_init_process(void)
+{
+    _init.kernel_esp = align_down_to_16byte(k_malloc(4096 * 1024));
+    _init.kernel_ss = 0x10;
+    _init.mms = types::kernel_allocator_new<mm_list>(*kernel_mms);
+
+    page_directory_entry* pd = alloc_pd();
+    memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
+
+    for (auto& item : *_init.mms) {
+        item.pd = pd;
+    }
+
+    _init.mms->push_back(mm {
+        .start = 0x40000000,
+        .attr = {
+            .read = 1,
+            .write = 1,
+            .system = 0,
+        },
+        .pgs = types::kernel_allocator_new<page_arr>(),
+        .pd = pd,
+    });
+
+    auto user_mm = ++_init.mms->begin();
+
+    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;
+    asm_switch_pd(pd);
+
+    // movl $0x01919810, %eax
+    // movl $0x00114514, %ebx
+    // jmp $.
+    unsigned char instruction[] = {
+        0xb8, 0x10, 0x98, 0x91, 0x01, 0xbb, 0x14, 0x45, 0x11, 0x00, 0xeb, 0xfe
+    };
+
+    void* user_mem = (void*)0x40000000U;
+    memcpy(user_mem, instruction, sizeof(instruction));
+}
+
+void NORETURN init_scheduler(struct tss32_t* tss)
+{
+    create_init_process();
+
+    tss->esp0 = (uint32_t)_init.kernel_esp;
+    tss->ss0 = _init.kernel_ss;
+
+    go_user_space((void*)0x40000000U);
+}

+ 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];
+static 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);
 }