{
"name": "OS-DEV",
"includePath": [
- "${workspaceFolder}/includes/**"
+ "${workspaceFolder}/includes"
],
"compilerArgs": [
"-ffreestanding",
"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
#include <arch/x86/boot/multiboot.h>
#define MB_FLAGS MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN
-#define KPG_SIZE 24*1024
+#define KPG_SIZE 10*4096
.section .multiboot
.long MULTIBOOT_MAGIC
/*
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
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
// 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;
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++)
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段的物理地址
#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
#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 <hal/cpu.h>
ISR(21)
ISR(32)
+ISR(33)
ISR(201)
--- /dev/null
+#ifndef __LUNAIX_TSS_H
+#define __LUNAIX_TSS_H
+#include <stdint.h>
+
+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 */
--- /dev/null
+#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 */
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
#ifndef __LUNAIX_CONSTANTS_H
#define __LUNAIX_CONSTANTS_H
-#include <stddef.h>
-
-#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 <stddef.h>
// From Linux kernel v2.6.0 <kernel.h:194>
/**
* container_of - cast a member of a structure out to the containing structure
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
#endif /* __LUNAIX_CONSTANTS_H */
#ifndef __LUNAIX_KEYBOARD_H
#define __LUNAIX_KEYBOARD_H
+#include <lunaix/clock.h>
// Lunaix Keycode
// 15 7 0
typedef unsigned short kbd_keycode_t;
typedef unsigned short kbd_kstate_t;
-#include <lunaix/clock.h>
-
#define KEYPAD 0x0100
#define FN_KEY 0x0200
--- /dev/null
+#ifndef __LUNAIX_UNISTD_H
+#define __LUNAIX_UNISTD_H
+
+#include <lunaix/syscall.h>
+#include <lunaix/types.h>
+
+__LXSYSCALL(pid_t, fork)
+
+__LXSYSCALL1(int, sbrk, void*, addr)
+
+__LXSYSCALL1(void*, brk, size_t, size)
+
+#endif /* __LUNAIX_UNISTD_H */
// Dynamic Memory (i.e., heap) Manager
#include <stddef.h>
+#include <lunaix/mm/mm.h>
+#include <lunaix/process.h>
#define M_ALLOCATED 0x1
#define M_PREV_FREE 0x2
#define HEAP_INIT_SIZE 4096
-typedef struct
-{
- void* start;
- void* brk;
- void* max_addr;
-} heap_context_t;
-
int
dmm_init(heap_context_t* heap);
--- /dev/null
+#ifndef __LUNAIX_MM_H
+#define __LUNAIX_MM_H
+
+#include <lunaix/ds/llist.h>
+#include <lunaix/ds/mutex.h>
+
+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 */
typedef unsigned long ptd_t;
typedef unsigned long pt_t;
typedef unsigned int pt_attr;
+typedef uint32_t x86_pte_t;
/**
* @brief 虚拟映射属性
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 */
#include <stdint.h>
#include <stddef.h>
+#include <lunaix/process.h>
#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 标注物理页为可使用
*
* @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 标注多个连续的物理页为可用
* @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 初始化物理内存管理器
*/
void pmm_init(uintptr_t mem_upper_lim);
+struct pp_struct* pmm_query(void* pa);
/**
* @brief 释放一个已分配的物理页,假若页地址不存在,则无操作。
* @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 */
#ifndef __LUNAIX_VMM_H
#define __LUNAIX_VMM_H
#include <lunaix/mm/page.h>
+#include <lunaix/process.h>
#include <stddef.h>
#include <stdint.h>
+#include <lunaix/mm/pmm.h>
// Virtual memory manager
/**
* @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 建立一个映射关系,映射指定的物理页地址至虚拟页地址。如果指定的虚拟页地址已被占用,
* @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);
/**
* @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 设置一个映射,如果映射已存在,则忽略。
* @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 删除一个映射
* @param vpn
*/
void
-vmm_unmap_page(void* va);
+vmm_unset_mapping(void* va);
/**
* @brief 将虚拟地址翻译为其对应的物理映射
v_mapping
vmm_lookup(void* va);
+/**
+ * @brief (COW) 为虚拟页创建副本。
+ *
+ * @return void* 包含虚拟页副本的物理页地址。
+ *
+ */
+void* vmm_dup_page(void* va);
+
#endif /* __LUNAIX_VMM_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_H
+#define __LUNAIX_SYS_H
+
+#include <lunaix/syscall.h>
+
+__LXSYSCALL1(void, exit, int, status)
+
+__LXSYSCALL(void, yield)
+
+#endif /* __LUNAIX_SYS_H */
--- /dev/null
+#ifndef __LUNAIX_PROCESS_H
+#define __LUNAIX_PROCESS_H
+
+#include <stdint.h>
+#include <arch/x86/interrupts.h>
+#include <lunaix/mm/mm.h>
+#include <lunaix/types.h>
+#include <lunaix/clock.h>
+
+// 虽然内核不是进程,但为了区分,这里使用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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#ifndef __LUNAIX_SYSCALL_H
+#define __LUNAIX_SYSCALL_H
+
+#include <arch/x86/vectors.h>
+
+#define __SYSCALL_fork 0x1
+#define __SYSCALL_yield 0x2
+#define __SYSCALL_exit 0x3
+#define __SYSCALL_sbrk 0x4
+#define __SYSCALL_brk 0x5
+
+#define __SYSCALL_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 */
--- /dev/null
+#ifndef __LUNAIX_TYPES_H
+#define __LUNAIX_TYPES_H
+
+#include <stdint.h>
+
+typedef int32_t pid_t;
+
+#endif /* __LUNAIX_TYPES_H */
#include <arch/x86/gdt.h>
+#include <arch/x86/tss.h>
#include <stdint.h>
-#define GDT_ENTRY 5
+#define GDT_ENTRY 6
uint64_t _gdt[GDT_ENTRY];
uint16_t _gdt_limit = sizeof(_gdt) - 1;
_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);
_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
// 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
#define __ASM__
#include <arch/x86/interrupts.h>
+// #define __ASM_INTR_DIAGNOSIS
.macro isr_template vector, no_error_code=1
.global _asm_isr\vector
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
interrupt_wrapper:
pushl %esp
+
pushl %esi
pushl %ebp
pushl %edi
movl %eax, (%esp)
call intr_handler
+
+ .global soft_iret
+ soft_iret:
popl %esp
popl %eax
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
#include <hal/cpu.h>
#include <lunaix/syslog.h>
#include <lunaix/tty/tty.h>
+#include <lunaix/process.h>
+#include <lunaix/sched.h>
+
+LOG_MODULE("intr")
static int_subscriber subscribers[256];
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) {
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
#include <hal/apic.h>
+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",
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)
{
--- /dev/null
+#include <arch/x86/interrupts.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/common.h>
+
+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
/* 高半核入口点 - 0xC0000000 */
+#define __ASM__
+#include <lunaix/common.h>
+
.section .text
.global hhk_entry_
hhk_entry_:
lgdt (%esp)
/* 更新段寄存器 */
- movw $0x10, %cx
+ movw $KDATA_SEG, %cx
movw %cx, %es
movw %cx, %ds
movw %cx, %fs
movw %cx, %ss
/* 更新 CS:EIP */
- pushw $0x08
+ pushw $KCODE_SEG
pushl $_after_gdt
retf
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
--- /dev/null
+#define __ASM__
+#include <lunaix/syscall.h>
+
+.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
+
+
--- /dev/null
+#include <arch/x86/tss.h>
+#include <lunaix/common.h>
+
+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
#include <lunaix/ds/semaphore.h>
+#include <lunaix/sched.h>
void sem_init(struct sem_t *sem, unsigned int initial) {
sem->counter = ATOMIC_VAR_INIT(initial);
void sem_wait(struct sem_t *sem) {
while (!atomic_load(&sem->counter)) {
- // TODO: yield the cpu
+ schedule();
}
atomic_fetch_sub(&sem->counter, 1);
}
#include <lunaix/timer.h>
#include <lunaix/clock.h>
#include <lunaix/peripheral/ps2kbd.h>
+#include <lunaix/process.h>
+#include <lunaix/sched.h>
+#include <lunaix/syscall.h>
#include <hal/rtc.h>
#include <hal/apic.h>
#include <arch/x86/interrupts.h>
#include <klibc/stdio.h>
+#include <klibc/string.h>
#include <stdint.h>
#include <stddef.h>
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();
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映射
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();
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++) {
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);
}
}
}
// 将内核占据的页,包括前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
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
#include <lunaix/timer.h>
#include <lunaix/keyboard.h>
#include <lunaix/tty/tty.h>
-#include <stdint.h>
+#include <lunaix/lunistd.h>
+#include <lunaix/proc.h>
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 "
tty_sync_cursor();
}
}
+
spin();
}
--- /dev/null
+#include <lunaix/mm/vmm.h>
+
+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
#include <lunaix/mm/dmm.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/mm/page.h>
+#include <lunaix/status.h>
#include <lunaix/spike.h>
+
+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
// 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;
}
}
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);
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*
#include <lunaix/mm/page.h>
#include <lunaix/mm/pmm.h>
+#include <lunaix/status.h>
-#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的页。我们不希望空指针是指向一个有效的内存空间。
// 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) ?
}
}
}
+ 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
#include <hal/cpu.h>
#include <klibc/string.h>
-#include <lunaix/mm/page.h>
-#include <lunaix/mm/pmm.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/spike.h>
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;
}
}
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,
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);
}
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);
}
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) {
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++;
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;
}
}
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;
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;
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);
// 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);
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)
{
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;
}
}
#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();
--- /dev/null
+#include <lunaix/process.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/clock.h>
+#include <lunaix/syslog.h>
+#include <lunaix/common.h>
+
+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
--- /dev/null
+#include <lunaix/process.h>
+#include <lunaix/sched.h>
+#include <lunaix/mm/vmm.h>
+#include <hal/cpu.h>
+#include <arch/x86/interrupts.h>
+#include <hal/apic.h>
+
+#include <lunaix/spike.h>
+#include <lunaix/status.h>
+#include <lunaix/syslog.h>
+
+#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
--- /dev/null
+#include <lunaix/syscall.h>
+#include <arch/x86/interrupts.h>
+#include <lunaix/process.h>
+#include <lunaix/sched.h>
+#include <lunaix/syslog.h>
+
+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
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
#include <lunaix/timer.h>
+#include <lunaix/sched.h>
#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector)
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
timer_ctx->active_timers =
(struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
llist_init_head(timer_ctx->active_timers);
+
}
void
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
lxfree(pos);
}
}
+
+ sched_ticks_counter++;
+
+ if (sched_ticks_counter >= sched_ticks) {
+ sched_ticks_counter = 0;
+ schedule();
+ }
}
static void
}
__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