From 0067bc210e621ccda286092d081a7890d65e1c18 Mon Sep 17 00:00:00 2001 From: Minep Date: Tue, 31 May 2022 21:43:35 +0100 Subject: [PATCH] feat: added ability to identify process vm regions 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. --- lunaix-os/includes/lunaix/common.h | 6 ++ lunaix-os/includes/lunaix/lunistd.h | 8 ++ lunaix-os/includes/lunaix/mm/mm.h | 13 +-- lunaix-os/includes/lunaix/mm/page.h | 20 +++-- lunaix-os/includes/lunaix/mm/region.h | 14 ++++ lunaix-os/includes/lunaix/mm/vmm.h | 4 +- lunaix-os/includes/lunaix/proc.h | 2 - lunaix-os/includes/lunaix/process.h | 20 +++-- lunaix-os/includes/lunaix/sched.h | 2 +- lunaix-os/includes/lunaix/status.h | 1 + lunaix-os/includes/lunaix/syscall.h | 46 +++++++++-- lunaix-os/includes/lunaix/timer.h | 6 +- lunaix-os/kernel/asm/x86/interrupts.c | 4 + lunaix-os/kernel/asm/x86/pfault.c | 53 ++++++++++-- lunaix-os/kernel/asm/x86/syscall.S | 17 ++-- lunaix-os/kernel/k_init.c | 7 +- lunaix-os/kernel/lxinit.c | 10 +-- lunaix-os/kernel/mm/dmm.c | 5 +- lunaix-os/kernel/mm/pmm.c | 9 +- lunaix-os/kernel/mm/region.c | 49 +++++++++++ lunaix-os/kernel/mm/vmm.c | 10 +-- lunaix-os/kernel/process.c | 113 +++++++++++++++++++------- lunaix-os/kernel/sched.c | 77 ++++++++++++++---- lunaix-os/kernel/time/timer.c | 23 +++--- lunaix-os/link/linker.ld | 2 - 25 files changed, 390 insertions(+), 131 deletions(-) create mode 100644 lunaix-os/includes/lunaix/mm/region.h create mode 100644 lunaix-os/kernel/mm/region.c diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h index 27243bf..6482008 100644 --- a/lunaix-os/includes/lunaix/common.h +++ b/lunaix-os/includes/lunaix/common.h @@ -17,6 +17,12 @@ #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__ diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index 20e394f..12faab5 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/mm/mm.h b/lunaix-os/includes/lunaix/mm/mm.h index 2ea1ac2..8318eaa 100644 --- a/lunaix-os/includes/lunaix/mm/mm.h +++ b/lunaix-os/includes/lunaix/mm/mm.h @@ -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; }; diff --git a/lunaix-os/includes/lunaix/mm/page.h b/lunaix-os/includes/lunaix/mm/page.h index 4b6a1a1..5755a46 100644 --- a/lunaix-os/includes/lunaix/mm/page.h +++ b/lunaix-os/includes/lunaix/mm/page.h @@ -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 index 0000000..8da41d2 --- /dev/null +++ b/lunaix-os/includes/lunaix/mm/region.h @@ -0,0 +1,14 @@ +#ifndef __LUNAIX_REGION_H +#define __LUNAIX_REGION_H + +#include +#include + +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 */ diff --git a/lunaix-os/includes/lunaix/mm/vmm.h b/lunaix-os/includes/lunaix/mm/vmm.h index 2e9f72f..99190c7 100644 --- a/lunaix-os/includes/lunaix/mm/vmm.h +++ b/lunaix-os/includes/lunaix/mm/vmm.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/proc.h b/lunaix-os/includes/lunaix/proc.h index f22fd68..cec5670 100644 --- a/lunaix-os/includes/lunaix/proc.h +++ b/lunaix-os/includes/lunaix/proc.h @@ -3,8 +3,6 @@ #include -__LXSYSCALL1(void, exit, int, status) - __LXSYSCALL(void, yield) #endif /* __LUNAIX_SYS_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index efa1166..d9a5bb1 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -6,33 +6,35 @@ #include #include #include +#include // 虽然内核不是进程,但为了区分,这里使用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); diff --git a/lunaix-os/includes/lunaix/sched.h b/lunaix-os/includes/lunaix/sched.h index a0778a3..618c324 100644 --- a/lunaix-os/includes/lunaix/sched.h +++ b/lunaix-os/includes/lunaix/sched.h @@ -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; diff --git a/lunaix-os/includes/lunaix/status.h b/lunaix-os/includes/lunaix/status.h index 44fa2f9..db33da2 100644 --- a/lunaix-os/includes/lunaix/status.h +++ b/lunaix-os/includes/lunaix/status.h @@ -6,5 +6,6 @@ #define LXINVLDPTR -(2) #define LXOUTOFMEM -(3) #define LXINVLDPID -(4) +#define LXSEGFAULT -(5) #endif /* __LUNAIX_CODE_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index d933584..ee63c40 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -3,11 +3,14 @@ #include -#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) \ } diff --git a/lunaix-os/includes/lunaix/timer.h b/lunaix-os/includes/lunaix/timer.h index 78976a5..567b8d2 100644 --- a/lunaix-os/includes/lunaix/timer.h +++ b/lunaix-os/includes/lunaix/timer.h @@ -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* diff --git a/lunaix-os/kernel/asm/x86/interrupts.c b/lunaix-os/kernel/asm/x86/interrupts.c index 8330bc2..09bd1eb 100644 --- a/lunaix-os/kernel/asm/x86/interrupts.c +++ b/lunaix-os/kernel/asm/x86/interrupts.c @@ -6,6 +6,7 @@ #include #include #include +#include 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) { diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 63a40a3..f07c74f 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -1,8 +1,12 @@ #include #include +#include +#include #include #include #include +#include +#include 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 diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index 25e153f..5ecfd01 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -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 diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index c119676..5fdc9cb 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -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 ); } diff --git a/lunaix-os/kernel/lxinit.c b/lunaix-os/kernel/lxinit.c index ec3425c..b2a9d9b 100644 --- a/lunaix-os/kernel/lxinit.c +++ b/lunaix-os/kernel/lxinit.c @@ -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); } diff --git a/lunaix-os/kernel/mm/dmm.c b/lunaix-os/kernel/mm/dmm.c index dee5d28..b4b1d0d 100644 --- a/lunaix-os/kernel/mm/dmm.c +++ b/lunaix-os/kernel/mm/dmm.c @@ -20,9 +20,10 @@ #include #include +#include -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); diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c index efb9dc8..3bf2128 100644 --- a/lunaix-os/kernel/mm/pmm.c +++ b/lunaix-os/kernel/mm/pmm.c @@ -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 index 0000000..1935583 --- /dev/null +++ b/lunaix-os/kernel/mm/region.c @@ -0,0 +1,49 @@ +#include +#include +#include + +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(®ion->head); + proc->mm.regions = region; + } + else { + llist_append(&proc->mm.regions->head, ®ion->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; +} diff --git a/lunaix-os/kernel/mm/vmm.c b/lunaix-os/kernel/mm/vmm.c index 40c8be5..dcd2f27 100644 --- a/lunaix-os/kernel/mm/vmm.c +++ b/lunaix-os/kernel/mm/vmm.c @@ -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 diff --git a/lunaix-os/kernel/process.c b/lunaix-os/kernel/process.c index de6eaf6..29cff62 100644 --- a/lunaix-os/kernel/process.c +++ b/lunaix-os/kernel/process.c @@ -1,8 +1,11 @@ #include #include +#include #include #include #include +#include +#include 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 diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index f4fb021..f5c2110 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -8,6 +8,7 @@ #include #include #include +#include #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 diff --git a/lunaix-os/kernel/time/timer.c b/lunaix-os/kernel/time/timer.c index 42a9ac2..981b645 100644 --- a/lunaix-os/kernel/time/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -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); } } diff --git a/lunaix-os/link/linker.ld b/lunaix-os/link/linker.ld index ce236c0..f61e368 100644 --- a/lunaix-os/link/linker.ld +++ b/lunaix-os/link/linker.ld @@ -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); /* 内核结束的地方即堆开始的地方 */ -- 2.27.0