ap_realmode_base:
ap_real_mode_entry:
cli
+ # TODO 只允许CPU1运行
wbinvd # 将CPU缓存写回主内存并使缓存失效
.align 32
ap_code32_entry:
cli
+ nop
+ nop
+
+ # 数据段寄存器需要调整成GDT的描述符的选择子
+ movl $0x10, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ # 加载一个跳板页目录,为真正切换到内核地址空间做准备
+ .extern ap_pre_pgd
+ leal ap_pre_pgd, %eax
+ movl %eax, %cr3
+
+ # 开启分页
+ movl %cr0, %eax
+ orl $0x80000000, %eax
+ movl %eax, %cr0
+
+ leal ap_code32_real_entry, %eax
+ jmp *%eax
+
+# 虽然下面的代码也会被复制到小于1MB的内存
+# 但是它不会在那里被执行,而是会在大于1MB的物理内存,并且是内核的地址空间执行
+# 也就是说他们在内核的原来的地址执行
+# 当然也可以把它搬到ap_boot_end之后,这样它就不会被复制到小于1MB的内存里了
+ap_code32_real_entry:
+
+ nop
+ nop
+
+ # 把栈指针调整到内核的地址空间
+ addl $kernel_virtual_addr_start, %esp
+
+ # 到这里我们就可以切到BSP一样cr3了
+ # 为什么在开启分页前无法直接加载BSP的cr3?
+ # 因为BSP把小于内核地址空间的映射都清0了,如果直接加载,分页后的第一行指令就无法执行
+
+ .extern init_pgd
+ leal init_pgd, %eax
+ subl $kernel_virtual_addr_start, %eax # 算出物理地址
+ movl %eax, %cr3
+
+ # 进入内核ap代码
+ .extern ap_kernel_entry
+ leal ap_kernel_entry, %eax
+ jmp *%eax
+
nop
nop
hlt
.extern setup_kernel
.extern root_task_entry
.extern get_root_task_stack_top
-.extern kernel_virtual_addr_start
#define MULTIBOOT_STACK_SIZE 0x200
extern pde_t __initdata init_pgd[PDECNT_PER_PAGE] __attribute__((__aligned__(PAGE_SIZE)));
extern pte_t __initdata init_pgt[PTECNT_PER_PAGE * BOOT_INIT_PAGETBL_CNT] __attribute__((__aligned__(PAGE_SIZE)));
+pde_t ap_pre_pgd[PDECNT_PER_PAGE] __attribute__((__aligned__(PAGE_SIZE)));
+
// Length = BOOT_INIT_PAGETBL_CNT*4M
// [0x00000000, 0x00000000 + Length - 1]
// [0xC0000000, 0xC0000000 + Length - 1]
pde_t* dir = (pde_t*)init_pgd_paddr;
for (int i = 0; i < PDECNT_PER_PAGE; i++) {
dir[i] = 0;
+ ap_pre_pgd[i] = 0;
}
// 初始化页目录
for (int i = 0; i < BOOT_INIT_PAGETBL_CNT; i++) {
dir[i] = pd_entry; // 设置低端线性地址空间的页表项
dir[kpde_base + i] = pd_entry; // 设置内核线性地址空间的页表项
+
+ // AP初始化用于开启分页后再跳入内核空间的跳板页目录
+ ap_pre_pgd[i] = pd_entry;
+ ap_pre_pgd[kpde_base + i] = pd_entry;
+
pd_entry += PAGE_SIZE;
}
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: ap.c
+ * Author: Zhao Yanbai
+ * 2026-01-04 20:15:33 Sunday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <page.h>
+
+extern pde_t* ap_pre_pgd;
+
+void ap_kernel_entry() {
+ // 虽然ap_pre_pgd只做了一下跳板页目录看起来很可惜
+ // 不过可以把它拿来个AP的栈用
+ asm("mov %0, %%esp" : : "r"(pa2va(&ap_pre_pgd) + PAGE_SIZE));
+ while (1) {
+ asm("nop;");
+ }
+}