-void spawn_lxinit() {
- struct proc_info kinit;
-
- init_proc(&kinit);
- kinit.intr_ctx = (isr_param) {
- .registers.esp = KSTACK_TOP - 20,
- .cs = KCODE_SEG,
- .eip = (void*)_lxinit_main,
- .ss = KDATA_SEG,
- .eflags = cpu_reflags()
- };
-
- setup_proc_mem(&kinit, PD_REFERENCED);
-
- // Ok... 准备fork进我们的init进程
- /*
- 这里是一些栈的设置,因为我们将切换到一个新的地址空间里,并且使用一个全新的栈。
- 让iret满意!
- */
- asm volatile(
- "movl %%cr3, %%eax\n"
- "movl %%esp, %%ebx\n"
- "movl %0, %%cr3\n"
- "movl %1, %%esp\n"
- "pushf\n"
- "pushl %2\n"
- "pushl %3\n"
- "pushl $0\n"
- "pushl $0\n"
- "movl %%eax, %%cr3\n"
- "movl %%ebx, %%esp\n"
- ::"r"(kinit.page_table), "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(kinit.intr_ctx.eip)
- :"%eax", "%ebx", "memory"
- );
-
- // 向调度器注册进程,然后这里阻塞等待调度器调度就好了。
- push_process(&kinit);
-
-}
-
-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(KERNEL_PID, (void*)(i << PG_SIZE_BITS));
- }
-
- // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射
- lock_reserved_memory();
-
- 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);
-
- 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();
- timer_init(SYS_TIMER_FREQUENCY_HZ);
- clock_init();
- ps2_kbd_init();
-
- syscall_install();
+void
+spawn_proc0()
+{
+ struct proc_info* proc0 = alloc_process();
+
+ /**
+ * @brief
+ * 注意:这里和视频中说的不一样,属于我之后的一点微调。
+ * 在视频中,spawn_proc0是在_kernel_post_init的末尾才调用的。并且是直接跳转到_proc0
+ *
+ * 但是我后来发现,上述的方法会产生竞态条件。这是因为spawn_proc0被调用的时候,时钟中断已经开启,
+ * 而中断的产生会打乱栈的布局,从而使得下面的上下文设置代码产生未定义行为(Undefined
+ * Behaviour)。 为了保险起见,有两种办法:
+ * 1. 在创建proc0进程前关闭中断
+ * 2. 将_kernel_post_init搬进proc0进程
+ * (_kernel_post_init已经更名为init_platform)
+ *
+ * 目前的解决方案是2
+ */
+
+ 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->parent = proc0;
+
+ // 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的!
+ // cpu_disable_interrupt();
+
+ /* Ok... 首先fork进我们的零号进程,而后由那里,我们fork进init进程。 */
+
+ // 把当前虚拟地址空间(内核)复制一份。
+ proc0->page_table = vmm_dup_vmspace(proc0->pid);
+
+ // 直接切换到新的拷贝,进行配置。
+ cpu_lcr3(proc0->page_table);