--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * 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:
.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:
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) {
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");
}