x86多核啟動代碼實現
前言
對于多核CPU,開機上電后,最開始其實只有一個cpu核心會啟動,稱為bootstrap processor (BSP) ,而其他的核心則稱為application processors (APs)。BSP的啟動無需操心,而啟動AP則需要我們自己代碼實現,學習時發現少有相關的資料,也踩了一些坑,因此記錄個簡單流程備忘。
流程
原理可以見引用1或者intel開發手冊vol3 8.4節,已經有了非常詳細的解答。
流程如下:
- 首先BSP要進入保護模式或者長模式,啟動AP需要訪問0xFEE00300這個地址(如果開啟了分頁,還需要確保已經映射到了該地址),因為實模式下是無法訪問到這個地址的。
- 發送相關指令,激活AP
2.1 發送 INIT IPI指令,其實就是往內存0xFEE00300這個地址寫入000C4500H
2.2 sleep 10毫秒
2.3 發送IPI指令,即往內存0xFEE00300寫入000C46**XXH,XX是AP的啟動地址除以4096的值,如AP啟動代碼在內存0x8000的位置,XX的之則為08。從這里就可以看出,AP的啟動地址是需要4K對齊的,否則無法正確計算出正確的AP啟動地址。同時要注意AP啟動代碼在內存中的位置不能大于1MB,因為AP剛啟動也是處于實模式,后續進入保護模式, 才能訪問大于1MB的內存地址。
2.4 sleep 200毫秒
2.5 再次發送IPI指令
寫成匯編就是如下十幾行代碼,完整代碼可以見https://github.com/basic60/ARCUS
APIC_ICR_LOW equ 0xFEE00300
start_multi_core:
; 向所有其他 AP 發送 INIT
mov eax, 000C4500H
mov esi, APIC_ICR_LOW
mov [esi], eax
push rdi
mov rdi, 10
call sleep
; 向所有其他 AP 發送 SIPI
mov eax, 0x000C4608
mov [esi], eax
mov rdi, 200
call sleep
pop rdi
mov [esi], eax
ret
可以看見AP啟動并不復雜,但這僅僅是萬里長征第一步,后續完成CPU多核同步、任務調度等才能真正發揮出SMP系統的價值。
其他
sleep實現
簡單實現可以通過一段很大的循環,或者通過時鐘中斷實現。
判斷當前CPU是否是BSP
可以通過讀取IA32_APIC_BASE這個MSR寄存器,看它第9位是否1來判斷

獲取當前的cpuid
可以通過cpuid指令來獲取,代碼如下:
get_cpu_id:
mov rax, 0x1
cpuid
and ebx, 0xff000000
shr ebx, 24
mov eax, ebx
ret

浙公網安備 33010602011771號