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