Kernel address space isolation and make the kernel heap global to all processes.
authorMinep <zelong56@gmail.com>
Mon, 30 May 2022 23:23:05 +0000 (00:23 +0100)
committerMinep <zelong56@gmail.com>
Mon, 30 May 2022 23:23:05 +0000 (00:23 +0100)
And featuring initd!

15 files changed:
lunaix-os/includes/lunaix/mm/page.h
lunaix-os/includes/lunaix/mm/vmm.h
lunaix-os/includes/lunaix/process.h
lunaix-os/kernel/asm/x86/interrupts.c
lunaix-os/kernel/asm/x86/pfault.c
lunaix-os/kernel/asm/x86/prologue.S
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/k_init.c
lunaix-os/kernel/lxinit.c
lunaix-os/kernel/mm/cow.c
lunaix-os/kernel/mm/kalloc.c
lunaix-os/kernel/mm/vmm.c
lunaix-os/kernel/process.c
lunaix-os/kernel/sched.c
lunaix-os/link/linker.ld

index a6b3162a9541379b1b35509f11015c6713be4a3b..4b6a1a15e3b1540261c984a1b0e4fd1395cdb9cb 100644 (file)
@@ -95,11 +95,13 @@ typedef struct
 
 extern void __pg_mount_point;
 
-/* 三个页挂载点: 用于临时创建&编辑页表 */
+/* ä¸\89个页æ\8c\82è½½ç\82¹ï¼\8cä¸\80个页ç\9b®å½\95æ\8c\82è½½ç\82¹ï¼\9a ç\94¨äº\8e临æ\97¶å\88\9b建&ç¼\96è¾\91页表 */
 
+#define PD_MOUNT    0xAFC00000
 #define PG_MOUNT_1  (&__pg_mount_point)
 #define PG_MOUNT_2  (&__pg_mount_point + 0x1000)
 #define PG_MOUNT_3  (&__pg_mount_point + 0x2000)
+#define PG_MOUNT_4  (&__pg_mount_point + 0x3000)
 
 
 #endif /* __LUNAIX_PAGE_H */
index 682f8d0611bd7d74a8a495ede00aa67a6825c5d5..2e9f72f67eb903be228ef7f05dd360980fa66b68 100644 (file)
@@ -119,6 +119,22 @@ vmm_lookup(void* va);
  * @return void* 包含虚拟页副本的物理页地址。
  * 
  */
-void* vmm_dup_page(void* va);
+void* vmm_dup_page(pid_t pid, void* pa);
+
+/**
+ * @brief 挂载另一个虚拟地址空间至当前虚拟地址空间
+ * 
+ * @param pde 页目录的物理地址
+ * @return void* 
+ */
+void*
+vmm_mount_pd(void* pde);
+
+/**
+ * @brief 卸载已挂载的虚拟地址空间
+ * 
+ */
+void*
+vmm_unmount_pd();
 
 #endif /* __LUNAIX_VMM_H */
index 25b1d60846f2d5649ef2538608286d0cdc78b9fa..efa11666674b9602bdc07100d8bd6bc35fe2896b 100644 (file)
@@ -18,7 +18,6 @@
 
 
 struct proc_mm {
-    heap_context_t k_heap;
     heap_context_t u_heap;
     struct mm_region* region;
 };
@@ -50,6 +49,8 @@ void push_process(struct proc_info* process);
 
 void destroy_process(pid_t pid);
 
+void* dup_pagetable(pid_t pid);
+
 /**
  * @brief 复制当前进程(LunaixOS的类 fork (unix) 实现)
  * 
index f6b55389ae68d8e43fd35db574f93301cdfb7528..8330bc263f1bb37b88bf56ff05b25ef7ecbad6d9 100644 (file)
@@ -5,6 +5,7 @@
 #include <lunaix/tty/tty.h>
 #include <lunaix/process.h>
 #include <lunaix/sched.h>
+#include <lunaix/mm/page.h>
 
 LOG_MODULE("intr")
 
@@ -29,6 +30,7 @@ intr_set_fallback_handler(int_subscriber subscribers) {
     fallback = subscribers;
 }
 
+extern x86_page_table* __kernel_ptd;
 
 void
 intr_handler(isr_param* param)
@@ -37,25 +39,29 @@ intr_handler(isr_param* param)
     //     kprintf(KDEBUG "%p", param->registers.esp);
     // }
     __current->intr_ctx = *param;
+
+    cpu_lcr3(__kernel_ptd);
+
+    isr_param *lparam = &__current->intr_ctx;
     
-    if (param->vector <= 255) {
-        int_subscriber subscriber = subscribers[param->vector];
+    if (lparam->vector <= 255) {
+        int_subscriber subscriber = subscribers[lparam->vector];
         if (subscriber) {
-            subscriber(param);
+            subscriber(lparam);
             goto done;
         }
     }
 
     if (fallback) {
-        fallback(param);
+        fallback(lparam);
         goto done;
     }
     
     kprint_panic("INT %u: (%x) [%p: %p] Unknown",
-            param->vector,
-            param->err_code,
-            param->cs,
-            param->eip);
+            lparam->vector,
+            lparam->err_code,
+            lparam->cs,
+            lparam->eip);
 
 done:
 
@@ -65,10 +71,12 @@ done:
 
     // for all external interrupts except the spurious interrupt
     //  this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5
-    if (param->vector >= EX_INTERRUPT_BEGIN && param->vector != APIC_SPIV_IV) {
+    if (lparam->vector >= EX_INTERRUPT_BEGIN && lparam->vector != APIC_SPIV_IV) {
         apic_done_servicing();
     }
 
+    cpu_lcr3(__current->page_table);
+
     *param = __current->intr_ctx;
 
     return;
index c5ec07f5f37bdf9dd61bb9975d68c1b1c2f303b6..63a40a36e89b3fb4345a7530cf20b057b9068702 100644 (file)
@@ -2,6 +2,9 @@
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/common.h>
+#include <lunaix/syslog.h>
+
+static void kprintf(const char* fmt, ...) { va_list args; va_start(args, fmt); __kprintf("PFAULT", fmt, args); va_end(args); }
 
 extern void __print_panic_msg(const char* msg, const isr_param* param);
 
@@ -14,6 +17,7 @@ intr_routine_page_fault (const isr_param* param)
         goto done;
     }
 
+    kprintf("%p", pg_fault_ptr);
     __print_panic_msg("Page fault", param);
 
 done:
index ddd2652fe64bd353c15ad5c7dc3379939723b703..ef559bbdd9398fd87236de5f3c1d8935be5b8f0f 100644 (file)
@@ -61,7 +61,9 @@
 
         call _kernel_init
 
-        /* _kernel_init 永不返回 */
+        movl $KSTACK_TOP, %esp
+
+        call _kernel_post_init
 
     1:
         hlt
index 2ea22d499124c94bd60e974cd5bd0ee974851d54..25e153f592e906528f54d6673dc8d4be8e2a653f 100644 (file)
@@ -6,12 +6,17 @@
         注意,这里的顺序非常重要。每个系统调用在这个地址表里的索引等于其调用号。
     */
     syscall_table:
+        1:
         .dc.l 0
         .dc.l dup_proc
         .dc.l schedule
         .dc.l terminate_process
         .dc.l _syscall_sbrk
         .dc.l _syscall_brk
+        2:
+        .rept __SYSCALL_MAX - (2b - 1b)/4
+            .dc.l 0
+        .endr
 
 .global syscall_hndlr
 
 
         movl  (%ebp), %eax
         cmpl  $__SYSCALL_MAX, %eax
-        jb 1f
+        jae 2f
+
+        shll $2, %eax
+        addl $syscall_table, %eax
+        cmpl $0, (%eax)
+        jne 1f
+    2:    
         neg   %eax
         popl  %ebp
         ret
         pushl 12(%ebp)    /* edx - #3 arg */
         pushl 8(%ebp)    /* ecx - #2 arg */
         pushl 4(%ebp)    /* ebx - #1 arg */
-        shll $2, %eax
-        addl $syscall_table, %eax
-
+        
         call (%eax)
 
         addl $24, %esp
 
         popl %ebp
+        
         ret
 
 
index bbd505d488b6c8123c25e98b983f1340ec79fd26..c119676bf5874017ac92f1e00bbe681dbf120be1 100644 (file)
@@ -39,6 +39,10 @@ extern uint8_t __init_hhk_end;
 // Set remotely by kernel/asm/x86/prologue.S
 multiboot_info_t* _k_init_mb_info;
 
+x86_page_table* __kernel_ptd;
+
+struct proc_info tmp;
+
 LOG_MODULE("BOOT");
 
 extern void _lxinit_main();
@@ -62,6 +66,14 @@ _kernel_pre_init() {
 
     tty_init((void*)VGA_BUFFER_PADDR);
     tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
+
+    __kernel_ptd = cpu_rcr3();
+
+    tmp = (struct proc_info) {
+        .page_table = __kernel_ptd
+    };
+
+    __current = &tmp;
 }
 
 void
@@ -81,8 +93,6 @@ _kernel_init() {
     kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n", KSTACK_SIZE>>PG_SIZE_BITS, KSTACK_START);
 
     sched_init();
-
-    spawn_lxinit();
 }
 
 /**
@@ -91,32 +101,43 @@ _kernel_init() {
  */
 void spawn_lxinit() {
     struct proc_info kinit;
-    uint32_t* kstack = (uint32_t*)KSTACK_TOP - 4 * 5;
 
     memset(&kinit, 0, sizeof(kinit));
-    kinit.page_table = (void*) cpu_rcr3();
     kinit.parent = -1;
     kinit.pid = 1;
     kinit.intr_ctx = (isr_param) {
-        .registers.esp = kstack,
+        .registers.esp = KSTACK_TOP - 20,
         .cs = KCODE_SEG,
-        .eip = (void*)_kernel_post_init,
+        .eip = (void*)_lxinit_main,
         .ss = KDATA_SEG,
         .eflags = cpu_reflags()
     };
-
-    /* 
-        因为schedule从设计上是需要在中断环境中执行的
-        可是我们需要在这里手动调用 schedule,从而使我们的init能够被执行。
-        所以需要模拟中断产生时的栈里内容。
-    */ 
-    kstack[2] = kinit.intr_ctx.eip;
-    kstack[3] = kinit.intr_ctx.cs;
-    kstack[4] = kinit.intr_ctx.eflags;
-
+    kinit.page_table = dup_pagetable(kinit.pid);
+
+    // Ok... 准备fork进我们的init进程
+    /*
+        这里是一些栈的设置,因为我们将切换到一个新的地址空间里,并且使用一个全新的栈。
+        让iret满意!
+    */
+    asm volatile(
+        "movl %%cr3, %%eax\n"
+        "movl %%esp, %%ebx\n"
+        "movl %0, %%cr3\n"
+        "movl %1, %%esp\n"
+        "pushf\n"
+        "pushl %2\n"
+        "pushl %3\n"
+        "pushl $0\n"
+        "pushl $0\n"
+        "movl %%eax, %%cr3\n"
+        "movl %%ebx, %%esp\n"
+        ::"r"(kinit.page_table), "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(kinit.intr_ctx.eip)
+        :"%eax", "%ebx", "memory"
+    );
+
+    // 向调度器注册进程,然后这里阻塞等待调度器调度就好了。
     push_process(&kinit);
-    
-    schedule();
+
 }
 
 void 
@@ -155,7 +176,7 @@ _kernel_post_init() {
         vmm_unmap_page(KERNEL_PID, (void*)(i << PG_SIZE_BITS));
     }
 
-    _lxinit_main();
+    spawn_lxinit();
 
     spin();
 }
index 7decff49900b513d3c7c85e38f3e4ca9252e4fbb..ec3425c1df6cd0fc0c141ff10238b223afb830a5 100644 (file)
@@ -35,10 +35,6 @@ _lxinit_main()
         kprintf(KINFO "Forked %d\n", pid);
     }
 
-    // FIXME: 这里fork会造成下面lxmalloc产生Heap corruption,需要实现COW和加入mutex
-    // fork();
-      
-
     char buf[64];
 
     kprintf(KINFO "Hello higher half kernel world!\nWe are now running in virtual "
@@ -50,35 +46,14 @@ _lxinit_main()
     void* k_start = vmm_v2p(&__kernel_start);
     kprintf(KINFO "The kernel's base address mapping: %p->%p\n", &__kernel_start, k_start);
 
-    // test malloc & free
-
-    uint8_t** arr = (uint8_t**)lxmalloc(10 * sizeof(uint8_t*));
-
-    for (size_t i = 0; i < 10; i++) {
-        arr[i] = (uint8_t*)lxmalloc((i + 1) * 2);
-    }
-
-    for (size_t i = 0; i < 10; i++) {
-        lxfree(arr[i]);
-    }
-
-    uint8_t* big_ = lxmalloc(8192);
-    big_[0] = 123;
-    big_[1] = 23;
-    big_[2] = 3;
-
-    kprintf(KINFO "%u, %u, %u\n", big_[0], big_[1], big_[2]);
-
-    // good free
-    lxfree(arr);
-    lxfree(big_);
-
-    // timer_run_second(1, test_timer, NULL, TIMER_MODE_PERIODIC);
+    // no lxmalloc here! This can only be used within kernel, but here, we are in a dedicated process!
+    // any access to kernel method must be done via syscall
 
     struct kdb_keyinfo_pkt keyevent;
     while (1)
     {
         if (!kbd_recv_key(&keyevent)) {
+            // yield();
             continue;
         }
         if ((keyevent.state & KBD_KEY_FPRESSED) && (keyevent.keycode & 0xff00) <= KEYPAD) {
index 30cead962456a51dc557804e9031ba769e540816..85dcd491694ac227cb37641e1fa75529180c561a 100644 (file)
@@ -1,16 +1,19 @@
 #include <lunaix/mm/vmm.h>
 
-void* vmm_dup_page(void* va) {    
-    void* new_ppg = pmm_alloc_page(KERNEL_PID, 0);
-    vmm_fmap_page(KERNEL_PID, PG_MOUNT_3, new_ppg, PG_PREM_RW);
+void* vmm_dup_page(pid_t pid, void* pa) {    
+    void* new_ppg = pmm_alloc_page(pid, 0);
+    vmm_fmap_page(pid, PG_MOUNT_3, new_ppg, PG_PREM_RW);
+    vmm_fmap_page(pid, PG_MOUNT_4, pa, PG_PREM_RW);
 
     asm volatile (
         "movl %1, %%edi\n"
+        "movl %2, %%esi\n"
         "rep movsl\n"
-        :: "c"(1024), "r"(PG_MOUNT_3), "S"((uintptr_t)va)
-        : "memory", "%edi");
+        :: "c"(1024), "r"(PG_MOUNT_3), "r"(PG_MOUNT_4)
+        : "memory", "%edi", "%esi");
 
     vmm_unset_mapping(PG_MOUNT_3);
+    vmm_unset_mapping(PG_MOUNT_4);
 
     return new_ppg;
 }
\ No newline at end of file
index 91905b4139cb2ee4933c07ddb7f4f5b37e1c93ef..4d9a5d1ee8fe463c3041a08c2d254b95ef2f3812 100644 (file)
@@ -57,27 +57,32 @@ lx_grow_heap(heap_context_t* heap, size_t sz);
     Note: the brk always point to the beginning of epilogue.
 */
 
+static heap_context_t kheap;
+
 int
 kalloc_init() {
-    heap_context_t* kheap = &__current->mm.k_heap;
-    kheap->start = &__kernel_heap_start;
-    kheap->brk = NULL;
-    kheap->max_addr = (void*)KSTACK_START;
+    kheap.start = &__kernel_heap_start;
+    kheap.brk = NULL;
+    kheap.max_addr = (void*)KSTACK_START;
 
-    if (!dmm_init(kheap)) {
+    if (!dmm_init(&kheap)) {
         return 0;
     }
 
-    SW(kheap->start, PACK(4, M_ALLOCATED));
-    SW(kheap->start + WSIZE, PACK(0, M_ALLOCATED));
-    kheap->brk += WSIZE;
+    SW(kheap.start, PACK(4, M_ALLOCATED));
+    SW(kheap.start + WSIZE, PACK(0, M_ALLOCATED));
+    kheap.brk += WSIZE;
 
-    return lx_grow_heap(kheap, HEAP_INIT_SIZE) != NULL;
+    return lx_grow_heap(&kheap, HEAP_INIT_SIZE) != NULL;
 }
 
 void*
 lxmalloc(size_t size) {
-    return lx_malloc_internal(&__current->mm.k_heap, size);
+    mutex_lock(&kheap.lock);
+    void* r = lx_malloc_internal(&kheap, size);
+    mutex_unlock(&kheap.lock);
+
+    return r;
 }
 
 void*
@@ -102,6 +107,7 @@ lxfree(void* ptr) {
     if (!ptr) {
         return;
     }
+    mutex_lock(&kheap.lock);
 
     uint8_t* chunk_ptr = (uint8_t*)ptr - WSIZE;
     uint32_t hdr = LW(chunk_ptr);
@@ -122,6 +128,8 @@ lxfree(void* ptr) {
     SW(next_hdr, LW(next_hdr) | M_PREV_FREE);
     
     coalesce(chunk_ptr);
+
+    mutex_unlock(&kheap.lock);
 }
 
 
index f791cc38969f340d49438fc748f32790ec7b2609..40c8be5885ffdf332667a82d9900a87a06de9473 100644 (file)
@@ -255,4 +255,17 @@ void*
 vmm_v2p(void* va)
 {
     return (void*)vmm_lookup(va).pa;
+}
+
+void*
+vmm_mount_pd(void* pde) {
+    x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
+    l1pt->entry[(PD_MOUNT >> 22)] = NEW_L1_ENTRY(PG_PREM_RW, pde);
+    return PD_MOUNT;
+}
+
+void*
+vmm_unmount_pd() {
+    x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
+    l1pt->entry[(PD_MOUNT >> 22)] = 0;
 }
\ No newline at end of file
index be7d423b3b6c36dc98654bb4df5e5570000e934c..de6eaf6625ef0136f21e7aa0f94af7b95cc8ef4e 100644 (file)
@@ -6,12 +6,10 @@
 
 LOG_MODULE("PROC")
 
-void dup_proc() {
-    pid_t pid = alloc_pid();
-
+void* __dup_pagetable(pid_t pid, uintptr_t mount_point) {
     void* ptd_pp = pmm_alloc_page(pid, PP_FGPERSIST);
     x86_page_table* ptd = vmm_fmap_page(pid, PG_MOUNT_1, ptd_pp, PG_PREM_RW);
-    x86_page_table* pptd = (x86_page_table*) L1_BASE_VADDR;
+    x86_page_table* pptd = (x86_page_table*) (mount_point | (0x3FF << 12));
 
     for (size_t i = 0; i < PG_MAX_ENTRIES - 1; i++)
     {
@@ -21,7 +19,7 @@ void dup_proc() {
             continue;
         }
         
-        x86_page_table* ppt = (x86_page_table*) L2_VADDR(i);
+        x86_page_table* ppt = (x86_page_table*) (mount_point | (i << 12));
         void* pt_pp = pmm_alloc_page(pid, PP_FGPERSIST);
         x86_page_table* pt = vmm_fmap_page(pid, PG_MOUNT_2, pt_pp, PG_PREM_RW);
 
@@ -36,7 +34,7 @@ void dup_proc() {
 
             // FIXME: 根据 mm_region 将读共享的页(如堆)标为只读,而私有的页(如栈),则复制;而写共享的页则无需更改flags
             if (va >= KSTACK_START) {
-                void* ppa = vmm_dup_page(va);
+                void* ppa = vmm_dup_page(pid, PG_ENTRY_ADDR(ppte));
                 ppte = ppte & 0xfff | (uintptr_t)ppa;
             }
             pt->entry[j] = ppte;
@@ -50,16 +48,39 @@ void dup_proc() {
     
     ptd->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, ptd_pp);
 
+    return ptd_pp;
+}
+
+void* dup_pagetable(pid_t pid) {
+    return __dup_pagetable(pid, L2_BASE_VADDR);
+}
+
+void dup_proc() {
+    pid_t pid = alloc_pid();
+
+    /* 
+        FIXME: Problematic! It should mount the page table of process then copy it.
+        The current implementation copy the CURRENTLY loaded pgt.
+        However, dup_pagetable is designed to copy current loaded pgt.
+        
+    */
+
+    void* mnt_pt = vmm_mount_pd(__current->page_table);
+
+    void* pg = __dup_pagetable(pid, mnt_pt);
+
+    vmm_unmount_pd();
+
     struct proc_info pcb = (struct proc_info) {
         .created = clock_systime(),
         .pid = pid,
         .mm = __current->mm,
-        .page_table = ptd_pp,
+        .page_table = pg,
         .intr_ctx = __current->intr_ctx,
         .parent_created = __current->created
     };
 
-    // 正如同fork一样,返回两次。
+    // 正如同fork,返回两次。
     pcb.intr_ctx.registers.eax = 0;
     __current->intr_ctx.registers.eax = pid;
 
index ed2cc74a2b02b813d9578d81af5eb36b88774d6c..f4fb021acccfdbf04cc6ab72d936f1202af3cbac 100644 (file)
@@ -32,8 +32,6 @@ void sched_init() {
         .ptable_len = 0,
         .procs_index = 0
     };
-
-    __current = &dummy;
 }
 
 void schedule() {
@@ -61,7 +59,9 @@ void schedule() {
 
     apic_done_servicing();
 
-    asm volatile ("pushl %0\n jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
+    asm volatile (
+        "pushl %0\n"
+        "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
 }
 
 pid_t alloc_pid() {
index 2589aeb09273d00991842be20ced49701736fcce..ce236c0c6ebbb01fc17c565a5e4d04b99579f833 100644 (file)
@@ -62,7 +62,7 @@ SECTIONS {
 
     __kernel_end = ALIGN(4K);
     __pg_mount_point = ALIGN(4K);
-    . += 12K;
+    . += 16K;
     __proc_table = ALIGN(4K);
     . += 128M;
     __kernel_heap_start = ALIGN(4K);    /* 内核结束的地方即堆开始的地方 */