From 48b4a227035048fdebcd32532deb7a857c6199ac Mon Sep 17 00:00:00 2001 From: Minep Date: Mon, 30 May 2022 01:46:55 +0100 Subject: [PATCH] basic process support and some syscalls --- lunaix-os/.vscode/c_cpp_properties.json | 5 +- lunaix-os/arch/x86/boot.S | 10 +- lunaix-os/arch/x86/hhk.c | 10 +- lunaix-os/includes/arch/x86/gdt.h | 2 + lunaix-os/includes/arch/x86/interrupts.h | 45 +------ lunaix-os/includes/arch/x86/tss.h | 14 ++ lunaix-os/includes/arch/x86/vectors.h | 48 +++++++ lunaix-os/includes/hal/cpu.h | 23 +++- lunaix-os/includes/lunaix/common.h | 25 ++-- lunaix-os/includes/lunaix/keyboard.h | 3 +- lunaix-os/includes/lunaix/lunistd.h | 13 ++ lunaix-os/includes/lunaix/mm/dmm.h | 9 +- lunaix-os/includes/lunaix/mm/mm.h | 44 ++++++ lunaix-os/includes/lunaix/mm/page.h | 12 +- lunaix-os/includes/lunaix/mm/pmm.h | 36 ++++- lunaix-os/includes/lunaix/mm/vmm.h | 32 ++++- lunaix-os/includes/lunaix/proc.h | 10 ++ lunaix-os/includes/lunaix/process.h | 73 ++++++++++ lunaix-os/includes/lunaix/sched.h | 15 +++ lunaix-os/includes/lunaix/status.h | 10 ++ lunaix-os/includes/lunaix/syscall.h | 62 +++++++++ lunaix-os/includes/lunaix/types.h | 8 ++ lunaix-os/kernel/asm/x86/gdt.c | 7 +- lunaix-os/kernel/asm/x86/idt.c | 1 + lunaix-os/kernel/asm/x86/interrupt.S | 26 +++- lunaix-os/kernel/asm/x86/interrupts.c | 18 +++ lunaix-os/kernel/asm/x86/intr_routines.c | 20 +-- lunaix-os/kernel/asm/x86/pfault.c | 21 +++ lunaix-os/kernel/asm/x86/prologue.S | 28 ++-- lunaix-os/kernel/asm/x86/syscall.S | 48 +++++++ lunaix-os/kernel/asm/x86/tss.c | 13 ++ lunaix-os/kernel/ds/semaphore.c | 3 +- lunaix-os/kernel/k_init.c | 118 +++++++++------- lunaix-os/kernel/{k_main.c => lxinit.c} | 27 +++- lunaix-os/kernel/mm/cow.c | 16 +++ lunaix-os/kernel/mm/dmm.c | 30 ++++- lunaix-os/kernel/mm/kalloc.c | 22 ++- lunaix-os/kernel/mm/pmm.c | 164 ++++++++++++++--------- lunaix-os/kernel/mm/vmm.c | 85 +++++++----- lunaix-os/kernel/peripheral/ps2kbd.c | 2 +- lunaix-os/kernel/process.c | 68 ++++++++++ lunaix-os/kernel/sched.c | 120 +++++++++++++++++ lunaix-os/kernel/syscall.c | 13 ++ lunaix-os/kernel/time/timer.c | 15 +++ lunaix-os/link/linker.ld | 4 + 45 files changed, 1083 insertions(+), 295 deletions(-) create mode 100644 lunaix-os/includes/arch/x86/tss.h create mode 100644 lunaix-os/includes/arch/x86/vectors.h create mode 100644 lunaix-os/includes/lunaix/lunistd.h create mode 100644 lunaix-os/includes/lunaix/mm/mm.h create mode 100644 lunaix-os/includes/lunaix/proc.h create mode 100644 lunaix-os/includes/lunaix/process.h create mode 100644 lunaix-os/includes/lunaix/sched.h create mode 100644 lunaix-os/includes/lunaix/status.h create mode 100644 lunaix-os/includes/lunaix/syscall.h create mode 100644 lunaix-os/includes/lunaix/types.h create mode 100644 lunaix-os/kernel/asm/x86/pfault.c create mode 100644 lunaix-os/kernel/asm/x86/syscall.S create mode 100644 lunaix-os/kernel/asm/x86/tss.c rename lunaix-os/kernel/{k_main.c => lxinit.c} (75%) create mode 100644 lunaix-os/kernel/mm/cow.c create mode 100644 lunaix-os/kernel/process.c create mode 100644 lunaix-os/kernel/sched.c create mode 100644 lunaix-os/kernel/syscall.c diff --git a/lunaix-os/.vscode/c_cpp_properties.json b/lunaix-os/.vscode/c_cpp_properties.json index f069ef5..574a1bd 100644 --- a/lunaix-os/.vscode/c_cpp_properties.json +++ b/lunaix-os/.vscode/c_cpp_properties.json @@ -3,7 +3,7 @@ { "name": "OS-DEV", "includePath": [ - "${workspaceFolder}/includes/**" + "${workspaceFolder}/includes" ], "compilerArgs": [ "-ffreestanding", @@ -13,8 +13,7 @@ "defines": [], "compilerPath": "${HOME}/opt/cross-compiler/bin/i686-elf-gcc", "cStandard": "gnu99", - "intelliSenseMode": "gcc-x86", - "configurationProvider": "ms-vscode.makefile-tools" + "intelliSenseMode": "gcc-x86" } ], "version": 4 diff --git a/lunaix-os/arch/x86/boot.S b/lunaix-os/arch/x86/boot.S index 8ba78cc..9c86bbc 100644 --- a/lunaix-os/arch/x86/boot.S +++ b/lunaix-os/arch/x86/boot.S @@ -2,7 +2,7 @@ #include #define MB_FLAGS MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN -#define KPG_SIZE 24*1024 +#define KPG_SIZE 10*4096 .section .multiboot .long MULTIBOOT_MAGIC @@ -24,9 +24,9 @@ /* 1 page directory, - 5 page tables: + 9 page tables: 1. Mapping reserved area and hhk_init - 2-5. Remapping the kernels + 2-9. Remapping the kernels */ .section .kpg @@ -77,9 +77,9 @@ andl $0xfffff000, %eax # 有点多余,但写上还算明白一点 movl %eax, %cr3 - /* 开启分页与地址转换 (CR0.PG=1) */ + /* 开启分页与地址转换 (CR0.PG=1, PG.WP=1) */ movl %cr0, %eax - orl $0x80000000, %eax + orl $0x80010000, %eax movl %eax, %cr0 addl $16, %esp diff --git a/lunaix-os/arch/x86/hhk.c b/lunaix-os/arch/x86/hhk.c index c6797c8..5dae566 100644 --- a/lunaix-os/arch/x86/hhk.c +++ b/lunaix-os/arch/x86/hhk.c @@ -14,12 +14,12 @@ // use table #1 #define PG_TABLE_IDENTITY 0 -// use table #2-4 +// use table #2-8 // hence the max size of kernel is 8MiB #define PG_TABLE_KERNEL 1 -// use table #5 -#define PG_TABLE_STACK 4 +// use table #9 +#define PG_TABLE_STACK 8 // Provided by linker (see linker.ld) extern uint8_t __kernel_start; @@ -29,7 +29,7 @@ extern uint8_t _k_stack; void _init_page(ptd_t* ptd) { - SET_PDE(ptd, 0, NEW_L1_ENTRY(PG_PRESENT, ptd + PG_MAX_ENTRIES)) + 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++) @@ -67,7 +67,7 @@ _init_page(ptd_t* ptd) { 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 - while (1); + asm ("ud2"); } // 计算内核.text段的物理地址 diff --git a/lunaix-os/includes/arch/x86/gdt.h b/lunaix-os/includes/arch/x86/gdt.h index bb2fa27..f312166 100644 --- a/lunaix-os/includes/arch/x86/gdt.h +++ b/lunaix-os/includes/arch/x86/gdt.h @@ -48,6 +48,8 @@ #define SEG_R3_DATA SD_TYPE(SEG_DATA_RDWR) | SD_CODE_DATA(1) | SD_DPL(3) | \ SD_PRESENT(1) | SD_AVL(0) | SD_64BITS(0) | SD_32BITS(1) | \ SD_4K_GRAN(1) + +#define SEG_TSS SD_TYPE(9) | SD_DPL(0) | SD_PRESENT(1) void diff --git a/lunaix-os/includes/arch/x86/interrupts.h b/lunaix-os/includes/arch/x86/interrupts.h index 664d69d..9d3d085 100644 --- a/lunaix-os/includes/arch/x86/interrupts.h +++ b/lunaix-os/includes/arch/x86/interrupts.h @@ -1,49 +1,7 @@ #ifndef __LUNAIX_INTERRUPTS_H #define __LUNAIX_INTERRUPTS_H - -#define FAULT_DIVISION_ERROR 0 -#define FAULT_TRAP_DEBUG_EXCEPTION 1 -#define INT_NMI 2 -#define TRAP_BREAKPOINT 3 -#define TRAP_OVERFLOW 4 -#define FAULT_BOUND_EXCEED 5 -#define FAULT_INVALID_OPCODE 6 -#define FAULT_NO_MATH_PROCESSOR 7 -#define ABORT_DOUBLE_FAULT 8 -#define FAULT_RESERVED_0 9 -#define FAULT_INVALID_TSS 10 -#define FAULT_SEG_NOT_PRESENT 11 -#define FAULT_STACK_SEG_FAULT 12 -#define FAULT_GENERAL_PROTECTION 13 -#define FAULT_PAGE_FAULT 14 -#define FAULT_RESERVED_1 15 -#define FAULT_X87_FAULT 16 -#define FAULT_ALIGNMENT_CHECK 17 -#define ABORT_MACHINE_CHECK 18 -#define FAULT_SIMD_FP_EXCEPTION 19 -#define FAULT_VIRTUALIZATION_EXCEPTION 20 -#define FAULT_CONTROL_PROTECTION 21 - -// LunaixOS related -#define LUNAIX_SYS_PANIC 32 - -#define EX_INTERRUPT_BEGIN 200 - -// Keyboard -#define PC_KBD_IV 201 - -#define RTC_TIMER_IV 210 - -// 来自APIC的中断有着最高的优先级。 -// APIC related -#define APIC_ERROR_IV 250 -#define APIC_LINT0_IV 251 -#define APIC_SPIV_IV 252 -#define APIC_TIMER_IV 253 - -#define PC_AT_IRQ_RTC 8 -#define PC_AT_IRQ_KBD 1 +#include "vectors.h" #ifndef __ASM__ #include @@ -88,6 +46,7 @@ ISR(20) ISR(21) ISR(32) +ISR(33) ISR(201) diff --git a/lunaix-os/includes/arch/x86/tss.h b/lunaix-os/includes/arch/x86/tss.h new file mode 100644 index 0000000..3310aa6 --- /dev/null +++ b/lunaix-os/includes/arch/x86/tss.h @@ -0,0 +1,14 @@ +#ifndef __LUNAIX_TSS_H +#define __LUNAIX_TSS_H +#include + +struct x86_tss { + uint32_t link; + uint32_t esp0; + uint16_t ss0; + uint8_t __padding[94]; +} __attribute__((packed)); + +void tss_update(uint32_t ss0, uint32_t esp0); + +#endif /* __LUNAIX_TSS_H */ diff --git a/lunaix-os/includes/arch/x86/vectors.h b/lunaix-os/includes/arch/x86/vectors.h new file mode 100644 index 0000000..5fb424f --- /dev/null +++ b/lunaix-os/includes/arch/x86/vectors.h @@ -0,0 +1,48 @@ +#ifndef __LUNAIX_VECTORS_H +#define __LUNAIX_VECTORS_H + +#define FAULT_DIVISION_ERROR 0 +#define FAULT_TRAP_DEBUG_EXCEPTION 1 +#define INT_NMI 2 +#define TRAP_BREAKPOINT 3 +#define TRAP_OVERFLOW 4 +#define FAULT_BOUND_EXCEED 5 +#define FAULT_INVALID_OPCODE 6 +#define FAULT_NO_MATH_PROCESSOR 7 +#define ABORT_DOUBLE_FAULT 8 +#define FAULT_RESERVED_0 9 +#define FAULT_INVALID_TSS 10 +#define FAULT_SEG_NOT_PRESENT 11 +#define FAULT_STACK_SEG_FAULT 12 +#define FAULT_GENERAL_PROTECTION 13 +#define FAULT_PAGE_FAULT 14 +#define FAULT_RESERVED_1 15 +#define FAULT_X87_FAULT 16 +#define FAULT_ALIGNMENT_CHECK 17 +#define ABORT_MACHINE_CHECK 18 +#define FAULT_SIMD_FP_EXCEPTION 19 +#define FAULT_VIRTUALIZATION_EXCEPTION 20 +#define FAULT_CONTROL_PROTECTION 21 + +// LunaixOS related +#define LUNAIX_SYS_PANIC 32 +#define LUNAIX_SYS_CALL 33 + +#define EX_INTERRUPT_BEGIN 200 + +// Keyboard +#define PC_KBD_IV 201 + +#define RTC_TIMER_IV 210 + +// 来自APIC的中断有着最高的优先级。 +// APIC related +#define APIC_ERROR_IV 250 +#define APIC_LINT0_IV 251 +#define APIC_SPIV_IV 252 +#define APIC_TIMER_IV 253 + +#define PC_AT_IRQ_RTC 8 +#define PC_AT_IRQ_KBD 1 + +#endif /* __LUNAIX_VECTORS_H */ diff --git a/lunaix-os/includes/hal/cpu.h b/lunaix-os/includes/hal/cpu.h index bdb07c4..b155d4b 100644 --- a/lunaix-os/includes/hal/cpu.h +++ b/lunaix-os/includes/hal/cpu.h @@ -39,19 +39,36 @@ cpu_has_apic(); static inline reg32 cpu_rcr0() { - asm("mov %cr0, %eax"); + uintptr_t val; + asm volatile("movl %%cr0,%0" : "=r" (val)); + return val; } static inline reg32 cpu_rcr2() { - asm("mov %cr2, %eax"); + uintptr_t val; + asm volatile("movl %%cr2,%0" : "=r" (val)); + return val; } static inline reg32 cpu_rcr3() { - asm("mov %cr3, %eax"); + uintptr_t val; + asm volatile("movl %%cr3,%0" : "=r" (val)); + return val; +} + +static inline reg32 +cpu_reflags() +{ + uintptr_t val; + asm volatile( + "pushf\n" + "popl %0\n" + :"=r"(val)::); + return val; } #pragma GCC diagnostic pop diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h index 51c37f6..27243bf 100644 --- a/lunaix-os/includes/lunaix/common.h +++ b/lunaix-os/includes/lunaix/common.h @@ -1,20 +1,26 @@ #ifndef __LUNAIX_CONSTANTS_H #define __LUNAIX_CONSTANTS_H -#include - -#define K_STACK_SIZE (64 << 10) -#define K_STACK_START ((0xFFBFFFFFU - K_STACK_SIZE) + 1) -#define HIGHER_HLF_BASE 0xC0000000UL -#define MEM_1MB 0x100000UL +#define KSTACK_SIZE (64 << 10) +#define KSTACK_START ((0xFFBFFFFFU - KSTACK_SIZE) + 1) +#define KSTACK_TOP 0xffbffff0 +#define HIGHER_HLF_BASE 0xC0000000 +#define MEM_1MB 0x100000 -#define VGA_BUFFER_VADDR 0xB0000000UL -#define VGA_BUFFER_PADDR 0xB8000UL +#define VGA_BUFFER_VADDR 0xB0000000 +#define VGA_BUFFER_PADDR 0xB8000 #define VGA_BUFFER_SIZE 4096 -#define SYS_TIMER_FREQUENCY_HZ 2048 +#define KCODE_SEG 0x08 +#define KDATA_SEG 0x10 +#define UCODE_SEG 0x1B +#define UDATA_SEG 0x23 +#define TSS_SEG 0x28 +#define SYS_TIMER_FREQUENCY_HZ 2048 +#ifndef __ASM__ +#include // From Linux kernel v2.6.0 /** * container_of - cast a member of a structure out to the containing structure @@ -28,4 +34,5 @@ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif #endif /* __LUNAIX_CONSTANTS_H */ diff --git a/lunaix-os/includes/lunaix/keyboard.h b/lunaix-os/includes/lunaix/keyboard.h index 7f13088..2dd40dd 100644 --- a/lunaix-os/includes/lunaix/keyboard.h +++ b/lunaix-os/includes/lunaix/keyboard.h @@ -1,5 +1,6 @@ #ifndef __LUNAIX_KEYBOARD_H #define __LUNAIX_KEYBOARD_H +#include // Lunaix Keycode // 15 7 0 @@ -15,8 +16,6 @@ typedef unsigned short kbd_keycode_t; typedef unsigned short kbd_kstate_t; -#include - #define KEYPAD 0x0100 #define FN_KEY 0x0200 diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h new file mode 100644 index 0000000..20e394f --- /dev/null +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -0,0 +1,13 @@ +#ifndef __LUNAIX_UNISTD_H +#define __LUNAIX_UNISTD_H + +#include +#include + +__LXSYSCALL(pid_t, fork) + +__LXSYSCALL1(int, sbrk, void*, addr) + +__LXSYSCALL1(void*, brk, size_t, size) + +#endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/includes/lunaix/mm/dmm.h b/lunaix-os/includes/lunaix/mm/dmm.h index 22b0539..793ab3f 100644 --- a/lunaix-os/includes/lunaix/mm/dmm.h +++ b/lunaix-os/includes/lunaix/mm/dmm.h @@ -3,6 +3,8 @@ // Dynamic Memory (i.e., heap) Manager #include +#include +#include #define M_ALLOCATED 0x1 #define M_PREV_FREE 0x2 @@ -29,13 +31,6 @@ #define HEAP_INIT_SIZE 4096 -typedef struct -{ - void* start; - void* brk; - void* max_addr; -} heap_context_t; - int dmm_init(heap_context_t* heap); diff --git a/lunaix-os/includes/lunaix/mm/mm.h b/lunaix-os/includes/lunaix/mm/mm.h new file mode 100644 index 0000000..2ea1ac2 --- /dev/null +++ b/lunaix-os/includes/lunaix/mm/mm.h @@ -0,0 +1,44 @@ +#ifndef __LUNAIX_MM_H +#define __LUNAIX_MM_H + +#include +#include + +typedef struct +{ + void* start; + void* brk; + void* max_addr; + mutex_t lock; +} heap_context_t; + +/** + * @brief 私有区域,该区域中的页无法进行任何形式的共享。 + * + */ +#define REGION_PRIVATE 0x0 + +/** + * @brief 读共享区域,该区域中的页可以被两个进程之间读共享,但任何写操作须应用Copy-On-Write + * + */ +#define REGION_RSHARED 0x1 + +/** + * @brief 写共享区域,该区域中的页可以被两个进程之间读共享,任何的写操作无需执行Copy-On-Write + * + */ +#define REGION_WSHARED 0x2 + +#define REGION_TYPE_CODE (0) +#define REGION_TYPE_DATA (1 << 2) + +struct mm_region +{ + struct llist_header* head; + void* start; + void* end; + unsigned int attr; +}; + +#endif /* __LUNAIX_MM_H */ diff --git a/lunaix-os/includes/lunaix/mm/page.h b/lunaix-os/includes/lunaix/mm/page.h index 415ea9e..a6b3162 100644 --- a/lunaix-os/includes/lunaix/mm/page.h +++ b/lunaix-os/includes/lunaix/mm/page.h @@ -70,6 +70,7 @@ typedef unsigned long ptd_t; typedef unsigned long pt_t; typedef unsigned int pt_attr; +typedef uint32_t x86_pte_t; /** * @brief 虚拟映射属性 @@ -82,14 +83,23 @@ typedef struct { uintptr_t pa; // 映射的flags uint16_t flags; + // PTE地址 + x86_pte_t *pte; } v_mapping; -typedef uint32_t x86_pte_t; typedef struct { x86_pte_t entry[PG_MAX_ENTRIES]; } __attribute__((packed)) x86_page_table; +extern void __pg_mount_point; + +/* 三个页挂载点: 用于临时创建&编辑页表 */ + +#define PG_MOUNT_1 (&__pg_mount_point) +#define PG_MOUNT_2 (&__pg_mount_point + 0x1000) +#define PG_MOUNT_3 (&__pg_mount_point + 0x2000) + #endif /* __LUNAIX_PAGE_H */ diff --git a/lunaix-os/includes/lunaix/mm/pmm.h b/lunaix-os/includes/lunaix/mm/pmm.h index 36396df..d45af82 100644 --- a/lunaix-os/includes/lunaix/mm/pmm.h +++ b/lunaix-os/includes/lunaix/mm/pmm.h @@ -4,9 +4,21 @@ #include #include +#include #define PM_PAGE_SIZE 4096 -#define PM_BMP_MAX_SIZE (128 * 1024) +#define PM_BMP_MAX_SIZE (1024 * 1024) + + +#define PP_FGPERSIST 0x1 + +typedef uint32_t pp_attr_t; + +struct pp_struct { + pid_t owner; + uint32_t ref_counts; + pp_attr_t attr; +}; /** * @brief 标注物理页为可使用 @@ -20,7 +32,7 @@ void pmm_mark_page_free(uintptr_t ppn); * * @param ppn */ -void pmm_mark_page_occupied(uintptr_t ppn); +void pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr); /** * @brief 标注多个连续的物理页为可用 @@ -36,14 +48,25 @@ void pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count); * @param start_ppn 起始PPN * @param page_count 数量 */ -void pmm_mark_chunk_occupied(uintptr_t start_ppn, size_t page_count); +void pmm_mark_chunk_occupied(pid_t owner, uintptr_t start_ppn, size_t page_count, pp_attr_t attr); /** * @brief 分配一个可用的物理页 * * @return void* 可用的页地址,否则为 NULL */ -void* pmm_alloc_page(); +void* pmm_alloc_page(pid_t owner, pp_attr_t attr); + +/** + * @brief 分配一个连续的物理内存区域 + * + * @param owner + * @param num_pages 区域大小,单位为页 + * @param attr + * @return void* + */ +void* +pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr); /** * @brief 初始化物理内存管理器 @@ -52,6 +75,7 @@ void* pmm_alloc_page(); */ void pmm_init(uintptr_t mem_upper_lim); +struct pp_struct* pmm_query(void* pa); /** * @brief 释放一个已分配的物理页,假若页地址不存在,则无操作。 @@ -59,7 +83,9 @@ void pmm_init(uintptr_t mem_upper_lim); * @param page 页地址 * @return 是否成功 */ -int pmm_free_page(void* page); +int pmm_free_page(pid_t owner, void* page); + +int pmm_ref_page(pid_t owner, void* page); #endif /* __LUNAIX_PMM_H */ diff --git a/lunaix-os/includes/lunaix/mm/vmm.h b/lunaix-os/includes/lunaix/mm/vmm.h index 3e124fc..682f8d0 100644 --- a/lunaix-os/includes/lunaix/mm/vmm.h +++ b/lunaix-os/includes/lunaix/mm/vmm.h @@ -1,8 +1,10 @@ #ifndef __LUNAIX_VMM_H #define __LUNAIX_VMM_H #include +#include #include #include +#include // Virtual memory manager /** @@ -31,7 +33,7 @@ vmm_init_pd(); * @return 虚拟页地址,如不成功,则为 NULL */ void* -vmm_map_page(void* va, void* pa, pt_attr tattr); +vmm_map_page(pid_t pid, void* va, void* pa, pt_attr tattr); /** * @brief 建立一个映射关系,映射指定的物理页地址至虚拟页地址。如果指定的虚拟页地址已被占用, @@ -44,16 +46,16 @@ vmm_map_page(void* va, void* pa, pt_attr tattr); * @return 虚拟页地址 */ void* -vmm_fmap_page(void* va, void* pa, pt_attr tattr); +vmm_fmap_page(pid_t pid, void* va, void* pa, pt_attr tattr); /** * @brief 尝试为一个虚拟页地址创建一个可用的物理页映射 * * @param va 虚拟页地址 - * @return 物理页地址,如不成功,则为 NULL + * @return 虚拟页地址,如不成功,则为 NULL */ void* -vmm_alloc_page(void* va, pt_attr tattr); +vmm_alloc_page(pid_t pid, void* va, void** pa, pt_attr tattr, pp_attr_t pattr); /** @@ -65,7 +67,7 @@ vmm_alloc_page(void* va, pt_attr tattr); * @return int 是否成功 */ int -vmm_alloc_pages(void* va, size_t sz, pt_attr tattr); +vmm_alloc_pages(pid_t pid, void* va, size_t sz, pt_attr tattr, pp_attr_t pattr); /** * @brief 设置一个映射,如果映射已存在,则忽略。 @@ -74,8 +76,16 @@ vmm_alloc_pages(void* va, size_t sz, pt_attr tattr); * @param pa * @param attr */ +int +vmm_set_mapping(pid_t pid, void* va, void* pa, pt_attr attr); + +/** + * @brief 删除并释放一个映射 + * + * @param vpn + */ void -vmm_set_mapping(void* va, void* pa, pt_attr attr); +vmm_unmap_page(pid_t pid, void* va); /** * @brief 删除一个映射 @@ -83,7 +93,7 @@ vmm_set_mapping(void* va, void* pa, pt_attr attr); * @param vpn */ void -vmm_unmap_page(void* va); +vmm_unset_mapping(void* va); /** * @brief 将虚拟地址翻译为其对应的物理映射 @@ -103,4 +113,12 @@ vmm_v2p(void* va); v_mapping vmm_lookup(void* va); +/** + * @brief (COW) 为虚拟页创建副本。 + * + * @return void* 包含虚拟页副本的物理页地址。 + * + */ +void* vmm_dup_page(void* va); + #endif /* __LUNAIX_VMM_H */ diff --git a/lunaix-os/includes/lunaix/proc.h b/lunaix-os/includes/lunaix/proc.h new file mode 100644 index 0000000..f22fd68 --- /dev/null +++ b/lunaix-os/includes/lunaix/proc.h @@ -0,0 +1,10 @@ +#ifndef __LUNAIX_SYS_H +#define __LUNAIX_SYS_H + +#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 new file mode 100644 index 0000000..25b1d60 --- /dev/null +++ b/lunaix-os/includes/lunaix/process.h @@ -0,0 +1,73 @@ +#ifndef __LUNAIX_PROCESS_H +#define __LUNAIX_PROCESS_H + +#include +#include +#include +#include +#include + +// 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。 +#define KERNEL_PID -1 + +#define PROC_CREATED 0 +#define PROC_RUNNING 1 +#define PROC_STOPPED 2 +#define PROC_TERMNAT 3 +#define PROC_DESTROY 4 + + +struct proc_mm { + heap_context_t k_heap; + heap_context_t u_heap; + struct mm_region* region; +}; + +struct proc_info { + pid_t pid; + pid_t 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; +}; + +extern struct proc_info* __current; + + +pid_t alloc_pid(); + +/** + * @brief 向系统发布一个进程,使其可以被调度。 + * + * @param process + */ +void push_process(struct proc_info* process); + +void destroy_process(pid_t pid); + +/** + * @brief 复制当前进程(LunaixOS的类 fork (unix) 实现) + * + */ +void dup_proc(); + +/** + * @brief 创建新进程(LunaixOS的类 CreateProcess (Windows) 实现) + * + */ +void new_proc(); + +/** + * @brief 终止(退出)当前进程 + * + */ +void terminate_process(int exit_code); + +struct proc_info* get_process(pid_t pid); + +#endif /* __LUNAIX_PROCESS_H */ diff --git a/lunaix-os/includes/lunaix/sched.h b/lunaix-os/includes/lunaix/sched.h new file mode 100644 index 0000000..a0778a3 --- /dev/null +++ b/lunaix-os/includes/lunaix/sched.h @@ -0,0 +1,15 @@ +#ifndef __LUNAIX_SCHEDULER_H +#define __LUNAIX_SCHEDULER_H + +#define SCHED_TIME_SLICE 1000 + +struct scheduler { + struct proc_info* _procs; + int procs_index; + unsigned int ptable_len; +}; + +void sched_init(); +void schedule(); + +#endif /* __LUNAIX_SCHEDULER_H */ diff --git a/lunaix-os/includes/lunaix/status.h b/lunaix-os/includes/lunaix/status.h new file mode 100644 index 0000000..44fa2f9 --- /dev/null +++ b/lunaix-os/includes/lunaix/status.h @@ -0,0 +1,10 @@ +#ifndef __LUNAIX_CODE_H +#define __LUNAIX_CODE_H + +#define LXPROCFULL -(1) +#define LXHEAPFULL -(2) +#define LXINVLDPTR -(2) +#define LXOUTOFMEM -(3) +#define LXINVLDPID -(4) + +#endif /* __LUNAIX_CODE_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h new file mode 100644 index 0000000..d933584 --- /dev/null +++ b/lunaix-os/includes/lunaix/syscall.h @@ -0,0 +1,62 @@ +#ifndef __LUNAIX_SYSCALL_H +#define __LUNAIX_SYSCALL_H + +#include + +#define __SYSCALL_fork 0x1 +#define __SYSCALL_yield 0x2 +#define __SYSCALL_exit 0x3 +#define __SYSCALL_sbrk 0x4 +#define __SYSCALL_brk 0x5 + +#define __SYSCALL_MAX 0x100 + +#ifndef __ASM__ +void syscall_install(); + +static void* syscall(unsigned int callcode) { + asm volatile( + "int %0" + ::"i"(LUNAIX_SYS_CALL), "D"(callcode) + :"eax" + ); +} + +#define ___DOINT33(callcode, rettype)\ + int v; \ + asm volatile ( \ + "int %1\n" \ + :"=a"(v) \ + :"i"(LUNAIX_SYS_CALL), "a"(callcode)); \ + return (rettype)v; \ + +#define __LXSYSCALL(rettype, name) \ + rettype name () { \ + ___DOINT33(__SYSCALL_##name, rettype) \ + } + +#define __LXSYSCALL1(rettype, name, t1, p1) \ + rettype name (t1 p1) { \ + asm (""::"b"(p1)); \ + ___DOINT33(__SYSCALL_##name, rettype) \ + } + +#define __LXSYSCALL2(rettype, name, t1, p1, t2, p2) \ + rettype name (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) { \ + 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) { \ + asm ("\n"::"b"(p1), "c"(p2), "d"(p3), "D"(p4)); \ + ___DOINT33(__SYSCALL_##name, rettype) \ + } +#endif +#endif /* __LUNAIX_SYSCALL_H */ diff --git a/lunaix-os/includes/lunaix/types.h b/lunaix-os/includes/lunaix/types.h new file mode 100644 index 0000000..ed59da3 --- /dev/null +++ b/lunaix-os/includes/lunaix/types.h @@ -0,0 +1,8 @@ +#ifndef __LUNAIX_TYPES_H +#define __LUNAIX_TYPES_H + +#include + +typedef int32_t pid_t; + +#endif /* __LUNAIX_TYPES_H */ diff --git a/lunaix-os/kernel/asm/x86/gdt.c b/lunaix-os/kernel/asm/x86/gdt.c index 41c597e..1bd1c00 100644 --- a/lunaix-os/kernel/asm/x86/gdt.c +++ b/lunaix-os/kernel/asm/x86/gdt.c @@ -1,7 +1,8 @@ #include +#include #include -#define GDT_ENTRY 5 +#define GDT_ENTRY 6 uint64_t _gdt[GDT_ENTRY]; uint16_t _gdt_limit = sizeof(_gdt) - 1; @@ -12,7 +13,8 @@ void _set_gdt_entry(uint32_t index, uint32_t base, uint32_t limit, uint32_t flag _gdt[index] |= SEG_BASE_L(base) | SEG_LIM_L(limit); } - +extern struct x86_tss _tss; + void _init_gdt() { _set_gdt_entry(0, 0, 0, 0); @@ -20,4 +22,5 @@ _init_gdt() { _set_gdt_entry(2, 0, 0xfffff, SEG_R0_DATA); _set_gdt_entry(3, 0, 0xfffff, SEG_R3_CODE); _set_gdt_entry(4, 0, 0xfffff, SEG_R3_DATA); + _set_gdt_entry(5, &_tss, sizeof(struct x86_tss) - 1, SEG_TSS); } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c index e194d87..9b2f0c6 100644 --- a/lunaix-os/kernel/asm/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -32,4 +32,5 @@ _init_idt() { // system defined interrupts _set_idt_entry(LUNAIX_SYS_PANIC, 0x08, _asm_isr32, 0); + _set_idt_entry(LUNAIX_SYS_CALL, 0x08, _asm_isr33, 0); } \ 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 f05c3b8..471a8e6 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -1,5 +1,6 @@ #define __ASM__ #include +// #define __ASM_INTR_DIAGNOSIS .macro isr_template vector, no_error_code=1 .global _asm_isr\vector @@ -12,12 +13,20 @@ jmp interrupt_wrapper .endm +#ifdef __ASM_INTR_DIAGNOSIS +.section .bss + .global debug_resv + debug_resv: + .skip 16 +#endif + .section .text 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 LUNAIX_SYS_PANIC + isr_template LUNAIX_SYS_CALL isr_template APIC_ERROR_IV isr_template APIC_LINT0_IV @@ -28,6 +37,7 @@ interrupt_wrapper: pushl %esp + pushl %esi pushl %ebp pushl %edi @@ -42,6 +52,9 @@ movl %eax, (%esp) call intr_handler + + .global soft_iret + soft_iret: popl %esp popl %eax @@ -55,4 +68,15 @@ addl $8, %esp - iret \ No newline at end of file +#ifdef __ASM_INTR_DIAGNOSIS + cmpl $0, (%esp) + jz 1f + iret +1: + movl $__current, %eax + movl (%esp), %ebx + movl $debug_resv, %ecx + ud2 +#else + iret +#endif diff --git a/lunaix-os/kernel/asm/x86/interrupts.c b/lunaix-os/kernel/asm/x86/interrupts.c index a7ac25a..f6b5538 100644 --- a/lunaix-os/kernel/asm/x86/interrupts.c +++ b/lunaix-os/kernel/asm/x86/interrupts.c @@ -3,6 +3,10 @@ #include #include #include +#include +#include + +LOG_MODULE("intr") static int_subscriber subscribers[256]; @@ -25,9 +29,15 @@ intr_set_fallback_handler(int_subscriber subscribers) { fallback = subscribers; } + void intr_handler(isr_param* param) { + // if (param->vector == LUNAIX_SYS_CALL) { + // kprintf(KDEBUG "%p", param->registers.esp); + // } + __current->intr_ctx = *param; + if (param->vector <= 255) { int_subscriber subscriber = subscribers[param->vector]; if (subscriber) { @@ -48,10 +58,18 @@ intr_handler(isr_param* param) param->eip); done: + + // if (__current->state != PROC_RUNNING) { + // schedule(); + // } + // for all external interrupts except the spurious interrupt // this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5 if (param->vector >= EX_INTERRUPT_BEGIN && param->vector != APIC_SPIV_IV) { apic_done_servicing(); } + + *param = __current->intr_ctx; + return; } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/intr_routines.c b/lunaix-os/kernel/asm/x86/intr_routines.c index 8660df6..f68b2ce 100644 --- a/lunaix-os/kernel/asm/x86/intr_routines.c +++ b/lunaix-os/kernel/asm/x86/intr_routines.c @@ -7,8 +7,12 @@ #include +LOG_MODULE("INTR") -static void +extern void +intr_routine_page_fault (const isr_param* param); + +void __print_panic_msg(const char* msg, const isr_param* param) { kprint_panic(" INT %u: (%x) [%p: %p] %s", @@ -33,20 +37,6 @@ intr_routine_general_protection (const isr_param* param) spin(); } -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); - } else { - char buf[32]; - sprintf(buf, "Page fault on %p", pg_fault_ptr); - __print_panic_msg(buf, param); - } - spin(); -} - void intr_routine_sys_panic (const isr_param* param) { diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c new file mode 100644 index 0000000..c5ec07f --- /dev/null +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +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; + } + + __print_panic_msg("Page fault", param); + +done: + while(1); +} \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/prologue.S b/lunaix-os/kernel/asm/x86/prologue.S index 38716f5..ddd2652 100644 --- a/lunaix-os/kernel/asm/x86/prologue.S +++ b/lunaix-os/kernel/asm/x86/prologue.S @@ -1,5 +1,8 @@ /* 高半核入口点 - 0xC0000000 */ +#define __ASM__ +#include + .section .text .global hhk_entry_ hhk_entry_: @@ -24,7 +27,7 @@ lgdt (%esp) /* 更新段寄存器 */ - movw $0x10, %cx + movw $KDATA_SEG, %cx movw %cx, %es movw %cx, %ds movw %cx, %fs @@ -32,7 +35,7 @@ movw %cx, %ss /* 更新 CS:EIP */ - pushw $0x08 + pushw $KCODE_SEG pushl $_after_gdt retf @@ -50,23 +53,16 @@ movw %ax, (%esp) lidt (%esp) + /* 加载TSS段选择器 */ + movw $TSS_SEG, %ax + ltr %ax + addl $6, %esp call _kernel_init - /* - 加载新的栈指针,位于0xffbfffff,但因为16字节对齐的需求,低四位清零。 - 为什么不是0xffffffff? 因为0xffc00000 - 0xffffffff 这4MiB的空间用于 - 对页表与页目录的循环映射。 - */ - mov $0xffbffff0, %esp - - call _kernel_post_init - - /* 进入内核 */ - call _kernel_main + /* _kernel_init 永不返回 */ - cli - j_: + 1: hlt - jmp j_ \ No newline at end of file + jmp 1b \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S new file mode 100644 index 0000000..2ea22d4 --- /dev/null +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -0,0 +1,48 @@ +#define __ASM__ +#include + +.section .data + /* + 注意,这里的顺序非常重要。每个系统调用在这个地址表里的索引等于其调用号。 + */ + syscall_table: + .dc.l 0 + .dc.l dup_proc + .dc.l schedule + .dc.l terminate_process + .dc.l _syscall_sbrk + .dc.l _syscall_brk + +.global syscall_hndlr + +.section .text + syscall_hndlr: + pushl %ebp + movl %esp, %ebp + addl $0x8, %ebp + movl (%ebp), %ebp + + movl (%ebp), %eax + cmpl $__SYSCALL_MAX, %eax + jb 1f + neg %eax + popl %ebp + ret + 1: + pushl 24(%ebp) /* esi - #6 arg */ + pushl 20(%ebp) /* ebp - #5 arg */ + pushl 16(%ebp) /* edi - #4 arg */ + pushl 12(%ebp) /* edx - #3 arg */ + pushl 8(%ebp) /* ecx - #2 arg */ + pushl 4(%ebp) /* ebx - #1 arg */ + shll $2, %eax + addl $syscall_table, %eax + + call (%eax) + + addl $24, %esp + + popl %ebp + ret + + diff --git a/lunaix-os/kernel/asm/x86/tss.c b/lunaix-os/kernel/asm/x86/tss.c new file mode 100644 index 0000000..8946107 --- /dev/null +++ b/lunaix-os/kernel/asm/x86/tss.c @@ -0,0 +1,13 @@ +#include +#include + +struct x86_tss _tss = { + .link = 0, + .esp0 = KSTACK_START, + .ss0 = KDATA_SEG +}; + +void tss_update(uint32_t ss0, uint32_t esp0) { + _tss.esp0 = esp0; + _tss.ss0 = ss0; +} \ No newline at end of file diff --git a/lunaix-os/kernel/ds/semaphore.c b/lunaix-os/kernel/ds/semaphore.c index 21d0e33..7b059a6 100644 --- a/lunaix-os/kernel/ds/semaphore.c +++ b/lunaix-os/kernel/ds/semaphore.c @@ -1,4 +1,5 @@ #include +#include void sem_init(struct sem_t *sem, unsigned int initial) { sem->counter = ATOMIC_VAR_INIT(initial); @@ -6,7 +7,7 @@ void sem_init(struct sem_t *sem, unsigned int initial) { void sem_wait(struct sem_t *sem) { while (!atomic_load(&sem->counter)) { - // TODO: yield the cpu + schedule(); } atomic_fetch_sub(&sem->counter, 1); } diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 74e3534..bbd505d 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include @@ -21,6 +24,7 @@ #include #include +#include #include #include @@ -30,24 +34,23 @@ extern uint8_t __kernel_start; extern uint8_t __kernel_end; extern uint8_t __init_hhk_end; +#define PP_KERN_SHARED (PP_FGSHARED | PP_TKERN) // Set remotely by kernel/asm/x86/prologue.S multiboot_info_t* _k_init_mb_info; -LOG_MODULE("INIT"); +LOG_MODULE("BOOT"); -void -setup_memory(multiboot_memory_map_t* map, size_t map_size); +extern void _lxinit_main(); +void spawn_lxinit(); +void _kernel_post_init(); void -setup_kernel_runtime(); +setup_memory(multiboot_memory_map_t* map, size_t map_size); void lock_reserved_memory(); -void -unlock_reserved_memory(); - void _kernel_pre_init() { _init_idt(); @@ -71,18 +74,62 @@ _kernel_init() { setup_memory((multiboot_memory_map_t*)_k_init_mb_info->mmap_addr, map_size); - setup_kernel_runtime(); + // 为内核创建一个专属栈空间。 + for (size_t i = 0; i < (KSTACK_SIZE >> PG_SIZE_BITS); i++) { + vmm_alloc_page(KERNEL_PID, (void*)(KSTACK_START + (i << PG_SIZE_BITS)), NULL, PG_PREM_RW, 0); + } + kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n", KSTACK_SIZE>>PG_SIZE_BITS, KSTACK_START); + + sched_init(); + + spawn_lxinit(); +} + +/** + * @brief 创建并运行init进程 + * + */ +void spawn_lxinit() { + struct proc_info kinit; + uint32_t* kstack = (uint32_t*)KSTACK_TOP - 4 * 5; + + memset(&kinit, 0, sizeof(kinit)); + kinit.page_table = (void*) cpu_rcr3(); + kinit.parent = -1; + kinit.pid = 1; + kinit.intr_ctx = (isr_param) { + .registers.esp = kstack, + .cs = KCODE_SEG, + .eip = (void*)_kernel_post_init, + .ss = KDATA_SEG, + .eflags = cpu_reflags() + }; + + /* + 因为schedule从设计上是需要在中断环境中执行的 + 可是我们需要在这里手动调用 schedule,从而使我们的init能够被执行。 + 所以需要模拟中断产生时的栈里内容。 + */ + kstack[2] = kinit.intr_ctx.eip; + kstack[3] = kinit.intr_ctx.cs; + kstack[4] = kinit.intr_ctx.eflags; + + push_process(&kinit); + + schedule(); } void _kernel_post_init() { + 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_unmap_page((void*)(i << PG_SIZE_BITS)); + vmm_unmap_page(KERNEL_PID, (void*)(i << PG_SIZE_BITS)); } // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射 @@ -90,12 +137,11 @@ _kernel_post_init() { acpi_init(_k_init_mb_info); uintptr_t ioapic_addr = acpi_get_context()->madt.ioapic->ioapic_addr; + pmm_mark_page_occupied(KERNEL_PID, FLOOR(__APIC_BASE_PADDR, PG_SIZE_BITS), 0); + pmm_mark_page_occupied(KERNEL_PID, FLOOR(ioapic_addr, PG_SIZE_BITS), 0); - pmm_mark_page_occupied(FLOOR(__APIC_BASE_PADDR, PG_SIZE_BITS)); - pmm_mark_page_occupied(FLOOR(ioapic_addr, PG_SIZE_BITS)); - - vmm_set_mapping(APIC_BASE_VADDR, __APIC_BASE_PADDR, PG_PREM_RW); - vmm_set_mapping(IOAPIC_BASE_VADDR, ioapic_addr, PG_PREM_RW); + vmm_set_mapping(KERNEL_PID, APIC_BASE_VADDR, __APIC_BASE_PADDR, PG_PREM_RW); + vmm_set_mapping(KERNEL_PID, IOAPIC_BASE_VADDR, ioapic_addr, PG_PREM_RW); apic_init(); ioapic_init(); @@ -103,31 +149,19 @@ _kernel_post_init() { clock_init(); ps2_kbd_init(); + syscall_install(); + for (size_t i = 256; i < hhk_init_pg_count; i++) { - vmm_unmap_page((void*)(i << PG_SIZE_BITS)); + vmm_unmap_page(KERNEL_PID, (void*)(i << PG_SIZE_BITS)); } -} -void -lock_reserved_memory() { - multiboot_memory_map_t* mmaps = _k_init_mb_info->mmap_addr; - size_t map_size = _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t); - for (unsigned int i = 0; i < map_size; i++) { - multiboot_memory_map_t mmap = mmaps[i]; - if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE) { - 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++) - { - vmm_set_mapping((pa + (j << PG_SIZE_BITS)), (pa + (j << PG_SIZE_BITS)), PG_PREM_R); - } - } + _lxinit_main(); + + spin(); } void -unlock_reserved_memory() { +lock_reserved_memory() { multiboot_memory_map_t* mmaps = _k_init_mb_info->mmap_addr; size_t map_size = _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t); for (unsigned int i = 0; i < map_size; i++) { @@ -139,7 +173,7 @@ unlock_reserved_memory() { size_t pg_num = CEIL(mmap.len_low, PG_SIZE_BITS); for (size_t j = 0; j < pg_num; j++) { - vmm_unmap_page((pa + (j << PG_SIZE_BITS))); + vmm_set_mapping(KERNEL_PID, (pa + (j << PG_SIZE_BITS)), (pa + (j << PG_SIZE_BITS)), PG_PREM_R); } } } @@ -167,19 +201,20 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) { // 将内核占据的页,包括前1MB,hhk_init 设为已占用 size_t pg_count = V2P(&__kernel_end) >> PG_SIZE_BITS; - pmm_mark_chunk_occupied(0, pg_count); + pmm_mark_chunk_occupied(KERNEL_PID, 0, pg_count, 0); kprintf(KINFO "[MM] Allocated %d pages for kernel.\n", pg_count); size_t vga_buf_pgs = VGA_BUFFER_SIZE >> PG_SIZE_BITS; // 首先,标记VGA部分为已占用 - pmm_mark_chunk_occupied(VGA_BUFFER_PADDR >> PG_SIZE_BITS, vga_buf_pgs); + pmm_mark_chunk_occupied(KERNEL_PID, VGA_BUFFER_PADDR >> PG_SIZE_BITS, vga_buf_pgs, 0); // 重映射VGA文本缓冲区(以后会变成显存,i.e., framebuffer) for (size_t i = 0; i < vga_buf_pgs; i++) { vmm_map_page( + KERNEL_PID, (void*)(VGA_BUFFER_VADDR + (i << PG_SIZE_BITS)), (void*)(VGA_BUFFER_PADDR + (i << PG_SIZE_BITS)), PG_PREM_RW @@ -190,15 +225,4 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) { tty_set_buffer((void*)VGA_BUFFER_VADDR); kprintf(KINFO "[MM] Mapped VGA to %p.\n", VGA_BUFFER_VADDR); - -} - -void -setup_kernel_runtime() { - // 为内核创建一个专属栈空间。 - for (size_t i = 0; i < (K_STACK_SIZE >> PG_SIZE_BITS); i++) { - vmm_alloc_page((void*)(K_STACK_START + (i << PG_SIZE_BITS)), PG_PREM_RW); - } - kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n", K_STACK_SIZE>>PG_SIZE_BITS, K_STACK_START); - assert_msg(kalloc_init(), "Fail to initialize heap"); } \ No newline at end of file diff --git a/lunaix-os/kernel/k_main.c b/lunaix-os/kernel/lxinit.c similarity index 75% rename from lunaix-os/kernel/k_main.c rename to lunaix-os/kernel/lxinit.c index c3819d9..7decff4 100644 --- a/lunaix-os/kernel/k_main.c +++ b/lunaix-os/kernel/lxinit.c @@ -7,18 +7,38 @@ #include #include #include -#include +#include +#include extern uint8_t __kernel_start; -LOG_MODULE("LX") +LOG_MODULE("INIT") void test_timer(void* payload); void -_kernel_main() +_lxinit_main() { + // 这里是就是LunaixOS的第一个进程了! + for (size_t i = 0; i < 10; i++) + { + pid_t pid = 0; + if (!(pid = fork())) { + while (1) + { + // kprintf(KINFO "Process %d\n", i); + tty_put_char('0'+i); + yield(); + } + } + kprintf(KINFO "Forked %d\n", pid); + } + + // FIXME: 这里fork会造成下面lxmalloc产生Heap corruption,需要实现COW和加入mutex + // fork(); + + char buf[64]; kprintf(KINFO "Hello higher half kernel world!\nWe are now running in virtual " @@ -66,6 +86,7 @@ _kernel_main() tty_sync_cursor(); } } + spin(); } diff --git a/lunaix-os/kernel/mm/cow.c b/lunaix-os/kernel/mm/cow.c new file mode 100644 index 0000000..30cead9 --- /dev/null +++ b/lunaix-os/kernel/mm/cow.c @@ -0,0 +1,16 @@ +#include + +void* vmm_dup_page(void* va) { + void* new_ppg = pmm_alloc_page(KERNEL_PID, 0); + vmm_fmap_page(KERNEL_PID, PG_MOUNT_3, new_ppg, PG_PREM_RW); + + asm volatile ( + "movl %1, %%edi\n" + "rep movsl\n" + :: "c"(1024), "r"(PG_MOUNT_3), "S"((uintptr_t)va) + : "memory", "%edi"); + + vmm_unset_mapping(PG_MOUNT_3); + + return new_ppg; +} \ No newline at end of file diff --git a/lunaix-os/kernel/mm/dmm.c b/lunaix-os/kernel/mm/dmm.c index ae89908..dee5d28 100644 --- a/lunaix-os/kernel/mm/dmm.c +++ b/lunaix-os/kernel/mm/dmm.c @@ -17,17 +17,36 @@ #include #include #include +#include #include + +int _syscall_sbrk(void* addr) { + heap_context_t* uheap = &__current->mm.u_heap; + mutex_lock(&uheap->lock); + int r = lxsbrk(uheap, addr); + mutex_unlock(&uheap->lock); + return r; +} + +void* _syscall_brk(size_t size) { + heap_context_t* uheap = &__current->mm.u_heap; + mutex_lock(&uheap->lock); + void* r = lxbrk(uheap, size); + mutex_unlock(&uheap->lock); + return r; +} + int dmm_init(heap_context_t* heap) { assert((uintptr_t)heap->start % BOUNDARY == 0); heap->brk = heap->start; + mutex_init(&heap->lock); - return vmm_alloc_page(heap->brk, PG_PREM_RW) != NULL; + return vmm_alloc_page(__current->pid, heap->brk, NULL, PG_PREM_RW, 0) != NULL; } int @@ -51,17 +70,16 @@ lxbrk(heap_context_t* heap, size_t size) // any invalid situations if (next >= heap->max_addr || next < current_brk) { - return NULL; + __current->k_status = LXINVLDPTR; } uintptr_t diff = PG_ALIGN(next) - PG_ALIGN(current_brk); if (diff) { // if next do require new pages to be allocated - if (!vmm_alloc_pages((void*)(PG_ALIGN(current_brk) + PG_SIZE), + if (!vmm_alloc_pages(__current->pid, (void*)(PG_ALIGN(current_brk) + PG_SIZE), diff, - PG_PREM_RW)) { - // for debugging - assert_msg(0, "unable to brk"); + PG_PREM_RW, 0)) { + __current->k_status = LXHEAPFULL; return NULL; } } diff --git a/lunaix-os/kernel/mm/kalloc.c b/lunaix-os/kernel/mm/kalloc.c index 16c1d82..91905b4 100644 --- a/lunaix-os/kernel/mm/kalloc.c +++ b/lunaix-os/kernel/mm/kalloc.c @@ -23,9 +23,6 @@ extern uint8_t __kernel_heap_start; -// FIXME: This should go to PCB once we're started to support multitasking -static heap_context_t __kalloc_kheap; - void* lx_malloc_internal(heap_context_t* heap, size_t size); @@ -62,24 +59,25 @@ lx_grow_heap(heap_context_t* heap, size_t sz); int kalloc_init() { - __kalloc_kheap.start = &__kernel_heap_start; - __kalloc_kheap.brk = NULL; - __kalloc_kheap.max_addr = (void*)K_STACK_START; + heap_context_t* kheap = &__current->mm.k_heap; + kheap->start = &__kernel_heap_start; + kheap->brk = NULL; + kheap->max_addr = (void*)KSTACK_START; - if (!dmm_init(&__kalloc_kheap)) { + if (!dmm_init(kheap)) { return 0; } - SW(__kalloc_kheap.start, PACK(4, M_ALLOCATED)); - SW(__kalloc_kheap.start + WSIZE, PACK(0, M_ALLOCATED)); - __kalloc_kheap.brk += WSIZE; + SW(kheap->start, PACK(4, M_ALLOCATED)); + SW(kheap->start + WSIZE, PACK(0, M_ALLOCATED)); + kheap->brk += WSIZE; - return lx_grow_heap(&__kalloc_kheap, HEAP_INIT_SIZE) != NULL; + return lx_grow_heap(kheap, HEAP_INIT_SIZE) != NULL; } void* lxmalloc(size_t size) { - return lx_malloc_internal(&__kalloc_kheap, size); + return lx_malloc_internal(&__current->mm.k_heap, size); } void* diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c index dcc70b0..efb9dc8 100644 --- a/lunaix-os/kernel/mm/pmm.c +++ b/lunaix-os/kernel/mm/pmm.c @@ -1,74 +1,48 @@ #include #include +#include -#define MARK_PG_AUX_VAR(ppn) \ - uint32_t group = ppn / 8; \ - uint32_t msk = (0x80U >> (ppn % 8)); \ - -#define MARK_CHUNK_AUX_VAR(start_ppn, page_count) \ - uint32_t group = start_ppn / 8; \ - uint32_t offset = start_ppn % 8; \ - uint32_t group_count = (page_count + offset) / 8; \ - uint32_t remainder = (page_count + offset) % 8; \ - uint32_t leading_shifts = \ - (page_count + offset) < 8 ? page_count : 8 - offset; - -static uint8_t pm_bitmap[PM_BMP_MAX_SIZE]; +// This is a very large array... +static struct pp_struct pm_table[PM_BMP_MAX_SIZE]; static uintptr_t max_pg; -// ... |xxxx xxxx | -// ... |-->| void pmm_mark_page_free(uintptr_t ppn) { - MARK_PG_AUX_VAR(ppn) - pm_bitmap[group] = pm_bitmap[group] & ~msk; + pm_table[ppn].ref_counts = 0; } void -pmm_mark_page_occupied(uintptr_t ppn) +pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr) { - MARK_PG_AUX_VAR(ppn) - pm_bitmap[group] = pm_bitmap[group] | msk; + pm_table[ppn] = (struct pp_struct) { + .owner = owner, + .ref_counts = 1, + .attr = attr + }; } void pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count) { - MARK_CHUNK_AUX_VAR(start_ppn, page_count) - - // nasty bit level hacks but it reduce # of iterations. - - pm_bitmap[group] &= ~(((1U << leading_shifts) - 1) << (8 - offset - leading_shifts)); - - group++; - - // prevent unsigned overflow - for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) { - pm_bitmap[group] = 0; + for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) + { + pm_table[i].ref_counts = 0; } - - pm_bitmap[group] &= - ~(((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder)); } void -pmm_mark_chunk_occupied(uint32_t start_ppn, size_t page_count) +pmm_mark_chunk_occupied(pid_t owner, uint32_t start_ppn, size_t page_count, pp_attr_t attr) { - MARK_CHUNK_AUX_VAR(start_ppn, page_count) - - pm_bitmap[group] |= (((1U << leading_shifts) - 1) << (8 - offset - leading_shifts)); - - group++; - - // prevent unsigned overflow - for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) { - pm_bitmap[group] = 0xFFU; + for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) + { + pm_table[i] = (struct pp_struct) { + .owner = owner, + .ref_counts = 1, + .attr = attr + }; } - - pm_bitmap[group] |= - (((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder)); } // 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。 @@ -85,32 +59,54 @@ pmm_init(uintptr_t mem_upper_lim) // mark all as occupied for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) { - pm_bitmap[i] = 0xFFU; + pm_table[i] = (struct pp_struct) { + .owner = 0, + .attr = 0, + .ref_counts = 1 + }; + } +} + +void* +pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr) { + size_t p1 = 0; + size_t p2 = 0; + + while (p2 < max_pg && p2 - p1 < num_pages) + { + (!(&pm_table[p2])->ref_counts) ? (p2++) : (p1 = p2); } + + if (p2 < max_pg) { + return NULL; + } + + pmm_mark_chunk_occupied(owner, p1, num_pages, attr); + + return p1 << 12; } void* -pmm_alloc_page() +pmm_alloc_page(pid_t owner, pp_attr_t attr) { // Next fit approach. Maximize the throughput! uintptr_t good_page_found = (uintptr_t)NULL; size_t old_pg_ptr = pg_lookup_ptr; size_t upper_lim = max_pg; - uint8_t chunk = 0; + struct pp_struct* pm; while (!good_page_found && pg_lookup_ptr < upper_lim) { - chunk = pm_bitmap[pg_lookup_ptr >> 3]; + pm = &pm_table[pg_lookup_ptr]; // skip the fully occupied chunk, reduce # of iterations - if (chunk != 0xFFU) { - for (size_t i = pg_lookup_ptr % 8; i < 8; i++, pg_lookup_ptr++) { - if (!(chunk & (0x80U >> i))) { - pmm_mark_page_occupied(pg_lookup_ptr); - good_page_found = pg_lookup_ptr << 12; - break; - } - } + if (!pm->ref_counts) { + *pm = (struct pp_struct) { + .attr = attr, + .owner = owner, + .ref_counts = 1 + }; + good_page_found = pg_lookup_ptr << 12; } else { - pg_lookup_ptr += 8; + pg_lookup_ptr++; // We've searched the interval [old_pg_ptr, max_pg) but failed // may be chances in [1, old_pg_ptr) ? @@ -122,18 +118,54 @@ pmm_alloc_page() } } } + if (!good_page_found) { + __current->k_status = LXOUTOFMEM; + } return (void*)good_page_found; } int -pmm_free_page(void* page) +pmm_free_page(pid_t owner, void* page) { - // XXX: Add kernel reserved memory page check or simply ownership check? - uint32_t pg = (uintptr_t)page >> 12; - if (pg && pg < max_pg) - { - pmm_mark_page_free(pg); + struct pp_struct* pm = &pm_table[(intptr_t)page >> 12]; + + // Oops, double free! + if (!(pm->ref_counts)) { + return 0; + } + + // 检查权限,保证:1) 用户只能释放用户页; 2) 内核可释放所有页。 + if ((pm->owner & owner) == pm->owner) { + pm->ref_counts--; return 1; } return 0; +} + +int pmm_ref_page(pid_t owner, void* page) { + (void*) owner; // TODO: do smth with owner + + uint32_t ppn = (uintptr_t)page >> 12; + + if (ppn >= PM_BMP_MAX_SIZE) { + return 0; + } + + struct pp_struct* pm = &pm_table[ppn]; + if (!pm->ref_counts) { + return 0; + } + + pm->ref_counts++; + return 1; +} + +struct pp_struct* pmm_query(void* pa) { + uint32_t ppn = (uintptr_t)pa >> 12; + + if (ppn >= PM_BMP_MAX_SIZE) { + return NULL; + } + + return &pm_table[ppn]; } \ No newline at end of file diff --git a/lunaix-os/kernel/mm/vmm.c b/lunaix-os/kernel/mm/vmm.c index 0aa09b8..f791cc3 100644 --- a/lunaix-os/kernel/mm/vmm.c +++ b/lunaix-os/kernel/mm/vmm.c @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include @@ -16,7 +14,7 @@ vmm_init() x86_page_table* vmm_init_pd() { - x86_page_table* dir = (x86_page_table*)pmm_alloc_page(); + x86_page_table* dir = (x86_page_table*)pmm_alloc_page(KERNEL_PID, PP_FGPERSIST); for (size_t i = 0; i < PG_MAX_ENTRIES; i++) { dir->entry[i] = PTE_NULL; } @@ -28,7 +26,8 @@ vmm_init_pd() } int -__vmm_map_internal(uint32_t l1_inx, +__vmm_map_internal(pid_t pid, + uint32_t l1_inx, uint32_t l2_inx, uintptr_t pa, pt_attr attr, @@ -41,14 +40,15 @@ __vmm_map_internal(uint32_t l1_inx, assert(attr <= 128); if (!l1pt->entry[l1_inx]) { - x86_page_table* new_l1pt_pa = pmm_alloc_page(); + x86_page_table* new_l1pt_pa = pmm_alloc_page(pid, PP_FGPERSIST); // 物理内存已满! if (!new_l1pt_pa) { return 0; } - l1pt->entry[l1_inx] = NEW_L1_ENTRY(attr, new_l1pt_pa); + // This must be writable + l1pt->entry[l1_inx] = NEW_L1_ENTRY(attr | PG_WRITE, new_l1pt_pa); memset((void*)L2_VADDR(l1_inx), 0, PG_SIZE); } @@ -57,9 +57,11 @@ __vmm_map_internal(uint32_t l1_inx, if (!forced) { return 0; } - if (HAS_FLAGS(l2pte, PG_PRESENT)) { - assert_msg(pmm_free_page(GET_PG_ADDR(l2pte)), "fail to release physical page"); - } + } + + if ((HAS_FLAGS(attr, PG_PRESENT))) { + // add one on reference count, regardless of existence. + pmm_ref_page(pid, pa); } l2pt->entry[l2_inx] = NEW_L2_ENTRY(attr, pa); @@ -68,7 +70,7 @@ __vmm_map_internal(uint32_t l1_inx, } void* -vmm_map_page(void* va, void* pa, pt_attr tattr) +vmm_map_page(pid_t pid, void* va, void* pa, pt_attr tattr) { // 显然,对空指针进行映射没有意义。 if (!pa || !va) { @@ -92,8 +94,7 @@ vmm_map_page(void* va, void* pa, pt_attr tattr) l2pt = (x86_page_table*)L2_VADDR(l1_index); } // 页表有空位,只需要开辟一个新的 PTE (Level 2) - if (l2pt && !l2pt->entry[l2_index]) { - l2pt->entry[l2_index] = NEW_L2_ENTRY(tattr, pa); + if (__vmm_map_internal(pid, l1_index, l2_index, pa, tattr, false)) { return (void*)V_ADDR(l1_index, l2_index, PG_OFFSET(va)); } l2_index++; @@ -104,7 +105,7 @@ vmm_map_page(void* va, void* pa, pt_attr tattr) return NULL; } - if (!__vmm_map_internal(l1_index, l2_index, (uintptr_t)pa, tattr, false)) { + if (!__vmm_map_internal(pid, l1_index, l2_index, (uintptr_t)pa, tattr, false)) { return NULL; } @@ -112,7 +113,7 @@ vmm_map_page(void* va, void* pa, pt_attr tattr) } void* -vmm_fmap_page(void* va, void* pa, pt_attr tattr) +vmm_fmap_page(pid_t pid, void* va, void* pa, pt_attr tattr) { if (!pa || !va) { return NULL; @@ -123,42 +124,44 @@ vmm_fmap_page(void* va, void* pa, pt_attr tattr) uint32_t l1_index = L1_INDEX(va); uint32_t l2_index = L2_INDEX(va); - if (!__vmm_map_internal(l1_index, l2_index, (uintptr_t)pa, tattr, true)) { + if (!__vmm_map_internal(pid, l1_index, l2_index, (uintptr_t)pa, tattr, true)) { return NULL; } cpu_invplg(va); - return (void*)V_ADDR(l1_index, l2_index, PG_OFFSET(va)); + return va; } void* -vmm_alloc_page(void* vpn, pt_attr tattr) +vmm_alloc_page(pid_t pid, void* vpn, void** pa, pt_attr tattr, pp_attr_t pattr) { - void* pp = pmm_alloc_page(); - void* result = vmm_map_page(vpn, pp, tattr); + void* pp = pmm_alloc_page(pid, pattr); + void* result = vmm_map_page(pid, vpn, pp, tattr); if (!result) { - pmm_free_page(pp); + pmm_free_page(pp, pid); } + pa ? (*pa = pp) : 0; return result; } int -vmm_alloc_pages(void* va, size_t sz, pt_attr tattr) +vmm_alloc_pages(pid_t pid, void* va, size_t sz, pt_attr tattr, pp_attr_t pattr) { assert((uintptr_t)va % PG_SIZE == 0) assert(sz % PG_SIZE == 0); void* va_ = va; for (size_t i = 0; i < (sz >> PG_SIZE_BITS); i++, va_ += PG_SIZE) { - void* pp = pmm_alloc_page(); + void* pp = pmm_alloc_page(pid, pattr); uint32_t l1_index = L1_INDEX(va_); uint32_t l2_index = L2_INDEX(va_); if (!pp || !__vmm_map_internal( + pid, l1_index, l2_index, (uintptr_t)pp, tattr, false)) { // if one failed, release previous allocated pages. va_ = va; for (size_t j = 0; j < i; j++, va_ += PG_SIZE) { - vmm_unmap_page(va_); + vmm_unmap_page(pid, va_); } return false; @@ -168,8 +171,8 @@ vmm_alloc_pages(void* va, size_t sz, pt_attr tattr) return true; } -void -vmm_set_mapping(void* va, void* pa, pt_attr attr) { +int +vmm_set_mapping(pid_t pid, void* va, void* pa, pt_attr attr) { assert(((uintptr_t)va & 0xFFFU) == 0); uint32_t l1_index = L1_INDEX(va); @@ -177,15 +180,15 @@ vmm_set_mapping(void* va, void* pa, pt_attr attr) { // prevent map of recursive mapping region if (l1_index == 1023) { - return; + return 0; } - __vmm_map_internal(l1_index, l2_index, (uintptr_t)pa, attr, false); + __vmm_map_internal(pid, l1_index, l2_index, (uintptr_t)pa, attr, false); + return 1; } void -vmm_unmap_page(void* va) -{ +__vmm_unmap_internal(pid_t pid, void* va, int free_ppage) { assert(((uintptr_t)va & 0xFFFU) == 0); uint32_t l1_index = L1_INDEX(va); @@ -203,14 +206,25 @@ vmm_unmap_page(void* va) if (l1pte) { x86_page_table* l2pt = (x86_page_table*)L2_VADDR(l1_index); x86_pte_t l2pte = l2pt->entry[l2_index]; - if (IS_CACHED(l2pte)) { - pmm_free_page((void*)l2pte); + if (IS_CACHED(l2pte) && free_ppage) { + pmm_free_page(pid, (void*)l2pte); } cpu_invplg(va); l2pt->entry[l2_index] = PTE_NULL; } } +void +vmm_unset_mapping(void* va) { + __vmm_unmap_internal(0, va, false); +} + +void +vmm_unmap_page(pid_t pid, void* va) +{ + __vmm_unmap_internal(pid, va, true); +} + v_mapping vmm_lookup(void* va) { @@ -224,12 +238,13 @@ vmm_lookup(void* va) v_mapping mapping = { .flags = 0, .pa = 0, .pn = 0 }; if (l1pte) { - x86_pte_t l2pte = - ((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index]; + x86_pte_t* l2pte = + &((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index]; if (l2pte) { - mapping.flags = PG_ENTRY_FLAGS(l2pte); - mapping.pa = PG_ENTRY_ADDR(l2pte); + mapping.flags = PG_ENTRY_FLAGS(*l2pte); + mapping.pa = PG_ENTRY_ADDR(*l2pte); mapping.pn = mapping.pa >> PG_SIZE_BITS; + mapping.pte = l2pte; } } diff --git a/lunaix-os/kernel/peripheral/ps2kbd.c b/lunaix-os/kernel/peripheral/ps2kbd.c index 24c9a1e..ece9eab 100644 --- a/lunaix-os/kernel/peripheral/ps2kbd.c +++ b/lunaix-os/kernel/peripheral/ps2kbd.c @@ -72,7 +72,7 @@ static kbd_keycode_t scancode_set2_shift[] = { #define KBD_STATE_CMDPROCS 0x40 #define KBD_ENABLE_SPIRQ_FIX -//#define KBD_DBGLOG +// #define KBD_DBGLOG void intr_ps2_kbd_handler(const isr_param* param); static struct kdb_keyinfo_pkt* ps2_keybuffer_next_write(); diff --git a/lunaix-os/kernel/process.c b/lunaix-os/kernel/process.c new file mode 100644 index 0000000..be7d423 --- /dev/null +++ b/lunaix-os/kernel/process.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +LOG_MODULE("PROC") + +void dup_proc() { + pid_t pid = alloc_pid(); + + void* ptd_pp = pmm_alloc_page(pid, PP_FGPERSIST); + x86_page_table* ptd = vmm_fmap_page(pid, PG_MOUNT_1, ptd_pp, PG_PREM_RW); + x86_page_table* pptd = (x86_page_table*) L1_BASE_VADDR; + + for (size_t i = 0; i < PG_MAX_ENTRIES - 1; i++) + { + x86_pte_t ptde = pptd->entry[i]; + if (!ptde || !(ptde & PG_PRESENT)) { + ptd->entry[i] = ptde; + continue; + } + + x86_page_table* ppt = (x86_page_table*) L2_VADDR(i); + void* pt_pp = pmm_alloc_page(pid, PP_FGPERSIST); + x86_page_table* pt = vmm_fmap_page(pid, PG_MOUNT_2, pt_pp, PG_PREM_RW); + + 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(va); + ppte = ppte & 0xfff | (uintptr_t)ppa; + } + pt->entry[j] = ppte; + // ppte = ppte & ~PG_WRITE; + // pt->entry[j] = ppte; + // ppt->entry[j] = ppte; + } + + ptd->entry[i] = (uintptr_t)pt_pp | PG_PREM_RW; + } + + ptd->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, ptd_pp); + + struct proc_info pcb = (struct proc_info) { + .created = clock_systime(), + .pid = pid, + .mm = __current->mm, + .page_table = ptd_pp, + .intr_ctx = __current->intr_ctx, + .parent_created = __current->created + }; + + // 正如同fork一样,返回两次。 + pcb.intr_ctx.registers.eax = 0; + __current->intr_ctx.registers.eax = pid; + + push_process(&pcb); + +} \ No newline at end of file diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c new file mode 100644 index 0000000..ed2cc74 --- /dev/null +++ b/lunaix-os/kernel/sched.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_PROCESS 512 + +struct proc_info* __current; +struct proc_info dummy; + +extern void __proc_table; + +struct scheduler sched_ctx; + +LOG_MODULE("SCHED") + +void sched_init() { + size_t pg_size = ROUNDUP(sizeof(struct proc_info) * MAX_PROCESS, 0x1000); + assert_msg( + vmm_alloc_pages(KERNEL_PID, &__proc_table, pg_size, PG_PREM_RW, PP_FGPERSIST), + "Fail to allocate proc table" + ); + + sched_ctx = (struct scheduler) { + ._procs = (struct proc_info*) &__proc_table, + .ptable_len = 0, + .procs_index = 0 + }; + + __current = &dummy; +} + +void schedule() { + if (!sched_ctx.ptable_len) { + return; + } + + struct proc_info* next; + int prev_ptr = sched_ctx.procs_index; + int ptr = prev_ptr; + // round-robin scheduler + 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); + + sched_ctx.procs_index = ptr; + + __current->state = PROC_STOPPED; + next->state = PROC_RUNNING; + + __current = next; + + cpu_lcr3(__current->page_table); + + apic_done_servicing(); + + asm volatile ("pushl %0\n jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory"); +} + +pid_t alloc_pid() { + pid_t i = 0; + for (; i < sched_ctx.ptable_len && sched_ctx._procs[i].state != PROC_DESTROY; i++); + + if (i == MAX_PROCESS) { + __current->k_status = LXPROCFULL; + return -1; + } + return i + 1; +} + +void push_process(struct proc_info* process) { + int index = process->pid - 1; + if (index < 0 || index > sched_ctx.ptable_len) { + __current->k_status = LXINVLDPID; + return; + } + + if (index == sched_ctx.ptable_len) { + sched_ctx.ptable_len++; + } + + process->parent = __current->pid; + process->state = PROC_CREATED; + + sched_ctx._procs[index] = *process; +} + +void destroy_process(pid_t pid) { + int index = pid - 1; + if (index < 0 || index > sched_ctx.ptable_len) { + __current->k_status = LXINVLDPID; + return; + } + + sched_ctx._procs[index].state = PROC_DESTROY; + + // TODO: recycle the physical pages used by page tables +} + +void terminate_process(int exit_code) { + __current->state = PROC_TERMNAT; + __current->exit_code = exit_code; + + schedule(); +} + +struct proc_info* get_process(pid_t pid) { + int index = pid - 1; + if (index < 0 || index > sched_ctx.ptable_len) { + return NULL; + } + return &sched_ctx._procs[index]; +} \ No newline at end of file diff --git a/lunaix-os/kernel/syscall.c b/lunaix-os/kernel/syscall.c new file mode 100644 index 0000000..0d41470 --- /dev/null +++ b/lunaix-os/kernel/syscall.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include + +LOG_MODULE("SYSCALL") + +extern void syscall_hndlr(isr_param* param); + +void syscall_install() { + intr_subscribe(LUNAIX_SYS_CALL, syscall_hndlr); +} \ No newline at end of file diff --git a/lunaix-os/kernel/time/timer.c b/lunaix-os/kernel/time/timer.c index 03ef2b4..42a9ac2 100644 --- a/lunaix-os/kernel/time/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -16,6 +16,7 @@ #include #include #include +#include #define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) @@ -38,6 +39,9 @@ static volatile struct lx_timer_context* timer_ctx = NULL; static volatile uint32_t rtc_counter = 0; static volatile uint8_t apic_timer_done = 0; +static volatile uint32_t sched_ticks = 0; +static volatile uint32_t sched_ticks_counter = 0; + #define APIC_CALIBRATION_CONST 0x100000 void @@ -51,6 +55,7 @@ timer_init_context() timer_ctx->active_timers = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer)); llist_init_head(timer_ctx->active_timers); + } void @@ -131,6 +136,9 @@ timer_init(uint32_t frequency) intr_subscribe(APIC_TIMER_IV, timer_update); apic_write_reg(APIC_TIMER_ICR, timer_ctx->tphz); + + sched_ticks = timer_ctx->running_frequency / 1000 * SCHED_TIME_SLICE; + sched_ticks_counter = 0; } int @@ -184,6 +192,13 @@ timer_update(const isr_param* param) lxfree(pos); } } + + sched_ticks_counter++; + + if (sched_ticks_counter >= sched_ticks) { + sched_ticks_counter = 0; + schedule(); + } } static void diff --git a/lunaix-os/link/linker.ld b/lunaix-os/link/linker.ld index a81dad5..2589aeb 100644 --- a/lunaix-os/link/linker.ld +++ b/lunaix-os/link/linker.ld @@ -61,5 +61,9 @@ SECTIONS { } __kernel_end = ALIGN(4K); + __pg_mount_point = ALIGN(4K); + . += 12K; + __proc_table = ALIGN(4K); + . += 128M; __kernel_heap_start = ALIGN(4K); /* 内核结束的地方即堆开始的地方 */ } \ No newline at end of file -- 2.27.0