-unlock_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_unmap_page((pa + (j << PG_SIZE_BITS)));
- }
- }
+spawn_proc0()
+{
+ struct proc_info proc0;
+
+ /**
+ * @brief
+ * 注意:这里和视频中说的不一样,属于我之后的一点微调。
+ * 在视频中,spawn_proc0是在_kernel_post_init的末尾才调用的。并且是直接跳转到_proc0
+ *
+ * 但是我后来发现,上述的方法会产生竞态条件。这是因为spawn_proc0被调用的时候,时钟中断已经开启,
+ * 而中断的产生会打乱栈的布局,从而使得下面的上下文设置代码产生未定义行为(Undefined
+ * Behaviour)。 为了保险起见,有两种办法:
+ * 1. 在创建proc0进程前关闭中断
+ * 2. 将_kernel_post_init搬进proc0进程
+ * (_kernel_post_init已经更名为init_platform)
+ *
+ * 目前的解决方案是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() };
+
+ // 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的!
+ // cpu_disable_interrupt();
+
+ setup_proc_mem(&proc0, PD_REFERENCED);
+
+ // Ok... 首先fork进我们的零号进程,而后由那里,我们fork进init进程。
+ /*
+ 这里是一些栈的设置,因为我们将切换到一个新的地址空间里,并且使用一个全新的栈。
+ 让iret满意!
+ */
+ asm volatile("movl %%cr3, %%eax\n"
+ "movl %%esp, %%ebx\n"
+ "movl %1, %%cr3\n"
+ "movl %2, %%esp\n"
+ "pushf\n"
+ "pushl %3\n"
+ "pushl %4\n"
+ "pushl $0\n"
+ "pushl $0\n"
+ "movl %%esp, %0\n"
+ "movl %%eax, %%cr3\n"
+ "movl %%ebx, %%esp\n"
+ : "=m"(proc0.intr_ctx.registers.esp)
+ : "r"(proc0.page_table),
+ "i"(KSTACK_TOP),
+ "i"(KCODE_SEG),
+ "r"(proc0.intr_ctx.eip)
+ : "%eax", "%ebx", "memory");
+
+ // 向调度器注册进程。
+ push_process(&proc0);
+
+ // 由于时钟中断未就绪,我们需要手动通知调度器进行第一次调度。这里也会同时隐式地恢复我们的eflags.IF位
+ schedule();
+
+ /* Should not return */
+ assert_msg(0, "Unexpected Return");