]> Zhao Yanbai Git Server - kernel.git/commitdiff
让AP进入保护模式后可以和BSP共享同样的内核地址空间
authoracevest <zhaoyanbai@126.com>
Sun, 4 Jan 2026 14:25:53 +0000 (22:25 +0800)
committeracevest <zhaoyanbai@126.com>
Sun, 4 Jan 2026 14:25:53 +0000 (22:25 +0800)
boot/ap_boot.S
boot/multiboot.S
boot/unpaged_boot.c
kernel/ap.c [new file with mode: 0644]

index 538fce85a39c3023170add39cc35597e12a11cf6..4e5c0c8f49c307a11160454b89999ad9b393460b 100644 (file)
@@ -17,6 +17,7 @@ ap_boot_bgn:
 ap_realmode_base:
 ap_real_mode_entry:
     cli
+    # TODO 只允许CPU1运行
 
     wbinvd # 将CPU缓存写回主内存并使缓存失效
 
@@ -64,6 +65,56 @@ ap_real_mode_entry:
 .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
index 4f850bcd04b25656e59a000f07adbee5f07385e1..941b3772c899cc3784603a6cc3e845f91f03b519 100644 (file)
@@ -21,7 +21,6 @@
 .extern setup_kernel
 .extern root_task_entry
 .extern get_root_task_stack_top
-.extern kernel_virtual_addr_start
 
 #define MULTIBOOT_STACK_SIZE 0x200
 
index 53d67ef9d3b0bc18be09998227a7f2a44e698596..4fbf2fabcb9a2dda926491a7f6770ed4331ffadd 100644 (file)
@@ -17,6 +17,8 @@ extern unsigned long kernel_virtual_addr_start;
 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]
@@ -30,6 +32,7 @@ void boot_paging() {
     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;
     }
 
     // 初始化页目录
@@ -38,6 +41,11 @@ void boot_paging() {
     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;
     }
 
diff --git a/kernel/ap.c b/kernel/ap.c
new file mode 100644 (file)
index 0000000..5b9a3a0
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * ------------------------------------------------------------------------
+ *   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;");
+    }
+}