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
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
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广播
*p = *p == ' ' ? 'K' : ' ';
system.lapic->write(LAPIC_EOI, 0);
}
+
+bool ap_ready() {
+ return system.ap_cpuid != 0;
+}
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");
}
// ## 中断路由路径配置矩阵