chore: make things more general
authorMinep <zelong56@gmail.com>
Sat, 18 Jun 2022 16:27:38 +0000 (17:27 +0100)
committerMinep <zelong56@gmail.com>
Sat, 18 Jun 2022 16:27:38 +0000 (17:27 +0100)
refactor: put a limit on kernel heap.
refactor: reduce overhead on kernel stack creation when we fork into our first process.

lunaix-os/includes/lunaix/mm/mm.h
lunaix-os/includes/lunaix/mm/page.h
lunaix-os/includes/lunaix/mm/region.h
lunaix-os/includes/lunaix/mm/vmm.h
lunaix-os/includes/lunaix/process.h
lunaix-os/kernel/asm/x86/pfault.c
lunaix-os/kernel/k_init.c
lunaix-os/kernel/mm/kalloc.c
lunaix-os/kernel/mm/region.c
lunaix-os/kernel/mm/vmm.c
lunaix-os/kernel/process.c

index 04f2f026ae1351a147519b46cb829ecffb20540b..060b88181aa733d7d2592155a5fffe3509119e1a 100644 (file)
@@ -4,7 +4,7 @@
 #include <lunaix/ds/llist.h>
 #include <lunaix/ds/mutex.h>
 
-typedef struct 
+typedef struct
 {
     void* start;
     void* brk;
@@ -14,28 +14,35 @@ typedef struct
 
 /**
  * @brief 私有区域,该区域中的页无法进行任何形式的共享。
- * 
+ *
  */
-#define REGION_PRIVATE      0x0
+#define REGION_PRIVATE 0x0
 
 /**
- * @brief 读共享区域,该区域中的页可以被两个进程之间读共享,但任何写操作须应用Copy-On-Write
- * 
+ * @brief
+ * 读共享区域,该区域中的页可以被两个进程之间读共享,但任何写操作须应用Copy-On-Write
+ *
  */
-#define REGION_RSHARED      0x1
+#define REGION_RSHARED 0x1
 
 /**
- * @brief 写共享区域,该区域中的页可以被两个进程之间读共享,任何的写操作无需执行Copy-On-Write
- * 
+ * @brief
+ * 写共享区域,该区域中的页可以被两个进程之间读共享,任何的写操作无需执行Copy-On-Write
+ *
  */
-#define REGION_WSHARED      0x2
+#define REGION_WSHARED 0x2
 
-#define REGION_PERM_MASK  0x1c
+#define REGION_PERM_MASK 0x1c
 
-#define REGION_READ       (1 << 2)
-#define REGION_WRITE      (1 << 3)
-#define REGION_EXEC       (1 << 4)
-#define REGION_RW         REGION_READ | REGION_WRITE
+#define REGION_READ (1 << 2)
+#define REGION_WRITE (1 << 3)
+#define REGION_EXEC (1 << 4)
+#define REGION_RW REGION_READ | REGION_WRITE
+
+#define REGION_TYPE_CODE (1 << 16);
+#define REGION_TYPE_GENERAL (2 << 16);
+#define REGION_TYPE_HEAP (3 << 16);
+#define REGION_TYPE_STACK (4 << 16);
 
 struct mm_region
 {
index 76ea882bddcd9aa546a900dbb239abcd282e922d..446e14e8e3c148a61c1520f22deb7e6b5a9cb271 100644 (file)
@@ -98,7 +98,7 @@ typedef struct
 extern void __pg_mount_point;
 
 /* 四个页挂载点,两个页目录挂载点: 用于临时创建&编辑页表 */
-
+#define PG_MOUNT_RANGE(l1_index) (701 <= l1_index && l1_index <= 703)
 #define PD_MOUNT_1 0xAFC00000
 #define PD_MOUNT_2 0xAF800000
 #define PG_MOUNT_BASE 0xAF7FF000
index 8da41d2c1019d84e6a9c907af4c37a3dfd6f436f..8271d2b68a16545084011edf1c714a93796fb268 100644 (file)
@@ -2,13 +2,20 @@
 #define __LUNAIX_REGION_H
 
 #include <lunaix/mm/mm.h>
-#include <lunaix/process.h>
 
-void region_add(struct proc_info* proc, unsigned long start, unsigned long end, unsigned int attr);
+void
+region_add(struct mm_region** proc,
+           unsigned long start,
+           unsigned long end,
+           unsigned int attr);
 
-void region_release_all(struct proc_info* proc);
+void
+region_release_all(struct mm_region** proc);
 
-struct mm_region* region_get(struct proc_info* proc, unsigned long vaddr);
+struct mm_region*
+region_get(struct mm_region** proc, unsigned long vaddr);
 
+void
+region_copy(struct mm_region** src, struct mm_region** dest);
 
 #endif /* __LUNAIX_REGION_H */
index 5d88f3c75b7f5e45a826de5db480beaa7ab46ad6..bd074c54d41b2466e1455fa7c0e8aee365d6384a 100644 (file)
@@ -7,7 +7,16 @@
 // Virtual memory manager
 
 #define VMAP_NULL 0
+/**
+ * @brief 映射模式:忽略已存在映射
+ *
+ */
 #define VMAP_IGNORE 1
+/**
+ * @brief 映射模式:不作实际映射。该功能用于预留出特定的地址空间
+ *
+ */
+#define VMAP_NOMAP 2
 
 /**
  * @brief 初始化虚拟内存管理器
@@ -69,6 +78,9 @@ vmm_lookup(uintptr_t va, v_mapping* mapping);
 void*
 vmm_dup_page(pid_t pid, void* pa);
 
+void*
+vmm_dup_vmspace(pid_t pid);
+
 /**
  * @brief 挂载另一个虚拟地址空间至当前虚拟地址空间
  *
index 0b743d39c3058fff0d1d61b702ff149ae3a67d78..26f33bd84dd9fbb21f753b5735a45a84458c2c5c 100644 (file)
@@ -38,11 +38,22 @@ struct proc_sig
 
 struct proc_info
 {
+    /*
+        Any change to *critical section*, including layout, size
+        must be reflected in kernel/asm/x86/interrupt.S to avoid
+        disaster!
+     */
+
+    /* ---- critical section start ---- */
+
     pid_t pid;
     struct proc_info* parent;
     isr_param intr_ctx; // size=76
     uintptr_t ustack_top;
     void* page_table;
+
+    /* ---- critical section end ---- */
+
     struct llist_header siblings;
     struct llist_header children;
     struct llist_header grp_member;
index 15f11eeb5bdf82615a83bd94d79cf12bb96e934a..3ad640e9a0e84588bcb03e9324df3d7608b7ae8e 100644 (file)
@@ -43,7 +43,7 @@ intr_routine_page_fault(const isr_param* param)
         goto segv_term;
     }
 
-    struct mm_region* hit_region = region_get(__current, ptr);
+    struct mm_region* hit_region = region_get(&__current->mm.regions, ptr);
 
     if (!hit_region) {
         // Into the void...
index 7600caf21e07d348c8e9556a1f23ba12e48aca62..427ca512126843423375fe2e264ef7c79d39e09f 100644 (file)
@@ -80,15 +80,6 @@ _kernel_init()
 
     setup_memory((multiboot_memory_map_t*)_k_init_mb_info->mmap_addr, map_size);
 
-    // 为内核创建一个专属栈空间。
-    for (size_t i = 0; i < (KSTACK_SIZE >> PG_SIZE_BITS); i++) {
-        uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
-        vmm_set_mapping(PD_REFERENCED,
-                        KSTACK_START + (i << PG_SIZE_BITS),
-                        pa,
-                        PG_PREM_RW,
-                        VMAP_NULL);
-    }
     kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n",
             KSTACK_SIZE >> PG_SIZE_BITS,
             KSTACK_START);
@@ -135,31 +126,37 @@ spawn_proc0()
     // 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的!
     // cpu_disable_interrupt();
 
-    setup_proc_mem(&proc0, PD_REFERENCED);
-
-    // Ok... 首先fork进我们的零号进程,而后由那里,我们fork进init进程。
-    /*
-        这里是一些栈的设置,因为我们将切换到一个新的地址空间里,并且使用一个全新的栈。
-        让iret满意!
-    */
-    asm volatile("movl %%cr3, %%eax\n"
-                 "movl %%esp, %%ebx\n"
-                 "movl %1, %%cr3\n"
-                 "movl %2, %%esp\n"
+    /* Ok... 首先fork进我们的零号进程,而后由那里,我们fork进init进程。 */
+
+    // 把当前虚拟地址空间(内核)复制一份。
+    proc0.page_table = vmm_dup_vmspace(proc0.pid);
+
+    // 直接切换到新的拷贝,进行配置。
+    cpu_lcr3(proc0.page_table);
+
+    // 为内核创建一个专属栈空间。
+    for (size_t i = 0; i < (KSTACK_SIZE >> PG_SIZE_BITS); i++) {
+        uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
+        vmm_set_mapping(PD_REFERENCED,
+                        KSTACK_START + (i << PG_SIZE_BITS),
+                        pa,
+                        PG_PREM_RW,
+                        VMAP_NULL);
+    }
+
+    // 手动设置进程上下文:用于第一次调度
+    asm volatile("movl %%esp, %%ebx\n"
+                 "movl %1, %%esp\n"
                  "pushf\n"
+                 "pushl %2\n"
                  "pushl %3\n"
-                 "pushl %4\n"
                  "pushl $0\n"
                  "pushl $0\n"
                  "movl %%esp, %0\n"
-                 "movl %%eax, %%cr3\n"
                  "movl %%ebx, %%esp\n"
                  : "=m"(proc0.intr_ctx.registers.esp)
-                 : "r"(proc0.page_table),
-                   "i"(KSTACK_TOP),
-                   "i"(KCODE_SEG),
-                   "r"(proc0.intr_ctx.eip)
-                 : "%eax", "%ebx", "memory");
+                 : "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(proc0.intr_ctx.eip)
+                 : "%ebx", "memory");
 
     // 向调度器注册进程。
     push_process(&proc0);
index 3aba61ec62d5f33a0df6ae1f2cfb1de3a704d325..d5116a2c15b331a1bbb282896a601a9855134176 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <lunaix/mm/dmm.h>
 #include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/vmm.h>
 
 #include <lunaix/common.h>
 #include <lunaix/spike.h>
@@ -61,12 +62,22 @@ lx_grow_heap(heap_context_t* heap, size_t sz);
 // FIXME: This should be per-process but not global!
 static heap_context_t kheap;
 
+#define KHEAP_SIZE_MB 256
+
 int
 kalloc_init()
 {
     kheap.start = &__kernel_heap_start;
     kheap.brk = NULL;
-    kheap.max_addr = (void*)KSTACK_START;
+    kheap.max_addr = (void*)((uintptr_t)kheap.start + (KHEAP_SIZE_MB << 20));
+
+    for (size_t i = 0; i < KHEAP_SIZE_MB >> 2; i++) {
+        vmm_set_mapping(PD_REFERENCED,
+                        (uintptr_t)kheap.start + (i << 22),
+                        0,
+                        PG_PREM_RW,
+                        VMAP_NOMAP);
+    }
 
     if (!dmm_init(&kheap)) {
         return 0;
index 19355832762035b8e94a34c87d487ac5510e1528..d9fddeb0688da964512df788207637f959e6e0dd 100644 (file)
@@ -1,46 +1,64 @@
-#include <lunaix/mm/region.h>
 #include <lunaix/mm/kalloc.h>
-#include <lunaix/process.h>
+#include <lunaix/mm/region.h>
 
-void region_add(struct proc_info* proc,unsigned long start, unsigned long end, unsigned int attr) {
+void
+region_add(struct mm_region** regions,
+           unsigned long start,
+           unsigned long end,
+           unsigned int attr)
+{
     struct mm_region* region = lxmalloc(sizeof(struct mm_region));
 
-    *region = (struct mm_region) {
-        .attr = attr,
-        .end = end,
-        .start = start
-    };
+    *region = (struct mm_region){ .attr = attr, .end = end, .start = start };
 
-    if (!proc->mm.regions) {
+    if (!*regions) {
         llist_init_head(&region->head);
-        proc->mm.regions = region;
-    }
-    else {
-        llist_append(&proc->mm.regions->head, &region->head);
+        *regions = region;
+    } else {
+        llist_append(&(*regions)->head, &region->head);
     }
 }
 
-void region_release_all(struct proc_info* proc) {
-    struct mm_region* head = proc->mm.regions;
+void
+region_release_all(struct mm_region** regions)
+{
     struct mm_region *pos, *n;
 
-    llist_for_each(pos, n, &head->head, head) {
+    llist_for_each(pos, n, &(*regions)->head, head)
+    {
         lxfree(pos);
     }
 
-    proc->mm.regions = NULL;
+    *regions = NULL;
+}
+
+void
+region_copy(struct mm_region** src, struct mm_region** dest)
+{
+    if (!*src) {
+        return;
+    }
+
+    struct mm_region *pos, *n;
+
+    llist_init_head(*dest);
+    llist_for_each(pos, n, &(*src)->head, head)
+    {
+        region_add(dest, pos->start, pos->end, pos->attr);
+    }
 }
 
-struct mm_region* region_get(struct proc_info* proc, unsigned long vaddr) {
-    struct mm_region* head = proc->mm.regions;
-    
-    if (!head) {
+struct mm_region*
+region_get(struct mm_region** regions, unsigned long vaddr)
+{
+    if (!*regions) {
         return NULL;
     }
 
     struct mm_region *pos, *n;
 
-    llist_for_each(pos, n, &head->head, head) {
+    llist_for_each(pos, n, &(*regions)->head, head)
+    {
         if (vaddr >= pos->start && vaddr < pos->end) {
             return pos;
         }
index 1453c89e65b10d505f9f380e19c284538aee5180..40e3724d5266a157d878dc5c3e74c08df08e451a 100644 (file)
@@ -64,6 +64,10 @@ vmm_set_mapping(uintptr_t mnt,
         cpu_invplg(va);
     }
 
+    if ((options & VMAP_NOMAP)) {
+        return 1;
+    }
+
     l2pt->entry[l2_inx] = NEW_L2_ENTRY(attr, pa);
     return 1;
 }
index c4e348f19b9dc96844f5cd71d33bd92136dbb2c0..ce491edef18590be181f76096d8e330c47727ae1 100644 (file)
@@ -22,6 +22,12 @@ __dup_pagetable(pid_t pid, uintptr_t mount_point)
     x86_page_table* pptd = (x86_page_table*)(mount_point | (0x3FF << 12));
 
     for (size_t i = 0; i < PG_MAX_ENTRIES - 1; i++) {
+        // 没有必要拷贝临时挂载点
+        if (PG_MOUNT_RANGE(i)) {
+            ptd->entry[i] = 0;
+            continue;
+        }
+
         x86_pte_t ptde = pptd->entry[i];
         if (!ptde || !(ptde & PG_PRESENT)) {
             ptd->entry[i] = ptde;
@@ -77,7 +83,7 @@ __del_pagetable(pid_t pid, uintptr_t mount_point)
 }
 
 void*
-dup_pagetable(pid_t pid)
+vmm_dup_vmspace(pid_t pid)
 {
     return __dup_pagetable(pid, PD_REFERENCED);
 }
@@ -138,6 +144,26 @@ init_proc(struct proc_info* pcb)
     pcb->pgid = pcb->pid;
 }
 
+void
+__mark_region(uintptr_t start_vpn, uintptr_t end_vpn, int attr)
+{
+    for (size_t i = start_vpn; i < end_vpn; i++) {
+        x86_pte_t* curproc = &PTE_MOUNTED(PD_REFERENCED, i);
+        x86_pte_t* newproc = &PTE_MOUNTED(PD_MOUNT_2, i);
+        cpu_invplg(newproc);
+
+        if (attr == REGION_RSHARED) {
+            // 如果读共享,则将两者的都标注为只读,那么任何写入都将会应用COW策略。
+            cpu_invplg(curproc);
+            *curproc = *curproc & ~PG_WRITE;
+            *newproc = *newproc & ~PG_WRITE;
+        } else {
+            // 如果是私有页,则将该页从新进程中移除。
+            *newproc = 0;
+        }
+    }
+}
+
 pid_t
 dup_proc()
 {
@@ -147,6 +173,8 @@ dup_proc()
     pcb.intr_ctx = __current->intr_ctx;
     pcb.parent = __current;
 
+    region_copy(&__current->mm.regions, &pcb.mm.regions);
+
 #ifdef USE_KERNEL_PG
     setup_proc_mem(&pcb, PD_MOUNT_1); //挂载点#1是当前进程的页表
 #else
@@ -158,12 +186,9 @@ dup_proc()
         goto not_copy;
     }
 
-    llist_init_head(&pcb.mm.regions);
     struct mm_region *pos, *n;
-    llist_for_each(pos, n, &__current->mm.regions->head, head)
+    llist_for_each(pos, n, &pcb.mm.regions->head, head)
     {
-        region_add(&pcb, pos->start, pos->end, pos->attr);
-
         // 如果写共享,则不作处理。
         if ((pos->attr & REGION_WSHARED)) {
             continue;
@@ -171,21 +196,7 @@ dup_proc()
 
         uintptr_t start_vpn = PG_ALIGN(pos->start) >> 12;
         uintptr_t end_vpn = PG_ALIGN(pos->end) >> 12;
-        for (size_t i = start_vpn; i < end_vpn; i++) {
-            x86_pte_t* curproc = &PTE_MOUNTED(PD_MOUNT_1, i);
-            x86_pte_t* newproc = &PTE_MOUNTED(PD_MOUNT_2, i);
-            cpu_invplg(newproc);
-
-            if (pos->attr == REGION_RSHARED) {
-                // 如果读共享,则将两者的都标注为只读,那么任何写入都将会应用COW策略。
-                cpu_invplg(curproc);
-                *curproc = *curproc & ~PG_WRITE;
-                *newproc = *newproc & ~PG_WRITE;
-            } else {
-                // 如果是私有页,则将该页从新进程中移除。
-                *newproc = 0;
-            }
-        }
+        __mark_region(start_vpn, end_vpn, pos->attr);
     }
 
 not_copy:
@@ -235,9 +246,9 @@ setup_proc_mem(struct proc_info* proc, uintptr_t usedMnt)
     // 定义用户栈区域,但是不分配实际的物理页。我们会在Page fault
     // handler里面实现动态分配物理页的逻辑。(虚拟内存的好处!)
     // FIXME: 这里应该放到spawn_proc里面。
-    // region_add(proc, USTACK_END, USTACK_SIZE, REGION_PRIVATE | REGION_RW);
+    // region_add(proc, USTACK_END, USTACK_SIZE, REGION_PRIVATE |
+    // REGION_RW);
 
     // 至于其他的区域我们暂时没有办法知道,因为那需要知道用户程序的信息。我们留到之后在处理。
-
     proc->page_table = pt_copy;
 }
\ No newline at end of file