]> Zhao Yanbai Git Server - kernel.git/commitdiff
用新的方法切换ap的内核栈
authoracevest <zhaoyanbai@126.com>
Thu, 8 Jan 2026 07:58:21 +0000 (15:58 +0800)
committeracevest <zhaoyanbai@126.com>
Thu, 8 Jan 2026 07:58:21 +0000 (15:58 +0800)
boot/ap_boot.S
include/system.h
kernel/ap.c
kernel/apic.c
kernel/system.c

index 86260b3b8811063f29e3bad05f2a1321c1b1a79a..154229846c7963db9d0b6375ceb636597b4e0ce3 100644 (file)
@@ -121,6 +121,11 @@ ap_code32_real_entry:
     subl    $kernel_virtual_addr_start, %eax # 算出物理地址
     movl    %eax, %cr3
 
+    # 加载AP的内核栈顶到esp
+    .extern ap_get_kernel_esp
+    call    ap_get_kernel_esp
+    movl    %eax, %esp
+
     # 进入内核ap代码
     .extern ap_kernel_entry
     leal    ap_kernel_entry, %eax
index d5c5ef1d7f8b2c6f0173624a67c801c29c2c7f0c..4c5dc1c24a46b4e8d727aa05ddf63188d544a746 100644 (file)
@@ -158,6 +158,9 @@ typedef struct system {
 
     dev_t root_dev;
 
+    //
+    uint32_t ap_cpuid;
+
     // 按理这些信息应该按CPU存储,简化实现
     lapic_t* lapic;
     paddr_t lapic_addr;
@@ -172,9 +175,9 @@ typedef struct system {
     u32 debug;
 
     u32 delay;
-} System, *pSystem;
+} system_t;
 
-extern System system;
+extern system_t system;
 
 void system_delay();
 
index fd05c06a5c890a9f98e562c5a8c91b266b31b2a6..898548204a721f9e5acf18163b2876765e409f10 100644 (file)
@@ -52,11 +52,13 @@ static inline void set_ap_idt_gate(u32 vec, u32 handler, u8 type, u8 DPL) {
         set_ap_idt_gate(vect, (u32)handler, type, DPL); \
     } while (0)
 
-void ap_kernel_entry() {
+uint32_t ap_get_kernel_esp() {
     // 虽然ap_pre_pgd只做了一下跳板页目录看起来很可惜
     // 不过可以把它拿来个AP的栈用
-    asm("mov %0, %%esp" : : "r"(pa2va(&ap_pre_pgd) + PAGE_SIZE - 128));
+    return (uint32_t)pa2va(&ap_pre_pgd) + PAGE_SIZE;
+}
 
+void ap_kernel_entry() {
     // 进入内核空间后要加载原来已经在内核空间的ap_gdt
     // 之前加载的被复制到1MB以下的ap_gdt需要废弃,因为它已经在内核地址空间之外了
     // 虽然他们是同一个ap_gdt
@@ -124,6 +126,9 @@ void ap_kernel_entry() {
         write_msr(MSR_IA32_APIC_BASE, apic_base);
     }
 
+    system.ap_cpuid = lapic->get_lapic_id();
+    printk("AP CPU id: %d\n", system.ap_cpuid);
+
     uint32_t lapic_svr = lapic->read(LAPIC_SVR);
     lapic_svr |= (1 << 8);    // 启用LAPIC
     lapic_svr &= ~(1 << 12);  // 禁用EOI广播
@@ -163,3 +168,7 @@ void do_ap_no_irq_handler() {
     *p = *p == ' ' ? 'K' : ' ';
     system.lapic->write(LAPIC_EOI, 0);
 }
+
+bool ap_ready() {
+    return system.ap_cpuid != 0;
+}
index 5600206c4c1516fc3021fd3038eca14f3001fb17..c4aa8ac3d499ff06c6eb778ad9a41ba1aa9449a4 100644 (file)
@@ -624,6 +624,13 @@ void init_apic() {
     paddr_t ap_code_addr = 0x1000;
     prepare_ap_code(ap_code_addr);
     wakeup_ap(ap_code_addr);
+
+    printk("wait AP ready...");
+    extern bool ap_ready();
+    while (!ap_ready()) {
+        asm("pause");
+    }
+    printk("AP ready\n");
 }
 
 // ## 中断路由路径配置矩阵
index a37f32ea59e6df247bf2fd84cd4b62aa1de25f32..2afd1ee9a20c4334acce461bf5134d6c9042f13f 100644 (file)
@@ -27,7 +27,7 @@
 #include <system.h>
 #include <linkage.h>
 
-System system;
+system_t system;
 tss_t tss;
 
 desc_t ALIGN8 idt[NIDT];