]> Zhao Yanbai Git Server - kernel.git/commitdiff
AP启动进入保护模式
authoracevest <zhaoyanbai@126.com>
Sun, 4 Jan 2026 11:11:18 +0000 (19:11 +0800)
committeracevest <zhaoyanbai@126.com>
Sun, 4 Jan 2026 11:11:18 +0000 (19:11 +0800)
boot/ap_boot.S [new file with mode: 0644]
boot/multiboot.S
kernel/apic.c

diff --git a/boot/ap_boot.S b/boot/ap_boot.S
new file mode 100644 (file)
index 0000000..538fce8
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: ap_boot.S
+ *      Author: Zhao Yanbai
+ *              2026-01-04 08:18:07 Sunday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+.code16
+#.text
+#.section .ap_boot, "ax", @progbits
+.global ap_boot_bgn
+.global ap_boot_end
+.align 0x1000
+ap_boot_bgn:
+ap_realmode_base:
+ap_real_mode_entry:
+    cli
+
+    wbinvd # 将CPU缓存写回主内存并使缓存失效
+
+    xorl    %ebx, %ebx
+
+    movw    %cs, %bx
+    movw    %bx, %ds
+    movw    %bx, %es
+    movw    %bx, %ss
+
+    # 算出ap_realmode_base的线性地址
+    shl     $4, %ebx
+
+    movl    %ebx, %esp
+    addl    $0x1000, %esp
+
+    # 算出gdt的线性地址
+    leal    (ap_gdt - ap_realmode_base)(%ebx), %eax
+    # 把这个地址填入gdtr的base位置
+    movl    %eax, (ap_gdtr_base - ap_realmode_base)
+
+
+    # 算出ap_code32_entry的线性地址
+    leal    (ap_code32_entry - ap_realmode_base)(%ebx), %eax
+    # 把这个地址填入ap_code32_entry_address
+    mov     %eax, (ap_code32_entry_address - ap_realmode_base)
+
+
+    lgdt    ap_gdtr - ap_realmode_base
+
+    # enable PE
+    movl    %cr0,%eax
+    orl     $0x00000001,%eax
+    movl    %eax,%cr0
+
+    # 清空指令流水线
+    jmp     .flush
+.flush:
+
+    # ljmpl 的前后两个l都很重要
+    ljmpl    *(ap_code32_entry_address - ap_realmode_base)
+
+
+.code32
+.align 32
+ap_code32_entry:
+    cli
+    nop
+    nop
+    hlt
+
+
+.align 32
+ap_code32_entry_address:    .long 0x00000000 # 等待动态写入
+                            .word 0x0008, 0x0000
+
+.align 32
+ap_gdt:
+empty:     .long    0x00000000, 0x00000000
+code_desc: .long    0x0000FFFF, 0x00CF9B00
+data_desc: .long    0x0000FFFF, 0x00CF9300
+ap_gdt_end:
+ap_gdtr:
+    ap_gdtr_limit: .word ap_gdt_end-ap_gdt
+    ap_gdtr_base:  .long 0 # 等待动态写入
+
+ap_boot_end:
index 9545d59e1bc8329ac11243cfbdde016d0f7523fd..4f850bcd04b25656e59a000f07adbee5f07385e1 100644 (file)
@@ -107,7 +107,7 @@ p_label_far_ptr:
 
 .align 32
 boot_gdt:
-empty: .long    0x00000000, 0x00000000
+empty:     .long    0x00000000, 0x00000000
 code_desc: .long    0x0000FFFF, 0x00CF9B00
 data_desc: .long    0x0000FFFF, 0x00CF9300
 boot_gdt_end:
index eecd23355501b7326bb710f86e787357f8a0b707..3643db0088fef7151adc33c7beedf1cbea5de9da 100644 (file)
@@ -362,12 +362,20 @@ void ioapic_init() {
 void prepare_ap_code(paddr_t paddr) {
     // 注意: 最开始时AP是运行在实模式
     paddr += KERNEL_VADDR_BASE;
-    *(volatile uint8_t*)(paddr + 0) = 0x90;
-    *(volatile uint8_t*)(paddr + 1) = 0x90;
-    *(volatile uint8_t*)(paddr + 2) = 0x90;
-    *(volatile uint8_t*)(paddr + 3) = 0xEA;     // jmp
-    *(volatile uint16_t*)(paddr + 4) = 0x0000;  // offset: 0000
-    *(volatile uint16_t*)(paddr + 6) = 0x0100;  // cs:0100
+    // *(volatile uint8_t*)(paddr + 0) = 0x90;
+    // *(volatile uint8_t*)(paddr + 1) = 0x90;
+    // *(volatile uint8_t*)(paddr + 2) = 0x90;
+    // *(volatile uint8_t*)(paddr + 3) = 0xEA;     // jmp
+    // *(volatile uint16_t*)(paddr + 4) = 0x0000;  // offset: 0000
+    // *(volatile uint16_t*)(paddr + 6) = 0x0100;  // cs:0100
+
+    extern char ap_boot_bgn;
+    extern char ap_boot_end;
+    uint32_t bytes = &ap_boot_end - &ap_boot_bgn;
+    // memcpy((void*)paddr, &ap_boot_bgn, bytes);
+    for(int i=0; i<bytes; i++) {
+        ((uint8_t*)paddr)[i] = ((uint8_t*)&ap_boot_bgn)[i];
+    }
 }
 
 void wakeup_ap(paddr_t paddr) {
@@ -428,9 +436,12 @@ void wakeup_ap(paddr_t paddr) {
         asm("nop");
     }
 
+#if 0
+    // 在调试的时候,如果在ap_boot.S的入口处写hlt,它会hlt的AP继续执行
     // intel 要求至少发两次
     lapic->write64(LAPIC_ICR, startup_ipi);
     printk("STARTUP[1] IPI %016x\n", startup_ipi);
+#endif
 
     printk("wakeup ap\n");
 }