From 8fdcd1575a97862975fa019f09c00453a2a7d8bb Mon Sep 17 00:00:00 2001 From: Minep Date: Sun, 19 Jun 2022 11:49:56 +0100 Subject: [PATCH 1/1] feat: User mode support. feat: All physical page allocations are now on-demand and being managed by PF handler. fix: Remove the 'garbage' mapping due to reserve area locking when initialize ACPI. refactor: alloc_pid now change to alloc_process. chore: annonation on issues that should be fixed chore: formatting some code. --- lunaix-os/arch/x86/hhk.c | 145 ++++++++++++----------- lunaix-os/includes/lunaix/common.h | 4 +- lunaix-os/includes/lunaix/mm/mm.h | 1 + lunaix-os/includes/lunaix/mm/region.h | 8 +- lunaix-os/includes/lunaix/process.h | 20 +++- lunaix-os/includes/lunaix/spike.h | 50 ++++---- lunaix-os/kernel/asm/x86/idt.c | 8 +- lunaix-os/kernel/asm/x86/interrupt.S | 2 + lunaix-os/kernel/asm/x86/intr_routines.c | 3 +- lunaix-os/kernel/asm/x86/pfault.c | 26 ++-- lunaix-os/kernel/asm/x86/tss.c | 10 +- lunaix-os/kernel/k_init.c | 47 ++++---- lunaix-os/kernel/lxinit.c | 9 +- lunaix-os/kernel/mm/region.c | 30 ++--- lunaix-os/kernel/mm/vmm.c | 4 +- lunaix-os/kernel/proc0.c | 91 +++++++++----- lunaix-os/kernel/process.c | 64 +++++----- lunaix-os/kernel/sched.c | 57 +++++---- lunaix-os/kernel/spike.c | 27 ++--- lunaix-os/kernel/tty/tty.c | 56 +++++---- lunaix-os/link/linker.ld | 6 + 21 files changed, 383 insertions(+), 285 deletions(-) diff --git a/lunaix-os/arch/x86/hhk.c b/lunaix-os/arch/x86/hhk.c index 5dae566..997bbdf 100644 --- a/lunaix-os/arch/x86/hhk.c +++ b/lunaix-os/arch/x86/hhk.c @@ -1,25 +1,27 @@ #include #include -#include #include +#include -#define PT_ADDR(ptd, pt_index) ((ptd_t*)ptd + (pt_index + 1) * 1024) -#define SET_PDE(ptd, pde_index, pde) *((ptd_t*)ptd + pde_index) = pde; -#define SET_PTE(ptd, pt_index, pte_index, pte) *(PT_ADDR(ptd, pt_index) + pte_index) = pte; -#define sym_val(sym) (uintptr_t)(&sym) +#define PT_ADDR(ptd, pt_index) ((ptd_t*)ptd + (pt_index + 1) * 1024) +#define SET_PDE(ptd, pde_index, pde) *((ptd_t*)ptd + pde_index) = pde; +#define SET_PTE(ptd, pt_index, pte_index, pte) \ + *(PT_ADDR(ptd, pt_index) + pte_index) = pte; +#define sym_val(sym) (uintptr_t)(&sym) -#define KERNEL_PAGE_COUNT ((sym_val(__kernel_end) - sym_val(__kernel_start) + 0x1000 - 1) >> 12); -#define HHK_PAGE_COUNT ((sym_val(__init_hhk_end) - 0x100000 + 0x1000 - 1) >> 12) +#define KERNEL_PAGE_COUNT \ + ((sym_val(__kernel_end) - sym_val(__kernel_start) + 0x1000 - 1) >> 12); +#define HHK_PAGE_COUNT ((sym_val(__init_hhk_end) - 0x100000 + 0x1000 - 1) >> 12) // use table #1 -#define PG_TABLE_IDENTITY 0 +#define PG_TABLE_IDENTITY 0 // use table #2-8 // hence the max size of kernel is 8MiB -#define PG_TABLE_KERNEL 1 +#define PG_TABLE_KERNEL 1 // use table #9 -#define PG_TABLE_STACK 8 +#define PG_TABLE_STACK 8 // Provided by linker (see linker.ld) extern uint8_t __kernel_start; @@ -27,108 +29,115 @@ extern uint8_t __kernel_end; extern uint8_t __init_hhk_end; extern uint8_t _k_stack; -void -_init_page(ptd_t* ptd) { +void +_init_page(ptd_t* ptd) +{ SET_PDE(ptd, 0, NEW_L1_ENTRY(PG_PREM_RW, ptd + PG_MAX_ENTRIES)) - - // 对低1MiB空间进行对等映射(Identity mapping),也包括了我们的VGA,方便内核操作。 - for (uint32_t i = 0; i < 256; i++) - { - SET_PTE(ptd, PG_TABLE_IDENTITY, i, NEW_L2_ENTRY(PG_PREM_RW, (i << PG_SIZE_BITS))) + + // 对低1MiB空间进行对等映射(Identity + // mapping),也包括了我们的VGA,方便内核操作。 + for (uint32_t i = 0; i < 256; i++) { + SET_PTE(ptd, + PG_TABLE_IDENTITY, + i, + NEW_L2_ENTRY(PG_PREM_RW, (i << PG_SIZE_BITS))) } - // 对等映射我们的hhk_init,这样一来,当分页与地址转换开启后,我们依然能够照常执行最终的 jmp 指令来跳转至 + // 对等映射我们的hhk_init,这样一来,当分页与地址转换开启后,我们依然能够照常执行最终的 + // jmp 指令来跳转至 // 内核的入口点 - for (uint32_t i = 0; i < HHK_PAGE_COUNT; i++) - { - SET_PTE(ptd, PG_TABLE_IDENTITY, 256 + i, NEW_L2_ENTRY(PG_PREM_RW, 0x100000 + (i << PG_SIZE_BITS))) + for (uint32_t i = 0; i < HHK_PAGE_COUNT; i++) { + SET_PTE(ptd, + PG_TABLE_IDENTITY, + 256 + i, + NEW_L2_ENTRY(PG_PREM_RW, 0x100000 + (i << PG_SIZE_BITS))) } - + // --- 将内核重映射至高半区 --- - - // 这里是一些计算,主要是计算应当映射进的 页目录 与 页表 的条目索引(Entry Index) + + // 这里是一些计算,主要是计算应当映射进的 页目录 与 页表 的条目索引(Entry + // Index) uint32_t kernel_pde_index = L1_INDEX(sym_val(__kernel_start)); uint32_t kernel_pte_index = L2_INDEX(sym_val(__kernel_start)); uint32_t kernel_pg_counts = KERNEL_PAGE_COUNT; - + // 将内核所需要的页表注册进页目录 // 当然,就现在而言,我们的内核只占用不到50个页(每个页表包含1024个页) // 这里分配了3个页表(12MiB),未雨绸缪。 - for (uint32_t i = 0; i < PG_TABLE_STACK - PG_TABLE_KERNEL; i++) - { - SET_PDE( - ptd, - kernel_pde_index + i, - NEW_L1_ENTRY(PG_PREM_RW, PT_ADDR(ptd, PG_TABLE_KERNEL + i)) - ) + for (uint32_t i = 0; i < PG_TABLE_STACK - PG_TABLE_KERNEL; i++) { + SET_PDE(ptd, + kernel_pde_index + i, + NEW_L1_ENTRY(PG_PREM_URW, PT_ADDR(ptd, PG_TABLE_KERNEL + i))) } - + // 首先,检查内核的大小是否可以fit进我们这几个表(12MiB) - if (kernel_pg_counts > (PG_TABLE_STACK - PG_TABLE_KERNEL) * PG_MAX_ENTRIES) { + if (kernel_pg_counts > + (PG_TABLE_STACK - PG_TABLE_KERNEL) * PG_MAX_ENTRIES) { // ERROR: require more pages // here should do something else other than head into blocking - asm ("ud2"); + asm("ud2"); } - + // 计算内核.text段的物理地址 uintptr_t kernel_pm = V2P(&__kernel_start); - + // 重映射内核至高半区地址(>=0xC0000000) - for (uint32_t i = 0; i < kernel_pg_counts; i++) - { - SET_PTE( - ptd, - PG_TABLE_KERNEL, - kernel_pte_index + i, - NEW_L2_ENTRY(PG_PREM_RW, kernel_pm + (i << PG_SIZE_BITS)) - ) + for (uint32_t i = 0; i < kernel_pg_counts; i++) { + // FIXME: 只是用作用户模式(R3)测试! + // 在实际中,内核代码除了极少部分需要暴露给R3(如从信号返回),其余的应为R0。 + SET_PTE(ptd, + PG_TABLE_KERNEL, + kernel_pte_index + i, + NEW_L2_ENTRY(PG_PREM_URW, kernel_pm + (i << PG_SIZE_BITS))) } // 最后一个entry用于循环映射 - SET_PDE( - ptd, - PG_MAX_ENTRIES - 1, - NEW_L1_ENTRY(T_SELF_REF_PERM, ptd) - ); + SET_PDE(ptd, PG_MAX_ENTRIES - 1, NEW_L1_ENTRY(T_SELF_REF_PERM, ptd)); } -uint32_t __save_subset(uint8_t* destination, uint8_t* base, unsigned int size) { +uint32_t +__save_subset(uint8_t* destination, uint8_t* base, unsigned int size) +{ unsigned int i = 0; - for (; i < size; i++) - { + for (; i < size; i++) { *(destination + i) = *(base + i); } return i; } -void -_save_multiboot_info(multiboot_info_t* info, uint8_t* destination) { +void +_save_multiboot_info(multiboot_info_t* info, uint8_t* destination) +{ uint32_t current = 0; - uint8_t* info_b = (uint8_t*) info; - for (; current < sizeof(multiboot_info_t); current++) - { + uint8_t* info_b = (uint8_t*)info; + for (; current < sizeof(multiboot_info_t); current++) { *(destination + current) = *(info_b + current); } - ((multiboot_info_t*) destination)->mmap_addr = (uintptr_t)destination + current; - current += __save_subset(destination + current, (uint8_t*)info->mmap_addr, info->mmap_length); + ((multiboot_info_t*)destination)->mmap_addr = + (uintptr_t)destination + current; + current += __save_subset( + destination + current, (uint8_t*)info->mmap_addr, info->mmap_length); if (present(info->flags, MULTIBOOT_INFO_DRIVE_INFO)) { - ((multiboot_info_t*) destination)->drives_addr = (uintptr_t)destination + current; - current += __save_subset(destination + current, (uint8_t*)info->drives_addr, info->drives_length); + ((multiboot_info_t*)destination)->drives_addr = + (uintptr_t)destination + current; + current += __save_subset(destination + current, + (uint8_t*)info->drives_addr, + info->drives_length); } } -void -_hhk_init(ptd_t* ptd, uint32_t kpg_size) { +void +_hhk_init(ptd_t* ptd, uint32_t kpg_size) +{ // 初始化 kpg 全为0 // P.s. 真没想到GRUB会在这里留下一堆垃圾! 老子的页表全乱套了! - uint8_t* kpg = (uint8_t*) ptd; - for (uint32_t i = 0; i < kpg_size; i++) - { + uint8_t* kpg = (uint8_t*)ptd; + for (uint32_t i = 0; i < kpg_size; i++) { *(kpg + i) = 0; } - + _init_page(ptd); } \ No newline at end of file diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h index f9ab67f..fe0c0bc 100644 --- a/lunaix-os/includes/lunaix/common.h +++ b/lunaix-os/includes/lunaix/common.h @@ -32,8 +32,8 @@ #define USER_START 0x400000 #define USTACK_SIZE 0x100000 -#define USTACK_TOP 0x9fffffff -#define USTACK_END (USTACK_TOP - USTACK_SIZE + 1) +#define USTACK_TOP 0x9ffffff0 +#define USTACK_END (0x9fffffff - USTACK_SIZE + 1) #define UMMAP_AREA 0x4D000000 #define SYS_TIMER_FREQUENCY_HZ 2048 diff --git a/lunaix-os/includes/lunaix/mm/mm.h b/lunaix-os/includes/lunaix/mm/mm.h index 060b881..6585916 100644 --- a/lunaix-os/includes/lunaix/mm/mm.h +++ b/lunaix-os/includes/lunaix/mm/mm.h @@ -33,6 +33,7 @@ typedef struct #define REGION_WSHARED 0x2 #define REGION_PERM_MASK 0x1c +#define REGION_MODE_MASK 0x3 #define REGION_READ (1 << 2) #define REGION_WRITE (1 << 3) diff --git a/lunaix-os/includes/lunaix/mm/region.h b/lunaix-os/includes/lunaix/mm/region.h index 8271d2b..9978d72 100644 --- a/lunaix-os/includes/lunaix/mm/region.h +++ b/lunaix-os/includes/lunaix/mm/region.h @@ -4,18 +4,18 @@ #include void -region_add(struct mm_region** proc, +region_add(struct mm_region* proc, unsigned long start, unsigned long end, unsigned int attr); void -region_release_all(struct mm_region** proc); +region_release_all(struct mm_region* proc); struct mm_region* -region_get(struct mm_region** proc, unsigned long vaddr); +region_get(struct mm_region* proc, unsigned long vaddr); void -region_copy(struct mm_region** src, struct mm_region** dest); +region_copy(struct mm_region* src, struct mm_region* dest); #endif /* __LUNAIX_REGION_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 26f33bd..7a5d502 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -24,7 +24,7 @@ struct proc_mm { heap_context_t u_heap; - struct mm_region* regions; + struct mm_region regions; }; struct proc_sig @@ -71,11 +71,21 @@ struct proc_info extern volatile struct proc_info* __current; -pid_t -alloc_pid(); +/** + * @brief 分配并初始化一个进程控制块 + * + * @return struct proc_info* + */ +struct proc_info* +alloc_process(); +/** + * @brief 初始化进程用户空间 + * + * @param pcb + */ void -init_proc(struct proc_info* pcb); +init_proc_user_space(struct proc_info* pcb); /** * @brief 向系统发布一个进程,使其可以被调度。 @@ -83,7 +93,7 @@ init_proc(struct proc_info* pcb); * @param process */ void -push_process(struct proc_info* process); +commit_process(struct proc_info* process); pid_t destroy_process(pid_t pid); diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 8fd47b5..1ce7481 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -4,42 +4,52 @@ // Some helper functions. As helpful as Spike the Dragon! :) // 除法向上取整 -#define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k)) +#define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k)) // 除法向下取整 -#define FLOOR(v, k) ((v) >> (k)) +#define FLOOR(v, k) ((v) >> (k)) // 获取v最近的最大k倍数 -#define ROUNDUP(v, k) (((v) + (k) - 1) & ~((k) - 1)) +#define ROUNDUP(v, k) (((v) + (k)-1) & ~((k)-1)) // 获取v最近的最小k倍数 -#define ROUNDDOWN(v, k) ((v) & ~((k) - 1)) +#define ROUNDDOWN(v, k) ((v) & ~((k)-1)) -inline static void spin() { - while(1); +#define __USER__ __attribute__((section("usrtext"))) + +inline static void +spin() +{ + while (1) + ; } #ifdef __LUNAIXOS_DEBUG__ -#define assert(cond) \ - if (!(cond)) { \ - __assert_fail(#cond, __FILE__, __LINE__); \ +#define assert(cond) \ + if (!(cond)) { \ + __assert_fail(#cond, __FILE__, __LINE__); \ } -#define assert_msg(cond, msg) \ - if (!(cond)) { \ - __assert_fail(msg, __FILE__, __LINE__); \ +#define assert_msg(cond, msg) \ + if (!(cond)) { \ + __assert_fail(msg, __FILE__, __LINE__); \ } -void __assert_fail(const char* expr, const char* file, unsigned int line) __attribute__((noinline, noreturn)); +void +__assert_fail(const char* expr, const char* file, unsigned int line) + __attribute__((noinline, noreturn)); #else -#define assert(cond) (void)(cond); //assert nothing -#define assert_msg(cond, msg) (void)(cond); //assert nothing +#define assert(cond) (void)(cond); // assert nothing +#define assert_msg(cond, msg) (void)(cond); // assert nothing #endif -void panick(const char* msg); - - -#define wait_until(cond) while(!(cond)); -#define loop_until(cond) while(!(cond)); +void +panick(const char* msg); +#define wait_until(cond) \ + while (!(cond)) \ + ; +#define loop_until(cond) \ + while (!(cond)) \ + ; #endif /* __LUNAIX_SPIKE_H */ diff --git a/lunaix-os/kernel/asm/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c index f453313..3e408fd 100644 --- a/lunaix-os/kernel/asm/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -45,6 +45,7 @@ _init_idt() _set_idt_intr_entry(FAULT_DIVISION_ERROR, 0x08, _asm_isr0, 0); _set_idt_intr_entry(FAULT_GENERAL_PROTECTION, 0x08, _asm_isr13, 0); _set_idt_intr_entry(FAULT_PAGE_FAULT, 0x08, _asm_isr14, 0); + _set_idt_intr_entry(FAULT_STACK_SEG_FAULT, 0x08, _asm_isr12, 0); _set_idt_intr_entry(APIC_ERROR_IV, 0x08, _asm_isr250, 0); _set_idt_intr_entry(APIC_LINT0_IV, 0x08, _asm_isr251, 0); @@ -57,12 +58,7 @@ _init_idt() // system defined interrupts _set_idt_intr_entry(LUNAIX_SYS_PANIC, 0x08, _asm_isr32, 0); - // syscall is a trap gate (recall: trap does NOT clear IF flag upon - // interruption) - // // XXX: this should be fine, as our design of context switch support - // interruptible syscall We make this a non-trap entry, and enable interrupt + // We make this a non-trap entry, and enable interrupt // only when needed! - // FIXME: This may cause nasty concurrency bug! We should 'lockify' our - // code! _set_idt_intr_entry(LUNAIX_SYS_CALL, 0x08, _asm_isr33, 3); } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index cd3f547..e941983 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -26,6 +26,7 @@ isr_template FAULT_DIVISION_ERROR isr_template FAULT_GENERAL_PROTECTION, no_error_code=0 isr_template FAULT_PAGE_FAULT, no_error_code=0 + isr_template FAULT_STACK_SEG_FAULT, no_error_code=0 isr_template LUNAIX_SYS_PANIC isr_template LUNAIX_SYS_CALL @@ -183,6 +184,7 @@ iret +.section .usrtext sig_wrapper: # in user mode movl %esp, %eax and $0xfffffff0, %esp diff --git a/lunaix-os/kernel/asm/x86/intr_routines.c b/lunaix-os/kernel/asm/x86/intr_routines.c index 0b05e75..8cc3ff5 100644 --- a/lunaix-os/kernel/asm/x86/intr_routines.c +++ b/lunaix-os/kernel/asm/x86/intr_routines.c @@ -83,9 +83,10 @@ intr_routine_init() intr_subscribe(FAULT_DIVISION_ERROR, intr_routine_divide_zero); intr_subscribe(FAULT_GENERAL_PROTECTION, intr_routine_general_protection); intr_subscribe(FAULT_PAGE_FAULT, intr_routine_page_fault); + intr_subscribe(FAULT_STACK_SEG_FAULT, intr_routine_page_fault); intr_subscribe(LUNAIX_SYS_PANIC, intr_routine_sys_panic); intr_subscribe(APIC_SPIV_IV, intr_routine_apic_spi); intr_subscribe(APIC_ERROR_IV, intr_routine_apic_error); - intr_set_fallback_handler(intr_set_fallback_handler); + intr_set_fallback_handler(intr_routine_fallback); } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 34589cb..30fd498 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -17,6 +17,8 @@ kprintf(const char* fmt, ...) va_end(args); } +#define COW_MASK (REGION_RSHARED | REGION_READ | REGION_WRITE) + extern void __print_panic_msg(const char* msg, const isr_param* param); @@ -48,17 +50,16 @@ intr_routine_page_fault(const isr_param* param) goto segv_term; } - x86_pte_t* pte = PTE_MOUNTED(PD_REFERENCED, ptr >> 12); - if (*pte & PG_PRESENT) { - if ((hit_region->attr & REGION_PERM_MASK) == - (REGION_RSHARED | REGION_READ)) { + x86_pte_t* pte = &PTE_MOUNTED(PD_REFERENCED, ptr >> 12); + if ((*pte & PG_PRESENT)) { + if ((hit_region->attr & COW_MASK) == COW_MASK) { // normal page fault, do COW cpu_invplg(pte); 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; + goto resolved; } // impossible cases or accessing privileged page goto segv_term; @@ -68,15 +69,18 @@ intr_routine_page_fault(const isr_param* param) // Invalid location goto segv_term; } + uintptr_t loc = *pte & ~0xfff; - // a writable page, not present, pte attr is not null - // and no indication of cached page -> a new page need to be alloc + + // a writable page, not present, not cached, pte attr is not null + // -> a new page need to be alloc if ((hit_region->attr & REGION_WRITE) && (*pte & 0xfff) && !loc) { cpu_invplg(pte); uintptr_t pa = pmm_alloc_page(__current->pid, 0); *pte = *pte | pa | PG_PRESENT; - return; + goto resolved; } + // page not present, bring it from disk or somewhere else __print_panic_msg("WIP page fault route", param); while (1) @@ -90,6 +94,12 @@ segv_term: param->eip); terminate_proc(LXSEGFAULT); // should not reach + while (1) + ; + +resolved: + cpu_invplg(ptr); + return; } int diff --git a/lunaix-os/kernel/asm/x86/tss.c b/lunaix-os/kernel/asm/x86/tss.c index c09db9e..74dad78 100644 --- a/lunaix-os/kernel/asm/x86/tss.c +++ b/lunaix-os/kernel/asm/x86/tss.c @@ -1,12 +1,10 @@ #include #include -struct x86_tss _tss = { - .link = 0, - .esp0 = KSTACK_START, - .ss0 = KDATA_SEG -}; +struct x86_tss _tss = { .link = 0, .esp0 = KSTACK_TOP, .ss0 = KDATA_SEG }; -void tss_update_esp(uint32_t esp0) { +void +tss_update_esp(uint32_t esp0) +{ _tss.esp0 = esp0; } \ No newline at end of file diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 59d9347..257112e 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -96,7 +96,7 @@ _kernel_init() void spawn_proc0() { - struct proc_info proc0; + struct proc_info* proc0 = alloc_process(); /** * @brief @@ -113,15 +113,14 @@ spawn_proc0() * 目前的解决方案是2 */ - init_proc(&proc0); - proc0.intr_ctx = (isr_param){ .registers = { .ds = KDATA_SEG, - .es = KDATA_SEG, - .fs = KDATA_SEG, - .gs = KDATA_SEG }, - .cs = KCODE_SEG, - .eip = (void*)__proc0, - .ss = KDATA_SEG, - .eflags = cpu_reflags() }; + proc0->intr_ctx = (isr_param){ .registers = { .ds = KDATA_SEG, + .es = KDATA_SEG, + .fs = KDATA_SEG, + .gs = KDATA_SEG }, + .cs = KCODE_SEG, + .eip = (void*)__proc0, + .ss = KDATA_SEG, + .eflags = cpu_reflags() }; // 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的! // cpu_disable_interrupt(); @@ -129,10 +128,10 @@ spawn_proc0() /* Ok... 首先fork进我们的零号进程,而后由那里,我们fork进init进程。 */ // 把当前虚拟地址空间(内核)复制一份。 - proc0.page_table = vmm_dup_vmspace(proc0.pid); + proc0->page_table = vmm_dup_vmspace(proc0->pid); // 直接切换到新的拷贝,进行配置。 - cpu_lcr3(proc0.page_table); + cpu_lcr3(proc0->page_table); // 为内核创建一个专属栈空间。 for (size_t i = 0; i < (KSTACK_SIZE >> PG_SIZE_BITS); i++) { @@ -154,25 +153,25 @@ spawn_proc0() "pushl $0\n" "movl %%esp, %0\n" "movl %%ebx, %%esp\n" - : "=m"(proc0.intr_ctx.registers.esp) - : "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(proc0.intr_ctx.eip) + : "=m"(proc0->intr_ctx.registers.esp) + : "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(proc0->intr_ctx.eip) : "%ebx", "memory"); // 向调度器注册进程。 - push_process(&proc0); + commit_process(proc0); // 由于时钟中断与APIC未就绪,我们需要手动进行第一次调度。这里也会同时隐式地恢复我们的eflags.IF位 - struct proc_info* proc = get_process(0); - assert_msg(proc, "fail to get proc0!"); - - proc->state = PROC_RUNNING; + proc0->state = PROC_RUNNING; asm volatile("pushl %0\n" - "jmp switch_to\n" ::"r"(proc)); + "jmp switch_to\n" ::"r"(proc0)); /* Should not return */ assert_msg(0, "Unexpected Return"); } +extern void __usrtext_start; +extern void __usrtext_end; + // 按照 Memory map 标识可用的物理页 void setup_memory(multiboot_memory_map_t* map, size_t map_size) @@ -216,6 +215,14 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) VMAP_NULL); } + assert_msg(!((uintptr_t)&__usrtext_start & 0xfff) && + !((uintptr_t)&__usrtext_end & 0xfff), + "Bad usrtext alignment"); + + for (uintptr_t i = &__usrtext_start; i < &__usrtext_end; i += PG_SIZE) { + vmm_set_mapping(PD_REFERENCED, i, V2P(i), PG_PREM_UR, VMAP_NULL); + } + // 更新VGA缓冲区位置至虚拟地址 tty_set_buffer((void*)VGA_BUFFER_VADDR); diff --git a/lunaix-os/kernel/lxinit.c b/lunaix-os/kernel/lxinit.c index 19e7eff..57e2bda 100644 --- a/lunaix-os/kernel/lxinit.c +++ b/lunaix-os/kernel/lxinit.c @@ -16,8 +16,9 @@ LOG_MODULE("INIT") // #define FORK_BOMB_DEMO #define WAIT_DEMO +#define IN_USER_MODE -void +void __USER__ _lxinit_main() { #ifdef FORK_BOMB_DEMO @@ -93,15 +94,15 @@ _lxinit_main() struct kdb_keyinfo_pkt keyevent; while (1) { if (!kbd_recv_key(&keyevent)) { - // yield(); + yield(); continue; } if ((keyevent.state & KBD_KEY_FPRESSED) && (keyevent.keycode & 0xff00) <= KEYPAD) { tty_put_char((char)(keyevent.keycode & 0x00ff)); - tty_sync_cursor(); + // FIXME: io to vga port is privileged and cause #GP in user mode + // tty_sync_cursor(); } } - spin(); } \ No newline at end of file diff --git a/lunaix-os/kernel/mm/region.c b/lunaix-os/kernel/mm/region.c index d9fddeb..1f706dc 100644 --- a/lunaix-os/kernel/mm/region.c +++ b/lunaix-os/kernel/mm/region.c @@ -2,7 +2,7 @@ #include void -region_add(struct mm_region** regions, +region_add(struct mm_region* regions, unsigned long start, unsigned long end, unsigned int attr) @@ -11,55 +11,47 @@ region_add(struct mm_region** regions, *region = (struct mm_region){ .attr = attr, .end = end, .start = start }; - if (!*regions) { - llist_init_head(®ion->head); - *regions = region; - } else { - llist_append(&(*regions)->head, ®ion->head); - } + llist_append(®ions->head, ®ion->head); } void -region_release_all(struct mm_region** regions) +region_release_all(struct mm_region* regions) { struct mm_region *pos, *n; - llist_for_each(pos, n, &(*regions)->head, head) + llist_for_each(pos, n, ®ions->head, head) { lxfree(pos); } - - *regions = NULL; } void -region_copy(struct mm_region** src, struct mm_region** dest) +region_copy(struct mm_region* src, struct mm_region* dest) { - if (!*src) { + if (!src) { return; } struct mm_region *pos, *n; - llist_init_head(*dest); - llist_for_each(pos, n, &(*src)->head, head) + llist_for_each(pos, n, &src->head, head) { region_add(dest, pos->start, pos->end, pos->attr); } } struct mm_region* -region_get(struct mm_region** regions, unsigned long vaddr) +region_get(struct mm_region* regions, unsigned long vaddr) { - if (!*regions) { + if (!regions) { return NULL; } struct mm_region *pos, *n; - llist_for_each(pos, n, &(*regions)->head, head) + llist_for_each(pos, n, ®ions->head, head) { - if (vaddr >= pos->start && vaddr < pos->end) { + if (pos->start <= vaddr && vaddr < pos->end) { return pos; } } diff --git a/lunaix-os/kernel/mm/vmm.c b/lunaix-os/kernel/mm/vmm.c index 40e3724..fe3d65c 100644 --- a/lunaix-os/kernel/mm/vmm.c +++ b/lunaix-os/kernel/mm/vmm.c @@ -51,7 +51,9 @@ vmm_set_mapping(uintptr_t mnt, } // This must be writable - l1pt->entry[l1_inx] = NEW_L1_ENTRY(attr | PG_WRITE, new_l1pt_pa); + l1pt->entry[l1_inx] = + NEW_L1_ENTRY(attr | PG_WRITE | PG_PRESENT, new_l1pt_pa); + memset((void*)l2pt, 0, PG_SIZE); } else { x86_pte_t pte = l2pt->entry[l2_inx]; diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index 2b21ac7..4cc414c 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -25,7 +25,23 @@ init_platform(); void lock_reserved_memory(); -// #define ENABLE_USER_MODE +void +unlock_reserved_memory(); + +void +__do_reserved_memory(int unlock); + +void __USER__ +__proc0_usr() +{ + if (!fork()) { + asm("jmp _lxinit_main"); + } + + while (1) { + yield(); + } +} /** * @brief LunaixOS的零号进程,该进程永远为可执行。 @@ -39,7 +55,9 @@ void __proc0() { init_platform(); -#ifdef ENABLE_USER_MODE + + init_proc_user_space(__current); + asm volatile("movw %0, %%ax\n" "movw %%ax, %%es\n" "movw %%ax, %%ds\n" @@ -52,16 +70,8 @@ __proc0() "retf" ::"i"(UDATA_SEG), "i"(USTACK_TOP & ~0xf), "i"(UCODE_SEG), - "r"(&&usr)); -#endif -usr: - if (!fork()) { - asm("jmp _lxinit_main"); - } - - while (1) { - yield(); - } + "r"(__proc0_usr) + : "eax", "memory"); } extern uint8_t __kernel_start; /* link/linker.ld */ @@ -74,14 +84,11 @@ init_platform() { assert_msg(kalloc_init(), "Fail to initialize heap"); - size_t hhk_init_pg_count = ((uintptr_t)(&__init_hhk_end)) >> PG_SIZE_BITS; - kprintf(KINFO "[MM] Releaseing %d pages from 0x0.\n", hhk_init_pg_count); - // Fuck it, I will no longer bother this little 1MiB // I just release 4 pages for my APIC & IOAPIC remappings - for (size_t i = 0; i < 3; i++) { - vmm_del_mapping(PD_REFERENCED, (void*)(i << PG_SIZE_BITS)); - } + // for (size_t i = 0; i < 3; i++) { + // vmm_del_mapping(PD_REFERENCED, (void*)(i << PG_SIZE_BITS)); + // } // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射 lock_reserved_memory(); @@ -105,13 +112,28 @@ init_platform() syscall_install(); - for (size_t i = 256; i < hhk_init_pg_count; i++) { - vmm_del_mapping(PD_REFERENCED, (void*)(i << PG_SIZE_BITS)); + unlock_reserved_memory(); + + for (size_t i = 0; i < (uintptr_t)(&__init_hhk_end); i += PG_SIZE) { + vmm_del_mapping(PD_REFERENCED, (void*)i); + pmm_free_page(KERNEL_PID, (void*)i); } } void lock_reserved_memory() +{ + __do_reserved_memory(0); +} + +void +unlock_reserved_memory() +{ + __do_reserved_memory(1); +} + +void +__do_reserved_memory(int unlock) { multiboot_memory_map_t* mmaps = _k_init_mb_info->mmap_addr; size_t map_size = @@ -119,18 +141,29 @@ lock_reserved_memory() // v_mapping mapping; for (unsigned int i = 0; i < map_size; i++) { multiboot_memory_map_t mmap = mmaps[i]; - if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE) { + uint8_t* pa = PG_ALIGN(mmap.addr_low); + if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE || pa <= MEM_4MB) { + // Don't fuck up our kernel code or any free area! continue; } - uint8_t* pa = PG_ALIGN(mmap.addr_low); size_t pg_num = CEIL(mmap.len_low, PG_SIZE_BITS); - for (size_t j = 0; j < pg_num; j++) { - uintptr_t _pa = pa + (j << PG_SIZE_BITS); - // if (vmm_lookup(_pa, &mapping) && *mapping.pte) { - // continue; - // } - vmm_set_mapping(PD_REFERENCED, _pa, _pa, PG_PREM_R, VMAP_IGNORE); - pmm_mark_page_occupied(KERNEL_PID, _pa >> 12, 0); + size_t j = 0; + if (!unlock) { + for (; j < pg_num; j++) { + uintptr_t _pa = pa + (j << PG_SIZE_BITS); + if (_pa >= KERNEL_MM_BASE) { + // Don't fuck up our kernel space! + break; + } + vmm_set_mapping(PD_REFERENCED, _pa, _pa, PG_PREM_R, VMAP_NULL); + } + // Save the progress for later unmapping. + mmaps[i].len_low = j * PG_SIZE; + } else { + for (; j < pg_num; j++) { + uintptr_t _pa = pa + (j << PG_SIZE_BITS); + vmm_del_mapping(PD_REFERENCED, _pa); + } } } } \ No newline at end of file diff --git a/lunaix-os/kernel/process.c b/lunaix-os/kernel/process.c index a41c6a6..a783efe 100644 --- a/lunaix-os/kernel/process.c +++ b/lunaix-os/kernel/process.c @@ -47,7 +47,7 @@ __dup_pagetable(pid_t pid, uintptr_t mount_point) pt->entry[j] = pte; } - ptd->entry[i] = (uintptr_t)pt_pp | PG_PREM_RW; + ptd->entry[i] = (uintptr_t)pt_pp | PG_ENTRY_FLAGS(ptde); } ptd->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, ptd_pp); @@ -135,27 +135,38 @@ __DEFINE_LXSYSCALL2(int, setpgid, pid_t, pid, pid_t, pgid) } void -init_proc(struct proc_info* pcb) +init_proc_user_space(struct proc_info* pcb) { - memset(pcb, 0, sizeof(*pcb)); + vmm_mount_pd(PD_MOUNT_1, pcb->page_table); - pcb->pid = alloc_pid(); - pcb->created = clock_systime(); - pcb->state = PROC_CREATED; - pcb->pgid = pcb->pid; + /*--- 分配用户栈 ---*/ + + // 注册用户栈区域 + region_add( + &pcb->mm.regions, USTACK_END, USTACK_TOP, REGION_RW | REGION_RSHARED); + + // 预留地址空间,具体物理页将由Page Fault Handler按需分配。 + for (uintptr_t i = PG_ALIGN(USTACK_END); i < USTACK_TOP; i += PG_SIZE) { + vmm_set_mapping(PD_MOUNT_1, i, 0, PG_ALLOW_USER | PG_WRITE, VMAP_NULL); + } + + // todo: other uspace initialization stuff + + vmm_unmount_pd(PD_MOUNT_1); } void __mark_region(uintptr_t start_vpn, uintptr_t end_vpn, int attr) { - for (size_t i = start_vpn; i < end_vpn; i++) { + 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_1, i); cpu_invplg(newproc); - if (attr == REGION_RSHARED) { + if ((attr & REGION_MODE_MASK) == REGION_RSHARED) { // 如果读共享,则将两者的都标注为只读,那么任何写入都将会应用COW策略。 cpu_invplg(curproc); + cpu_invplg(i << 12); *curproc = *curproc & ~PG_WRITE; *newproc = *newproc & ~PG_WRITE; } else { @@ -168,43 +179,38 @@ __mark_region(uintptr_t start_vpn, uintptr_t end_vpn, int attr) pid_t dup_proc() { - struct proc_info pcb; - init_proc(&pcb); - pcb.mm = __current->mm; - pcb.intr_ctx = __current->intr_ctx; - pcb.parent = __current; + struct proc_info* pcb = alloc_process(); + pcb->mm.u_heap = __current->mm.u_heap; + pcb->intr_ctx = __current->intr_ctx; + pcb->parent = __current; - region_copy(&__current->mm.regions, &pcb.mm.regions); + region_copy(&__current->mm.regions, &pcb->mm.regions); - setup_proc_mem(&pcb, PD_REFERENCED); + setup_proc_mem(pcb, PD_REFERENCED); // 根据 mm_region 进一步配置页表 - if (!__current->mm.regions) { - goto not_copy; - } struct mm_region *pos, *n; - llist_for_each(pos, n, &pcb.mm.regions->head, head) + llist_for_each(pos, n, &pcb->mm.regions.head, head) { // 如果写共享,则不作处理。 if ((pos->attr & REGION_WSHARED)) { continue; } - uintptr_t start_vpn = PG_ALIGN(pos->start) >> 12; - uintptr_t end_vpn = PG_ALIGN(pos->end) >> 12; + uintptr_t start_vpn = pos->start >> 12; + uintptr_t end_vpn = pos->end >> 12; __mark_region(start_vpn, end_vpn, pos->attr); } -not_copy: vmm_unmount_pd(PD_MOUNT_1); // 正如同fork,返回两次。 - pcb.intr_ctx.registers.eax = 0; + pcb->intr_ctx.registers.eax = 0; - push_process(&pcb); + commit_process(pcb); - return pcb.pid; + return pcb->pid; } extern void __kernel_end; @@ -241,12 +247,6 @@ setup_proc_mem(struct proc_info* proc, uintptr_t usedMnt) // 我们不需要分配内核的区域,因为所有的内核代码和数据段只能通过系统调用来访问,任何非法的访问 // 都会导致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 ee25ebb..1a9743d 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -49,8 +49,9 @@ run(struct proc_info* proc) } proc->state = PROC_RUNNING; - // FIXME: 这里还是得再考虑一下。 + // XXX: 我们需要这一步吗? // tss_update_esp(__current->intr_ctx.esp); + apic_done_servicing(); asm volatile("pushl %0\n" @@ -168,8 +169,8 @@ done: return destroy_process(proc->pid); } -pid_t -alloc_pid() +struct proc_info* +alloc_process() { pid_t i = 0; for (; @@ -180,29 +181,35 @@ alloc_pid() if (i == MAX_PROCESS) { panick("Panic in Ponyville shimmer!"); } - return i; -} - -void -push_process(struct proc_info* process) -{ - int index = process->pid; - if (index < 0 || index > sched_ctx.ptable_len) { - __current->k_status = LXINVLDPID; - return; - } - if (index == sched_ctx.ptable_len) { + if (i == sched_ctx.ptable_len) { sched_ctx.ptable_len++; } - sched_ctx._procs[index] = *process; + struct proc_info* proc = &sched_ctx._procs[i]; + memset(proc, 0, sizeof(*proc)); - process = &sched_ctx._procs[index]; + proc->state = PROC_CREATED; + proc->pid = i; + proc->created = clock_systime(); + proc->pgid = proc->pid; - // make sure the reference is relative to process table - llist_init_head(&process->children); - llist_init_head(&process->grp_member); + llist_init_head(&proc->mm.regions); + llist_init_head(&proc->children); + llist_init_head(&proc->grp_member); + + return proc; +} + +void +commit_process(struct proc_info* process) +{ + assert(process == &sched_ctx._procs[process->pid]); + + if (process->state != PROC_CREATED) { + __current->k_status = LXINVL; + return; + } // every process is the child of first process (pid=1) if (process->parent) { @@ -230,12 +237,10 @@ destroy_process(pid_t pid) proc->state = PROC_DESTROY; llist_delete(&proc->siblings); - if (proc->mm.regions) { - struct mm_region *pos, *n; - llist_for_each(pos, n, &proc->mm.regions->head, head) - { - lxfree(pos); - } + struct mm_region *pos, *n; + llist_for_each(pos, n, &proc->mm.regions.head, head) + { + lxfree(pos); } vmm_mount_pd(PD_MOUNT_1, proc->page_table); diff --git a/lunaix-os/kernel/spike.c b/lunaix-os/kernel/spike.c index 4cb2051..5aa0137 100644 --- a/lunaix-os/kernel/spike.c +++ b/lunaix-os/kernel/spike.c @@ -1,27 +1,26 @@ -#include #include #include +#include static char buffer[1024]; -void __assert_fail(const char* expr, const char* file, unsigned int line) { +void +__assert_fail(const char* expr, const char* file, unsigned int line) +{ sprintf(buffer, "%s (%s:%u)", expr, file, line); // Here we load the buffer's address into %edi ("D" constraint) // This is a convention we made that the LUNAIX_SYS_PANIC syscall will - // print the panic message passed via %edi. (see kernel/asm/x86/interrupts.c) - asm( - "int %0" - ::"i"(LUNAIX_SYS_PANIC), "D"(buffer) - ); + // print the panic message passed via %edi. (see + // kernel/asm/x86/interrupts.c) + asm("int %0" ::"i"(LUNAIX_SYS_PANIC), "D"(buffer)); - spin(); // never reach + spin(); // never reach } -void panick(const char* msg) { - asm( - "int %0" - ::"i"(LUNAIX_SYS_PANIC), "D"(msg) - ); +void +panick(const char* msg) +{ + asm("int %0" ::"i"(LUNAIX_SYS_PANIC), "D"(msg)); spin(); -} \ No newline at end of file +} diff --git a/lunaix-os/kernel/tty/tty.c b/lunaix-os/kernel/tty/tty.c index c779ed5..4164239 100644 --- a/lunaix-os/kernel/tty/tty.c +++ b/lunaix-os/kernel/tty/tty.c @@ -1,8 +1,8 @@ +#include #include -#include #include +#include #include -#include #define TTY_WIDTH 80 #define TTY_HEIGHT 25 @@ -14,18 +14,22 @@ static vga_attribute tty_theme_color = VGA_COLOR_BLACK; static uint32_t tty_x = 0; static uint32_t tty_y = 0; -void tty_init(void* vga_buf) { +void +tty_init(void* vga_buf) +{ tty_vga_buffer = (vga_attribute*)vga_buf; tty_clear(); io_outb(0x3D4, 0x0A); - io_outb(0x3D5, (io_inb(0x3D5) & 0xC0) | 13); - - io_outb(0x3D4, 0x0B); - io_outb(0x3D5, (io_inb(0x3D5) & 0xE0) | 15); + io_outb(0x3D5, (io_inb(0x3D5) & 0xC0) | 13); + + io_outb(0x3D4, 0x0B); + io_outb(0x3D5, (io_inb(0x3D5) & 0xE0) | 15); } -void tty_set_buffer(void* vga_buf) { +void +tty_set_buffer(void* vga_buf) +{ tty_vga_buffer = (vga_attribute*)vga_buf; } @@ -50,10 +54,12 @@ tty_put_char(char chr) break; case '\x08': tty_x = tty_x ? tty_x - 1 : 0; - *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) = (tty_theme_color | 0x20); + *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) = + (tty_theme_color | 0x20); break; default: - *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) = (tty_theme_color | chr); + *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) = + (tty_theme_color | chr); tty_x++; break; } @@ -67,12 +73,15 @@ tty_put_char(char chr) } } -void tty_sync_cursor() { +void +tty_sync_cursor() +{ tty_set_cursor(tty_x, tty_y); } - -void tty_set_cursor(uint8_t x, uint8_t y) { +void +tty_set_cursor(uint8_t x, uint8_t y) +{ if (x >= TTY_WIDTH || y >= TTY_HEIGHT) { x = y = 0; } @@ -90,7 +99,11 @@ tty_put_str(char* str) tty_put_char(*str); str++; } - tty_sync_cursor(); + // FIXME: This does not work in user mode. + // Work around: + // 1. (Easy) Define an IO Permission bitmap in TSS + // 2. (More effort) Mount onto file system. (/dev/tty) + // tty_sync_cursor(); } void @@ -115,26 +128,29 @@ tty_clear() } void -tty_clear_line(unsigned int y) { - for (size_t i = 0; i < TTY_WIDTH; i++) - { +tty_clear_line(unsigned int y) +{ + for (size_t i = 0; i < TTY_WIDTH; i++) { *(tty_vga_buffer + i + y * TTY_WIDTH) = tty_theme_color; } } void -tty_set_cpos(unsigned int x, unsigned int y) { +tty_set_cpos(unsigned int x, unsigned int y) +{ tty_x = x % TTY_WIDTH; tty_y = y % TTY_HEIGHT; } void -tty_get_cpos(unsigned int* x, unsigned int* y) { +tty_get_cpos(unsigned int* x, unsigned int* y) +{ *x = tty_x; *y = tty_y; } vga_attribute -tty_get_theme() { +tty_get_theme() +{ return tty_theme_color; } \ No newline at end of file diff --git a/lunaix-os/link/linker.ld b/lunaix-os/link/linker.ld index 2bd3ded..ba3a385 100644 --- a/lunaix-os/link/linker.ld +++ b/lunaix-os/link/linker.ld @@ -41,6 +41,12 @@ SECTIONS { build/obj/hal/*.o (.text) } + __usrtext_start = ALIGN(4K); + .usrtext BLOCK(4K) : AT ( ADDR(.usrtext) - 0xC0000000 ) { + build/obj/kernel/*.o (.usrtext) + } + __usrtext_end = ALIGN(4K); + .bss BLOCK(4K) : AT ( ADDR(.bss) - 0xC0000000 ) { build/obj/kernel/*.o (.bss) build/obj/hal/*.o (.bss) -- 2.27.0