玩轉(zhuǎn)Linux多核SMP系統(tǒng)的引導(dǎo),從這幾點(diǎn)入手!
本篇文章基于Linux 2.6.32,x86體系結(jié)構(gòu)
系統(tǒng)的引導(dǎo)和初始化階段是個(gè)特例,因?yàn)樵谶@個(gè)階段里系統(tǒng)中只有一個(gè)"上下文",只能由一個(gè)處理器來(lái)處理。在這個(gè)階段里,也就是在系統(tǒng)剛加電或"總清(reset)"之后,系統(tǒng)中暫時(shí)只有一個(gè)處理器運(yùn)行,這個(gè)處理器稱之為"引導(dǎo)處理器"BP;其余的處理器則處于暫停狀態(tài),稱為"應(yīng)用處理器"AP。"引導(dǎo)處理器"完成整個(gè)系統(tǒng)的引導(dǎo)和初始化,并創(chuàng)建起多個(gè)進(jìn)程,從而可以由多個(gè)處理器同時(shí)參與處理時(shí),才啟動(dòng)所有的"應(yīng)用處理器",讓他們完成自身的初始化以后,投入運(yùn)行。參考intel手冊(cè):
MP 初始化協(xié)議定義了兩類處理器:引導(dǎo)處理器 (BSP) 和應(yīng)用處理器 (AP)。在 MP 系統(tǒng)通電或重置后,系統(tǒng)硬件動(dòng)態(tài)選擇系統(tǒng)總線上的一個(gè)處理器作為 BSP。其余處理器被指定為 AP。
我們?cè)谶@里關(guān)心的是"引導(dǎo)處理器"怎樣為各個(gè)"應(yīng)用處理器"做好準(zhǔn)備,然后啟動(dòng)其運(yùn)行的過(guò)程。
在初始化階段,引導(dǎo)處理器先完成自身的初始化,進(jìn)入保護(hù)模式并開(kāi)啟頁(yè)式存儲(chǔ)管理機(jī)制,再完成系統(tǒng)特別是內(nèi)存的初始化,然后從 –> –> –> 進(jìn)行SMP系統(tǒng)的初始化。由于此時(shí)APs處于暫停狀態(tài),所以BP需要通過(guò) –> –> –> –> 發(fā)送IPI中斷喚醒APs,這樣APs就開(kāi)始了正常的運(yùn)行過(guò)程,擁有和BP一樣的地位。詳細(xì)過(guò)程我們后面分析。先來(lái)看總體大綱圖:start_kernel()rest_init()kernel_init()smp_init()smp_init()cpu_up()native_cpu_up()do_boot_cpu()wakeup_secondary_cpu_via_init()

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書(shū)籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。?!前100名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書(shū)、實(shí)戰(zhàn)項(xiàng)目及代碼)?


smp_init的代碼在init/main.c:
native_cpu_up的注冊(cè):
native_cpu_up
接下來(lái)看標(biāo)號(hào)(1)處 native_cpu_up(unsigned int cpu) 。依次啟動(dòng)系統(tǒng)中各個(gè)CPU。
1、do_boot_cpu
發(fā)送IPI中斷喚醒APs,并且在IPI中斷中,帶有AP喚醒后要執(zhí)行的代碼地址(實(shí)際上只是一個(gè)vector,AP會(huì)把這個(gè)vector?12作為要執(zhí)行的代碼地址)。
2、wakeup_secondary_cpu_via_init發(fā)送IPI
發(fā)送IPI中斷,至于為什么這里apic_icr_write可以發(fā)送vector到AP,請(qǐng)參考intel文檔。
AP接收到IPI,就開(kāi)始激活執(zhí)行了。
3、蹦床。S 這段代碼就是前面do_boot_cpu()—>setup_trampoline()拷貝到trampoline_base的代碼:
在這段代碼中,設(shè)置標(biāo)識(shí),以便BSP知道該AP已經(jīng)運(yùn)行到這段代碼,加載GDT和LDT表基址。然后啟動(dòng)保護(hù)模式,更新CS段寄存器,跳轉(zhuǎn)到startup_32_smp 處。
4、startup_32_smp
這個(gè)函數(shù)的主要作用在于開(kāi)啟分頁(yè),更新EIP,ESP。重新設(shè)置GDT,更新所有的段寄存器,最后跳轉(zhuǎn)到start_secondary執(zhí)行。
5、start_secondary
此時(shí)分頁(yè)和保護(hù)模式都已經(jīng)開(kāi)啟,且完全進(jìn)入BP事先為我們fork好的idel線程的上下文。
本函數(shù)主要是通知BP本AP啟動(dòng)完成,然后cpu_idle,參與到任務(wù)調(diào)度。
總結(jié)
整理一下AP啟動(dòng)的整個(gè)過(guò)程:
wakeup_secondary_cpu_via_init:BP發(fā)送IPI中斷給AP
蹦床。S AP引導(dǎo)代碼,為16進(jìn)制代碼,啟用保護(hù)模式
head.s 為AP創(chuàng)建分頁(yè)管理
start_secondary 通知BP啟動(dòng)成功。AP參與任務(wù)調(diào)度。
F&Q:
每個(gè)AP自己的GDTR在哪里設(shè)置的?(每個(gè)AP的GDT都已經(jīng)由BP處理器初始化完成,就等待設(shè)置到CPU上)
發(fā)送IPI到AP后,CS:IP如何設(shè)置的?
CS 為 0x**00(**代表IPI中包含的vector),IP為0,CS:IP就可以引用trampoline.S中的代碼
