feat: added ability to identify process vm regions
authorMinep <zelong56@gmail.com>
Tue, 31 May 2022 20:43:35 +0000 (21:43 +0100)
committerMinep <zelong56@gmail.com>
Tue, 31 May 2022 20:43:35 +0000 (21:43 +0100)
feat: page fault handler for COW policy
refactor: improved system call declaration experience.
feat: more system call (sleep, _exit and other process related)
feat: add ability to detect orphan process.

25 files changed:
lunaix-os/includes/lunaix/common.h
lunaix-os/includes/lunaix/lunistd.h
lunaix-os/includes/lunaix/mm/mm.h
lunaix-os/includes/lunaix/mm/page.h
lunaix-os/includes/lunaix/mm/region.h [new file with mode: 0644]
lunaix-os/includes/lunaix/mm/vmm.h
lunaix-os/includes/lunaix/proc.h
lunaix-os/includes/lunaix/process.h
lunaix-os/includes/lunaix/sched.h
lunaix-os/includes/lunaix/status.h
lunaix-os/includes/lunaix/syscall.h
lunaix-os/includes/lunaix/timer.h
lunaix-os/kernel/asm/x86/interrupts.c
lunaix-os/kernel/asm/x86/pfault.c
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/k_init.c
lunaix-os/kernel/lxinit.c
lunaix-os/kernel/mm/dmm.c
lunaix-os/kernel/mm/pmm.c
lunaix-os/kernel/mm/region.c [new file with mode: 0644]
lunaix-os/kernel/mm/vmm.c
lunaix-os/kernel/process.c
lunaix-os/kernel/sched.c
lunaix-os/kernel/time/timer.c
lunaix-os/link/linker.ld

index 27243bfba322957684e1ba6bd1806d9d159ce3dc..64820083092128555119e2ee2f8850d5a8a8702c 100644 (file)
 #define UDATA_SEG              0x23
 #define TSS_SEG                0x28
 
+#define USER_START             0x400000
+#define USTACK_SIZE            0x100000
+#define USTACK_TOP             0x9fffffff
+#define USTACK_END             (USTACK_TOP - USTACK_SIZE + 1)
+#define UMMAP_AREA             0x4D000000
+
 #define SYS_TIMER_FREQUENCY_HZ  2048
 
 #ifndef __ASM__
index 20e394fac576a930b7724adb3f51f7d968ac18c4..12faab5fdf0721dcea693669f4ef76aa3c1f452e 100644 (file)
@@ -10,4 +10,12 @@ __LXSYSCALL1(int, sbrk, void*, addr)
 
 __LXSYSCALL1(void*, brk, size_t, size)
 
+__LXSYSCALL(pid_t, getpid)
+
+__LXSYSCALL(pid_t, getppid)
+
+__LXSYSCALL1(void, _exit, int, status)
+
+__LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
+
 #endif /* __LUNAIX_UNISTD_H */
index 2ea1ac27b41c74c7d1d5e22f3d7ee675e8304089..8318eaa17167ceb219eb43527e0f542c860ae644 100644 (file)
@@ -30,14 +30,17 @@ typedef struct
  */
 #define REGION_WSHARED      0x2
 
-#define REGION_TYPE_CODE    (0)
-#define REGION_TYPE_DATA    (1 << 2)
+#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
 
 struct mm_region
 {
-    struct llist_header* head;
-    void* start;
-    void* end;
+    struct llist_header head;
+    unsigned long start;
+    unsigned long end;
     unsigned int attr;
 };
 
index 4b6a1a15e3b1540261c984a1b0e4fd1395cdb9cb..5755a46e2e8c473557d801b59267a2faf734582b 100644 (file)
@@ -95,13 +95,17 @@ typedef struct
 
 extern void __pg_mount_point;
 
-/* 三个页挂载点,一个页目录挂载点: 用于临时创建&编辑页表 */
-
-#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)
-
+/* 四个页挂载点,两个页目录挂载点: 用于临时创建&编辑页表 */
+
+#define PD_MOUNT_1          0xAFC00000
+#define PD_MOUNT_2          0xAF800000
+#define PG_MOUNT_BASE       0xAF7FF000
+#define PG_MOUNT_1          (PG_MOUNT_BASE)
+#define PG_MOUNT_2          (PG_MOUNT_BASE - 0x1000)
+#define PG_MOUNT_3          (PG_MOUNT_BASE - 0x2000)
+#define PG_MOUNT_4          (PG_MOUNT_BASE - 0x3000)
+#define PD_REFERENCED       L2_BASE_VADDR
+
+#define CURPROC_PTE(vpn)     (&((x86_page_table*)(PD_MOUNT_1 | (((vpn) & 0xffc00) << 2)))->entry[(vpn) & 0x3ff])
 
 #endif /* __LUNAIX_PAGE_H */
diff --git a/lunaix-os/includes/lunaix/mm/region.h b/lunaix-os/includes/lunaix/mm/region.h
new file mode 100644 (file)
index 0000000..8da41d2
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LUNAIX_REGION_H
+#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_release_all(struct proc_info* proc);
+
+struct mm_region* region_get(struct proc_info* proc, unsigned long vaddr);
+
+
+#endif /* __LUNAIX_REGION_H */
index 2e9f72f67eb903be228ef7f05dd360980fa66b68..99190c7eadbb9affe3310ffc889b733cfe2faedc 100644 (file)
@@ -128,13 +128,13 @@ void* vmm_dup_page(pid_t pid, void* pa);
  * @return void* 
  */
 void*
-vmm_mount_pd(void* pde);
+vmm_mount_pd(uintptr_t mnt, void* pde);
 
 /**
  * @brief 卸载已挂载的虚拟地址空间
  * 
  */
 void*
-vmm_unmount_pd();
+vmm_unmount_pd(uintptr_t mnt);
 
 #endif /* __LUNAIX_VMM_H */
index f22fd684b42f009dfff03827644b5a8ea823f206..cec56704f6b6e531dcf435d455e671b2944d58d1 100644 (file)
@@ -3,8 +3,6 @@
 
 #include <lunaix/syscall.h>
 
-__LXSYSCALL1(void, exit, int, status)
-
 __LXSYSCALL(void, yield)
 
 #endif /* __LUNAIX_SYS_H */
index efa11666674b9602bdc07100d8bd6bc35fe2896b..d9a5bb189058ed2aa1fa38b39688dbe993aa851e 100644 (file)
@@ -6,33 +6,35 @@
 #include <lunaix/mm/mm.h>
 #include <lunaix/types.h>
 #include <lunaix/clock.h>
+#include <lunaix/timer.h>
 
 // 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。
 #define KERNEL_PID -1
 
-#define PROC_CREATED 0
+#define PROC_STOPPED 0
 #define PROC_RUNNING 1
-#define PROC_STOPPED 2
-#define PROC_TERMNAT 3
+#define PROC_TERMNAT 2
 #define PROC_DESTROY 4
+#define PROC_SPOILED 8
+#define PROC_BLOCKED 16
 
 
 struct proc_mm {
     heap_context_t u_heap;
-    struct mm_region* region;
+    struct mm_region* regions;
 };
 
 struct proc_info {
     pid_t pid;
-    pid_t parent;
+    struct proc_info* parent;
     isr_param intr_ctx;
     struct proc_mm mm;
     void* page_table;
     time_t created;
-    time_t parent_created;
     uint8_t state;
     int32_t exit_code;
     int32_t k_status;
+    struct lx_timer* timer;
 };
 
 extern struct proc_info* __current;
@@ -49,7 +51,7 @@ void push_process(struct proc_info* process);
 
 void destroy_process(pid_t pid);
 
-void* dup_pagetable(pid_t pid);
+void setup_proc_mem(struct proc_info* proc, uintptr_t kstack_from);
 
 /**
  * @brief 复制当前进程(LunaixOS的类 fork (unix) 实现)
@@ -67,7 +69,9 @@ void new_proc();
  * @brief 终止(退出)当前进程
  * 
  */
-void terminate_process(int exit_code);
+void terminate_proc(int exit_code);
+
+int orphaned_proc(pid_t pid);
 
 struct proc_info* get_process(pid_t pid);
 
index a0778a39faf7d53f848ff05eb8caf61b21bd23f5..618c32484e849245fe3378f7e73c077452e9355b 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __LUNAIX_SCHEDULER_H
 #define __LUNAIX_SCHEDULER_H
 
-#define SCHED_TIME_SLICE 1000
+#define SCHED_TIME_SLICE 200
 
 struct scheduler {
     struct proc_info* _procs;
index 44fa2f9858dca4bec0fe47ec09d268e2bd02de88..db33da2d9a9697504e3fd51fbadb362c89017f5e 100644 (file)
@@ -6,5 +6,6 @@
 #define LXINVLDPTR -(2)
 #define LXOUTOFMEM -(3)
 #define LXINVLDPID -(4)
+#define LXSEGFAULT -(5)
 
 #endif /* __LUNAIX_CODE_H */
index d93358425a51861ffad05d868ce0b19c13bd93f9..ee63c40250351e14ecd47797aee9969fb90afe05 100644 (file)
@@ -3,11 +3,14 @@
 
 #include <arch/x86/vectors.h>
 
-#define __SYSCALL_fork    0x1
-#define __SYSCALL_yield   0x2
-#define __SYSCALL_exit    0x3
-#define __SYSCALL_sbrk    0x4
-#define __SYSCALL_brk     0x5
+#define __SYSCALL_fork    1
+#define __SYSCALL_yield   2
+#define __SYSCALL_sbrk    3
+#define __SYSCALL_brk     4
+#define __SYSCALL_getpid     5
+#define __SYSCALL_getppid    6
+#define __SYSCALL_sleep    7
+#define __SYSCALL__exit    8
 
 #define __SYSCALL_MAX     0x100
 
@@ -22,6 +25,15 @@ static void* syscall(unsigned int callcode) {
     );
 }
 
+#define asmlinkage __attribute__((regparm(0)))
+
+#define __PARAM_MAP1(t1, p1) t1 p1
+#define __PARAM_MAP2(t1, p1, ...) t1 p1, __PARAM_MAP1(__VA_ARGS__)
+#define __PARAM_MAP3(t1, p1, ...) t1 p1, __PARAM_MAP2(__VA_ARGS__)
+#define __PARAM_MAP4(t1, p1, ...) t1 p1, __PARAM_MAP3(__VA_ARGS__)
+#define __PARAM_MAP5(t1, p1, ...) t1 p1, __PARAM_MAP4(__VA_ARGS__)
+#define __PARAM_MAP6(t1, p1, ...) t1 p1, __PARAM_MAP5(__VA_ARGS__)
+
 #define ___DOINT33(callcode, rettype)\
     int v;    \
     asm volatile (  \
@@ -30,31 +42,47 @@ static void* syscall(unsigned int callcode) {
         :"i"(LUNAIX_SYS_CALL), "a"(callcode));  \
     return (rettype)v;     \
 
+#define __DEFINE_LXSYSCALL(rettype, name) \
+    asmlinkage rettype __lxsys_##name()
+
+#define __DEFINE_LXSYSCALL1(rettype, name, t1, p1) \
+    asmlinkage rettype __lxsys_##name(__PARAM_MAP1(t1, p1))
+
+#define __DEFINE_LXSYSCALL2(rettype, name, t1, p1, t2, p2) \
+    asmlinkage rettype __lxsys_##name(__PARAM_MAP2(t1, p1, t2, p2))
+
+#define __DEFINE_LXSYSCALL3(rettype, name, t1, p1, t2, p2, t3, p3) \
+    asmlinkage rettype __lxsys_##name(__PARAM_MAP3(t1, p1, t2, p2, t3, p3));
+
+#define __DEFINE_LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4) \
+    asmlinkage rettype __lxsys_##nam (__PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4))
+
+
 #define __LXSYSCALL(rettype, name) \
     rettype name () { \
         ___DOINT33(__SYSCALL_##name, rettype) \
     }
 
 #define __LXSYSCALL1(rettype, name, t1, p1) \
-    rettype name (t1 p1) { \
+    rettype name (__PARAM_MAP1(t1, p1)) { \
         asm (""::"b"(p1)); \
         ___DOINT33(__SYSCALL_##name, rettype) \
     }
 
 #define __LXSYSCALL2(rettype, name, t1, p1, t2, p2) \
-    rettype name (t1 p1, t2 p2) { \
+    rettype name (__PARAM_MAP2(t1, p1, t2, p2)) { \
         asm ("\n"::"b"(p1), "c"(p2)); \
         ___DOINT33(__SYSCALL_##name, rettype) \
     }
 
 #define __LXSYSCALL3(rettype, name, t1, p1, t2, p2, t3, p3) \
-    rettype name (t1 p1, t2 p2, t3 p3) { \
+    rettype name (__PARAM_MAP3(t1, p1, t2, p2, t3, p3)) { \
         asm ("\n"::"b"(p1), "c"(p2), "d"(p3)); \
         ___DOINT33(__SYSCALL_##name, rettype) \
     }
 
 #define __LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4) \
-    rettype name (t1 p1, t2 p2, t3 p3, t4 p4) { \
+    rettype name (__PARAM_MAP3(t1, p1, t2, p2, t3, p3, t4, p4)) { \
         asm ("\n"::"b"(p1), "c"(p2), "d"(p3), "D"(p4)); \
         ___DOINT33(__SYSCALL_##name, rettype) \
     }
index 78976a579759501390b5a1d5bf52fa05e6c5d115..567b8d24d70e72462ad1ee941c20c1c26e2ed25e 100644 (file)
@@ -47,11 +47,13 @@ struct lx_timer {
 void
 timer_init(uint32_t frequency);
 
-int
+struct lx_timer*
 timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags);
+
+struct lx_timer*
 timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags);
 
-int
+struct lx_timer*
 timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags);
 
 struct lx_timer_context* 
index 8330bc263f1bb37b88bf56ff05b25ef7ecbad6d9..09bd1eb1409cfdcf18a78a64784739112f30107e 100644 (file)
@@ -6,6 +6,7 @@
 #include <lunaix/process.h>
 #include <lunaix/sched.h>
 #include <lunaix/mm/page.h>
+#include <lunaix/mm/vmm.h>
 
 LOG_MODULE("intr")
 
@@ -42,6 +43,9 @@ intr_handler(isr_param* param)
 
     cpu_lcr3(__kernel_ptd);
 
+    // 将当前进程的页目录挂载到内核地址空间里(页目录挂载点#1),方便访问。
+    vmm_mount_pd(PD_MOUNT_1, __current->page_table);
+
     isr_param *lparam = &__current->intr_ctx;
     
     if (lparam->vector <= 255) {
index 63a40a36e89b3fb4345a7530cf20b057b9068702..f07c74faa54cc4f5afdaa4acd44a88f97195b4de 100644 (file)
@@ -1,8 +1,12 @@
 #include <arch/x86/interrupts.h>
 #include <lunaix/mm/pmm.h>
+#include <lunaix/mm/mm.h>
+#include <lunaix/mm/region.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/common.h>
 #include <lunaix/syslog.h>
+#include <lunaix/status.h>
+#include <lunaix/sched.h>
 
 static void kprintf(const char* fmt, ...) { va_list args; va_start(args, fmt); __kprintf("PFAULT", fmt, args); va_end(args); }
 
@@ -11,15 +15,48 @@ extern void __print_panic_msg(const char* msg, const isr_param* param);
 void
 intr_routine_page_fault (const isr_param* param) 
 {
-    void* pg_fault_ptr = cpu_rcr2();
-    if (!pg_fault_ptr) {
-        __print_panic_msg("Null pointer reference", param);
-        goto done;
+    uintptr_t ptr = cpu_rcr2();
+    if (!ptr) {
+        goto segv_term;
     }
 
-    kprintf("%p", pg_fault_ptr);
-    __print_panic_msg("Page fault", param);
+    struct mm_region* hit_region = region_get(__current, ptr);
 
-done:
-    while(1);
+    if (!hit_region) {
+        // Into the void...
+        goto segv_term;
+    }
+
+    if (param->eip == ptr && !(hit_region->attr & REGION_EXEC)) {
+        // Attempt to execute non-executable page
+        goto segv_term;
+    }
+
+    x86_pte_t* pte = CURPROC_PTE(ptr >> 12);
+    if (*pte & PG_PRESENT) {
+        if ((hit_region->attr & REGION_PERM_MASK) == (REGION_RSHARED | REGION_READ)) {
+            // normal page fault, do COW
+                uintptr_t pa = (uintptr_t)vmm_dup_page(__current->pid, PG_ENTRY_ADDR(*pte));
+                pmm_free_page(__current->pid, *pte & ~0xFFF);
+                *pte = (*pte & 0xFFF) | pa | PG_WRITE;
+                return;
+        }
+        else {
+            // impossible cases or accessing privileged page
+            goto segv_term;
+        }
+    } else {
+        if (!(*pte)) {
+            // Invalid location
+            goto segv_term;
+        }
+        // page not present, bring it from disk or somewhere else
+        __print_panic_msg("WIP page fault route", param);
+        while (1);
+    }
+
+segv_term:
+    kprintf(KERROR "(pid: %d) Segmentation fault on %p\n", __current->pid, ptr);
+    terminate_proc(LXSEGFAULT);
+    // should not reach
 }
\ No newline at end of file
index 25e153f592e906528f54d6673dc8d4be8e2a653f..5ecfd0121f2aa14ae8e46a3f9c7249cb2233a0c9 100644 (file)
@@ -7,15 +7,18 @@
     */
     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
+        .long 0
+        .long __lxsys_fork
+        .long __lxsys_yield
+        .long __lxsys_sbrk
+        .long __lxsys_brk
+        .long __lxsys_getpid
+        .long __lxsys_getppid
+        .long __lxsys_sleep
+        .long __lxsys_exit
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
-            .dc.l 0
+            .long 0
         .endr
 
 .global syscall_hndlr
index c119676bf5874017ac92f1e00bbe681dbf120be1..5fdc9cbce541ad504fa66118578cc0a7cbfddb81 100644 (file)
@@ -103,7 +103,7 @@ void spawn_lxinit() {
     struct proc_info kinit;
 
     memset(&kinit, 0, sizeof(kinit));
-    kinit.parent = -1;
+    kinit.parent = (void*)0;
     kinit.pid = 1;
     kinit.intr_ctx = (isr_param) {
         .registers.esp = KSTACK_TOP - 20,
@@ -112,7 +112,8 @@ void spawn_lxinit() {
         .ss = KDATA_SEG,
         .eflags = cpu_reflags()
     };
-    kinit.page_table = dup_pagetable(kinit.pid);
+
+    setup_proc_mem(&kinit, PD_REFERENCED);
 
     // Ok... 准备fork进我们的init进程
     /*
@@ -238,7 +239,7 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) {
             KERNEL_PID,
             (void*)(VGA_BUFFER_VADDR + (i << PG_SIZE_BITS)), 
             (void*)(VGA_BUFFER_PADDR + (i << PG_SIZE_BITS)), 
-            PG_PREM_RW
+            PG_PREM_URW
         );
     }
     
index ec3425c1df6cd0fc0c141ff10238b223afb830a5..b2a9d9b88af16bce71be4cbe937061b580ec2ba9 100644 (file)
@@ -25,12 +25,12 @@ _lxinit_main()
     {
         pid_t pid = 0;
         if (!(pid = fork())) {
-            while (1)
-            {
-                // kprintf(KINFO "Process %d\n", i);
-                tty_put_char('0'+i);
-                yield();
+            sleep(i);
+            if (i == 3) {
+                i = *(int*)0x400000;
             }
+            tty_put_char('0'+i);
+            _exit(0);
         }
         kprintf(KINFO "Forked %d\n", pid);
     }
index dee5d28636fa30f5ff1fc3438762b1b5c1644662..b4b1d0d214f00611a4fdad84b465f7aab1bb7184 100644 (file)
 #include <lunaix/status.h>
 
 #include <lunaix/spike.h>
+#include <lunaix/syscall.h>
 
 
-int _syscall_sbrk(void* addr) {
+__DEFINE_LXSYSCALL1(int, sbrk, void*, addr) {
     heap_context_t* uheap = &__current->mm.u_heap;
     mutex_lock(&uheap->lock);
     int r = lxsbrk(uheap, addr);
@@ -30,7 +31,7 @@ int _syscall_sbrk(void* addr) {
     return r;
 }
 
-void* _syscall_brk(size_t size) {
+__DEFINE_LXSYSCALL1(void*, brk, size_t, size) {
     heap_context_t* uheap = &__current->mm.u_heap;
     mutex_lock(&uheap->lock);
     void* r = lxbrk(uheap, size);
index efb9dc8d36c67f169bec85ff80ff4b5ac1e035f2..3bf2128969fcf4129065c2e50378abe80d3e85f9 100644 (file)
@@ -134,12 +134,9 @@ pmm_free_page(pid_t owner, void* page)
         return 0;
     }
 
-    // 检查权限,保证:1) 用户只能释放用户页; 2) 内核可释放所有页。
-    if ((pm->owner & owner) == pm->owner) {
-        pm->ref_counts--;
-        return 1;
-    }
-    return 0;
+    // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放; 2) 内核可释放所有页。
+    pm->ref_counts--;
+    return 1;
 }
 
 int pmm_ref_page(pid_t owner, void* page) {
diff --git a/lunaix-os/kernel/mm/region.c b/lunaix-os/kernel/mm/region.c
new file mode 100644 (file)
index 0000000..1935583
--- /dev/null
@@ -0,0 +1,49 @@
+#include <lunaix/mm/region.h>
+#include <lunaix/mm/kalloc.h>
+#include <lunaix/process.h>
+
+void region_add(struct proc_info* proc,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
+    };
+
+    if (!proc->mm.regions) {
+        llist_init_head(&region->head);
+        proc->mm.regions = region;
+    }
+    else {
+        llist_append(&proc->mm.regions->head, &region->head);
+    }
+}
+
+void region_release_all(struct proc_info* proc) {
+    struct mm_region* head = proc->mm.regions;
+    struct mm_region *pos, *n;
+
+    llist_for_each(pos, n, &head->head, head) {
+        lxfree(pos);
+    }
+
+    proc->mm.regions = NULL;
+}
+
+struct mm_region* region_get(struct proc_info* proc, unsigned long vaddr) {
+    struct mm_region* head = proc->mm.regions;
+    
+    if (!head) {
+        return NULL;
+    }
+
+    struct mm_region *pos, *n;
+
+    llist_for_each(pos, n, &head->head, head) {
+        if (vaddr >= pos->start && vaddr < pos->end) {
+            return pos;
+        }
+    }
+    return NULL;
+}
index 40c8be5885ffdf332667a82d9900a87a06de9473..dcd2f2771acbf64af1dd09f0e3ed09adb20e39b2 100644 (file)
@@ -258,14 +258,14 @@ vmm_v2p(void* va)
 }
 
 void*
-vmm_mount_pd(void* pde) {
+vmm_mount_pd(uintptr_t mnt, 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;
+    l1pt->entry[(mnt >> 22)] = NEW_L1_ENTRY(PG_PREM_RW, pde);
+    return mnt;
 }
 
 void*
-vmm_unmount_pd() {
+vmm_unmount_pd(uintptr_t mnt) {
     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
-    l1pt->entry[(PD_MOUNT >> 22)] = 0;
+    l1pt->entry[(mnt >> 22)] = 0;
 }
\ No newline at end of file
index de6eaf6625ef0136f21e7aa0f94af7b95cc8ef4e..29cff62c78f16805077a2bbe277ffbc7b2125440 100644 (file)
@@ -1,8 +1,11 @@
 #include <lunaix/process.h>
 #include <lunaix/mm/vmm.h>
+#include <lunaix/mm/region.h>
 #include <lunaix/clock.h>
 #include <lunaix/syslog.h>
 #include <lunaix/common.h>
+#include <lunaix/syscall.h>
+#include <lunaix/spike.h>
 
 LOG_MODULE("PROC")
 
@@ -25,22 +28,9 @@ void* __dup_pagetable(pid_t pid, uintptr_t mount_point) {
 
         for (size_t j = 0; j < PG_MAX_ENTRIES; j++)
         {
-            uintptr_t va = ((i << 10) | j) << 12;
-            x86_pte_t ppte = ppt->entry[j];
-            if (!ppte || !(ppte & PG_PRESENT)) {
-                pt->entry[j] = ppte;
-                continue;
-            }
-
-            // FIXME: 根据 mm_region 将读共享的页(如堆)标为只读,而私有的页(如栈),则复制;而写共享的页则无需更改flags
-            if (va >= KSTACK_START) {
-                void* ppa = vmm_dup_page(pid, PG_ENTRY_ADDR(ppte));
-                ppte = ppte & 0xfff | (uintptr_t)ppa;
-            }
-            pt->entry[j] = ppte;
-            // ppte = ppte & ~PG_WRITE;
-            // pt->entry[j] = ppte;
-            // ppt->entry[j] = ppte;
+            x86_pte_t pte = ppt->entry[j];
+            pmm_ref_page(pid, pte & ~0xfff);
+            pt->entry[j] = pte;
         }
 
         ptd->entry[i] = (uintptr_t)pt_pp | PG_PREM_RW;
@@ -52,38 +42,99 @@ void* __dup_pagetable(pid_t pid, uintptr_t mount_point) {
 }
 
 void* dup_pagetable(pid_t pid) {
-    return __dup_pagetable(pid, L2_BASE_VADDR);
+    return __dup_pagetable(pid, PD_REFERENCED);
 }
 
-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.
-        
-    */
+__DEFINE_LXSYSCALL(void, fork) {
+    dup_proc();
+}
 
-    void* mnt_pt = vmm_mount_pd(__current->page_table);
+__DEFINE_LXSYSCALL(pid_t, getpid) {
+    return __current->pid;
+}
 
-    void* pg = __dup_pagetable(pid, mnt_pt);
+__DEFINE_LXSYSCALL(pid_t, getppid) {
+    return __current->parent->pid;
+}
 
-    vmm_unmount_pd();
+void dup_proc() {
+    pid_t pid = alloc_pid();
 
     struct proc_info pcb = (struct proc_info) {
         .created = clock_systime(),
         .pid = pid,
         .mm = __current->mm,
-        .page_table = pg,
         .intr_ctx = __current->intr_ctx,
-        .parent_created = __current->created
+        .parent = __current
     };
 
+    setup_proc_mem(&pcb, PD_MOUNT_1);    //挂载点#1是当前进程的页表
+
+    // 根据 mm_region 进一步配置页表
+    if (__current->mm.regions) {
+        struct mm_region *pos, *n;
+        llist_for_each(pos, n, &__current->mm.regions->head, head) {
+            region_add(&pcb, pos->start, pos->end, pos->attr);
+
+            // 如果写共享,则不作处理。
+            if ((pos->attr & REGION_WSHARED)) {
+                continue;
+            }
+
+            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 = &((x86_page_table*)(PD_MOUNT_1 | ((i & 0xffc00) << 2)))->entry[i & 0x3ff];
+                x86_pte_t *newproc = &((x86_page_table*)(PD_MOUNT_2 | ((i & 0xffc00) << 2)))->entry[i & 0x3ff];
+
+                if (pos->attr == REGION_RSHARED) {
+                    // 如果读共享,则将两者的都标注为只读,那么任何写入都将会应用COW策略。
+                    *curproc = *curproc & ~PG_WRITE;
+                    *newproc = *newproc & ~PG_WRITE;
+                }
+                else {
+                    // 如果是私有页,则将该页从新进程中移除。
+                    *newproc = 0;
+                }
+            }
+        }
+    }
+    
+    vmm_unmount_pd(PD_MOUNT_2);
+
     // 正如同fork,返回两次。
     pcb.intr_ctx.registers.eax = 0;
     __current->intr_ctx.registers.eax = pid;
 
     push_process(&pcb);
+}
+
+extern void __kernel_end;
+
+void setup_proc_mem(struct proc_info* proc, uintptr_t usedMnt) {
+    // copy the entire kernel page table
+    pid_t pid = proc->pid;
+    void* pt_copy = __dup_pagetable(pid, usedMnt);
+
+    vmm_mount_pd(PD_MOUNT_2, pt_copy);   // 将新进程的页表挂载到挂载点#2
+
+    // copy the kernel stack
+    for (size_t i = KSTACK_START >> 12; i <= KSTACK_TOP >> 12; i++)
+    {
+        x86_pte_t *ppte = &((x86_page_table*)(PD_MOUNT_2 | ((i & 0xffc00) << 2)))->entry[i & 0x3ff];
+        void* ppa = vmm_dup_page(pid, PG_ENTRY_ADDR(*ppte));
+        *ppte = (*ppte & 0xfff) | (uintptr_t)ppa;
+    }
+
+    // 我们不需要分配内核的区域,因为所有的内核代码和数据段只能通过系统调用来访问,任何非法的访问
+    // 都会导致eip落在区域外面,从而segmentation fault.
     
+    // 定义用户栈区域,但是不分配实际的物理页。我们会在Page fault handler里面实现动态分配物理页的逻辑。(虚拟内存的好处!)
+    // FIXME: 这里应该放到spawn_proc里面。
+    // region_add(proc, USTACK_END, USTACK_SIZE, REGION_PRIVATE | REGION_RW);
+
+    // 至于其他的区域我们暂时没有办法知道,因为那需要知道用户程序的信息。我们留到之后在处理。
+
+    proc->page_table = pt_copy;
 }
\ No newline at end of file
index f4fb021acccfdbf04cc6ab72d936f1202af3cbac..f5c2110d791e94d654a642421f4dce7375ea99d9 100644 (file)
@@ -8,6 +8,7 @@
 #include <lunaix/spike.h>
 #include <lunaix/status.h>
 #include <lunaix/syslog.h>
+#include <lunaix/syscall.h>
 
 #define MAX_PROCESS 512
 
@@ -34,6 +35,23 @@ void sched_init() {
     };
 }
 
+void run(struct proc_info* proc) {
+    if (!(__current->state & ~PROC_RUNNING)) {
+        __current->state = PROC_STOPPED;
+    }
+    proc->state = PROC_RUNNING;
+    
+    __current = proc;
+
+    cpu_lcr3(__current->page_table);
+
+    apic_done_servicing();
+
+    asm volatile (
+        "pushl %0\n"
+        "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
+}
+
 void schedule() {
     if (!sched_ctx.ptable_len) {
         return;
@@ -46,22 +64,39 @@ void schedule() {
     do {
         ptr = (ptr + 1) % sched_ctx.ptable_len;
         next = &sched_ctx._procs[ptr];
-    } while((next->state != PROC_STOPPED && next->state != PROC_CREATED) && ptr != prev_ptr);
+    } while(next->state != PROC_STOPPED && ptr != prev_ptr);
     
     sched_ctx.procs_index = ptr;
     
-    __current->state = PROC_STOPPED;
-    next->state = PROC_RUNNING;
-    
-    __current = next;
+    run(next);
+}
 
-    cpu_lcr3(__current->page_table);
+static void proc_timer_callback(struct proc_info* proc) {
+    proc->timer = NULL;
+    proc->state = PROC_STOPPED;
+}
 
-    apic_done_servicing();
+__DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) {
+    if (!seconds) {
+        return 0;
+    }
+    if (__current->timer) {
+        return __current->timer->counter / timer_context()->running_frequency;
+    }
 
-    asm volatile (
-        "pushl %0\n"
-        "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
+    struct lx_timer* timer = timer_run_second(seconds, proc_timer_callback, __current, 0);
+    __current->timer = timer;
+    __current->intr_ctx.registers.eax = seconds;
+    __current->state = PROC_BLOCKED;
+    schedule();
+}
+
+__DEFINE_LXSYSCALL1(void, exit, int, status) {
+    terminate_proc(status);
+}
+
+__DEFINE_LXSYSCALL(void, yield) {
+    schedule();
 }
 
 pid_t alloc_pid() {
@@ -86,15 +121,16 @@ void push_process(struct proc_info* process) {
         sched_ctx.ptable_len++;
     }
     
-    process->parent = __current->pid;
-    process->state = PROC_CREATED;
+    // every process is the parent of first process (pid=1)
+    process->parent = process->parent ? process->parent : &sched_ctx._procs;
+    process->state = PROC_STOPPED;
 
     sched_ctx._procs[index] = *process;
 }
 
 void destroy_process(pid_t pid) {
     int index = pid - 1;
-    if (index < 0 || index > sched_ctx.ptable_len) {
+    if (index <= 0 || index > sched_ctx.ptable_len) {
         __current->k_status = LXINVLDPID;
         return;
     }
@@ -104,8 +140,8 @@ void destroy_process(pid_t pid) {
     // TODO: recycle the physical pages used by page tables
 }
 
-void terminate_process(int exit_code) {
-    __current->state = PROC_TERMNAT;
+void terminate_proc(int exit_code) {
+    __current->state = exit_code < 0 ? PROC_SPOILED : PROC_TERMNAT;
     __current->exit_code = exit_code;
 
     schedule();
@@ -117,4 +153,15 @@ struct proc_info* get_process(pid_t pid) {
         return NULL;
     }
     return &sched_ctx._procs[index];
+}
+
+int orphaned_proc(pid_t pid) {
+    if(!pid) return 0;
+    if(pid >= sched_ctx.ptable_len) return 0;
+    struct proc_info* proc = &sched_ctx._procs[pid-1];
+    struct proc_info* parent = proc->parent;
+    
+    // 如果其父进程的状态是terminated, spoiled 或 destroy中的一种
+    // 或者其父进程是在该进程之后创建的,那么该进程为孤儿进程
+    return (parent->state & 0xe) || parent->created > proc->created;
 }
\ No newline at end of file
index 42a9ac214262d655a3e4b628091fce92d397373b..981b64565fc458121e3f071d4ba65a1540621876 100644 (file)
@@ -141,24 +141,24 @@ timer_init(uint32_t frequency)
     sched_ticks_counter = 0;
 }
 
-int
+struct lx_timer*
 timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags)
 {
     return timer_run(second * timer_ctx->running_frequency, callback, payload, flags);
 }
 
-int
+struct lx_timer*
 timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags)
 {
     return timer_run(timer_ctx->running_frequency / 1000 * millisecond, callback, payload, flags);
 }
 
-int
+struct lx_timer*
 timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
 {
     struct lx_timer* timer = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
 
-    if (!timer) return 0;
+    if (!timer) return NULL;
 
     timer->callback = callback;
     timer->counter = ticks;
@@ -168,7 +168,7 @@ timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
 
     llist_append(timer_ctx->active_timers, &timer->link);
 
-    return 1;
+    return timer;
 }
 
 static void
@@ -179,17 +179,20 @@ timer_update(const isr_param* param)
 
     llist_for_each(pos, n, &timer_list_head->link, link)
     {
-        if (--pos->counter) {
+        if (!pos->counter) {
+            llist_delete(&pos->link);
+            lxfree(pos);
+            continue;
+        }
+        
+        if (--(pos->counter)) {
             continue;
         }
 
         pos->callback ? pos->callback(pos->payload) : 1;
 
-        if (pos->flags & TIMER_MODE_PERIODIC) {
+        if ((pos->flags & TIMER_MODE_PERIODIC)) {
             pos->counter = pos->deadline;
-        } else {
-            llist_delete(&pos->link);
-            lxfree(pos);
         }
     }
     
index ce236c0c6ebbb01fc17c565a5e4d04b99579f833..f61e368f19483ee54d69c467bcb9678d9a452819 100644 (file)
@@ -61,8 +61,6 @@ SECTIONS {
     }
 
     __kernel_end = ALIGN(4K);
-    __pg_mount_point = ALIGN(4K);
-    . += 16K;
     __proc_table = ALIGN(4K);
     . += 128M;
     __kernel_heap_start = ALIGN(4K);    /* 内核结束的地方即堆开始的地方 */