? ? ? ?本文側(cè)重點在于BIOS查找“啟動順序”(Boot Sequence)之前夯尽,也就是從按下電源到BIOS移交權(quán)限之間的這一段
我們從按下電源開始纵东。
? ? ? ?首先酬诀,是CPU Reset颓影。主板加電之后在電壓尚未穩(wěn)定之前粉楚,其北橋控制芯片會向CPU發(fā)出重置信號(Reset)音五,此時CPU進(jìn)行初始化惫撰。當(dāng)電壓穩(wěn)定后,控制芯片會撤銷Reset信號躺涝,CPU開始工作厨钻。我們要探討的第一個問題就是CPU執(zhí)行的第一條指令的位置
。
? ? ? ?現(xiàn)在網(wǎng)上流傳的資料基本上是8086 CPU的資料坚嗜,給出的說法一般是這樣:CS寄存器初始化為0xF000夯膀,IP寄存器初始化為0xFFF0,所以按照CPU實模式地址計算法則苍蔬,CPU執(zhí)行的第一條指令地址是CS*10h+IP诱建,即0xFFFF0處。8086CPU確實如此碟绑,但是80386及其以上的CPU
其計算地址法則卻不是這樣俺猿。
? ? ? ?第一點,80386及其以上的現(xiàn)代CPU(以下簡稱CPU)加電Reset之后并不是直接進(jìn)入實模式格仲;
? ? ? ?第二點押袍,CPU在合成地址的時候不區(qū)分實模式和保護(hù)模式。
? ? ? ?我們知道凯肋,CPU進(jìn)入保護(hù)模式的方法是CR0寄存器的PE位置為1谊惭。而在CPU剛加電的時候,CR0寄存器的PE位確實沒有置1,那么圈盔,此時是實模式嗎豹芯?暫時還不是,Intel并沒有給給出表示此時CPU狀態(tài)的術(shù)語名詞驱敲,我們姑且稱之為混沌模式吧铁蹈。自從80386以來,因為增加了保護(hù)模式的緣故癌佩,CS等段寄存器不再是簡簡單單的段寄存器了木缝,而是一個包含了段選擇器(segment selector)、段基址(segment base)围辙,以及段限制(segment limit)的一組復(fù)雜寄存器。顯然段基址決定著內(nèi)存段的基地址放案。不過需要說明的是作為程序員只能操作CS寄存器中的“段選擇器”這16位的大小姚建,其它的區(qū)域作為隱藏區(qū)域?qū)Τ绦騿T不可見,我們無法訪問吱殉。
? ? ? ?當(dāng)CPU處于段尋址模式的時候掸冤,假設(shè)段選擇器(我們能訪問的那16位)裝入了0xF000,那么CPU會先將F000 * 10h也就是F0000h裝入段基址里友雳。之后需要合成地址的時候不考慮別的稿湿,而是直接從之前合成好的段基址里讀出基地址F0000h加上IP寄存器里的偏移生成地址。如果CS寄存器的值不發(fā)生改變押赊,段基址部分就不會發(fā)生改變饺藤。所以我們說,CPU在合成地址的時候不區(qū)分實模式和保護(hù)模式流礁,CPU只是機(jī)械的從隱藏區(qū)域讀出來段基址和IP寄存器的數(shù)值相加涕俗。
? ? ? ?Intel這樣做的目的何在?當(dāng)然是為了效率神帅,也許實模式的地址計算很快再姑,但是保護(hù)模式計算一個地址還要有去內(nèi)存中尋找段描述符等工作,這會大大影響CPU的效率找御,而我們知道元镀,程序具有訪問局部區(qū)域里的數(shù)據(jù)和代碼的趨勢(局部性原理)。所以在CS寄存器沒有發(fā)生變化的時候霎桅,直接從之前隱藏區(qū)域獲取段基址豈不是更快栖疑?當(dāng)CS寄存器被修改呢?那CPU就再進(jìn)行一次查找段描述符的操作哆档,然后更新隱藏區(qū)域蔽挠。
? ? ? ?順便說一句,利用CPU的這個特性,我們可以先進(jìn)入CPU的保護(hù)模式配置好某個起始地址為0澳淑,段限長為4G的段描述符并加載到除過CS的其他任意寄存器(CS寄存器改變太過頻繁)比原,然后退出保護(hù)模式進(jìn)入實模式去執(zhí)行指令,利用80386之后長達(dá)32位的ESI或EDI寄存器和那個段寄存器配合尋址就可以在實模式下訪問全部地址空間了杠巡。(中途不可以修改那個載入過段描述符的寄存器量窘,否則其隱藏區(qū)域會被更新)。這種方式是一種稱之為Big Real Mode的模式氢拥,其區(qū)別于實模式和保護(hù)模式蚌铜。
? ? ? ?說了這么多,我們找張圖片大概說明一下CS寄存器嫩海。下圖來自Intel的“CPU使用說明書”冬殃,著名的那三卷開發(fā)文檔的第三卷《Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide》P91中的插圖,算是對上文的證明叁怪,至于隱藏區(qū)域有多大审葬,Intel并沒有說,不過不會短于一個段描述符的大小奕谭,也就是至少有8字節(jié)(64位)涣觉。(純屬猜測)
? ? ? ?CPU在Reset之后,IP寄存器被置為0x0000FFFF血柳,CS寄存器的段選擇器默認(rèn)值是0xF000官册,而隱藏區(qū)域中的段基址卻沒有按照實模式的標(biāo)準(zhǔn)去裝入,而是被置為0xFFFF0000难捌。那么CPU生成的第一條訪問地址是什么呢膝宁?顯而易見,80383之后的CPU合成的是0xFFFFFFF0這個地址栖榨,這也符合Intel文檔的說法昆汹。也有資料顯示從80286之后的CPU就是這個地址了,暫時沒有考證婴栽。即便是有其它文檔有不同見解满粗,還是覺得Intel的說法更靠譜,畢竟還是人家造的處理器不是愚争。
? ? ? ?再來一張圖映皆,說明下80386以上CPU在保護(hù)模式下的尋址圖,同樣來自那個PDF轰枝。
? ? ? ?所以我們說CPU執(zhí)行第一條指令的時候不是實模式也不是保護(hù)模式捅彻,而是一種怪異的中間模式。
? ? ? ? 問題又來了鞍陨,這一條指令在哪步淹?我們知道計算機(jī)開機(jī)后首先讀取哪里呢从隆?BIOS!對就是它缭裆,這一條指令會被指向BIOS键闺。
? ? ? ?我們雖然已經(jīng)假定過讀者知道線性地址空間的大致意思,但我覺得還是有必要簡單說一下澈驼,IBM PC一部分的端口采用獨立編址辛燥,而另一部分采用端口統(tǒng)一編址,傳統(tǒng)PC機(jī)使用0x000~0x3FF共1024個端口地址》炱洌現(xiàn)代PC則有多達(dá)64KB的 I/O 端口提供編址挎塌。不過顯存等一些硬件的地址還有所有BIOS的編址卻在線性地址空間里。這也是我們所謂的32位操作系統(tǒng)沒辦法完全利用4G內(nèi)存的原因内边,盡管尋址能力有4G(共2的32次方個地址)榴都,但是并不是所有的地址都能分配給內(nèi)存使用。
? ? ? ?對于傳統(tǒng)的CPU+北橋+南橋類型的主板來說漠其,CPU的地址請求通過FSB(Front Side BUS前端總線)到達(dá)北橋缭贡,北橋?qū)⑦@個請求送到南橋。而對于最新的主板芯片組來說辉懒,北橋和CPU封裝在一顆芯片里面,所以會看到這個請求通過DMI/QPI(Quick Path Interconnect谍失,即快速通道互聯(lián)眶俩,是Intel用來取代FSB的新一代高速總線,CPU與CPU之間或者CPU與北橋芯片之間都可以使用QPI相連快鱼。在民用級的i7+X58平臺颠印,i7處理器與X58北橋芯片之間就通過QPI總線相連)被送到南橋。請求到達(dá)南橋后抹竹,南橋根據(jù)目前的地址映射表的設(shè)置決定是否將請求轉(zhuǎn)發(fā)到SPI(Serial Peripheral Interface)或者LPC(Low Pin Count)线罕。
? ? ? ? 這里貌似說的過于底層了,簡單說就是南橋芯片擁有一張地址映射表窃判,當(dāng)有地址解析的請求到來時钞楼,南橋查看這張表決定將地址解析到何處去。這張表里有兩個特殊區(qū)域袄琳,一個是從地址空間4G向下询件,大小從4MB到16MB不等的一個區(qū)域,我們以4MB為例唆樊,地址空間從FFFC00000h~FFFFFFFFh宛琅。稱之為Range 4G。第二個區(qū)域一般是是從1MB向下128KB的范圍逗旁,即E Segment和F Segment嘿辟,從E0000~FFFFF,稱之為Legacy Range,也就是說红伦,F(xiàn)FFC00000hFFFFFFFFh之間和E0000FFFFF之間的尋址請求都會被導(dǎo)向到SPI/LPC英古,最終指向了BIOS。
? ? ? ?呼~說了這么多色建,這個地址總算是指向了BIOS了哺呜。解決了第一條指令,接下呢箕戳?廠商們有分歧了某残,Intel設(shè)計的EFI(Extensible Firmware Interface)的做法和傳統(tǒng)的Legacy BIOS就不一樣了。
? ? ? ?就Legacy BIOS來說陵吸,放在0xFFFFFFF0的第一條指令一般是一個遠(yuǎn)跳轉(zhuǎn)指令(far jump)玻墅,也就是說CPU在執(zhí)行Legacy BIOS時,會直接從0xFFFFFFF0跳回F Segment壮虫,回到1MB以下這個Legacy BIOS的老巢里去澳厢。而EFI BIOS的第一條指令是wbinvd(清洗CPU高速緩存),之后做一些設(shè)定之后囚似,會直接進(jìn)入保護(hù)模式剩拢。所以EFI BIOS是從南橋Region 4G通過,并不需要Legacy Region饶唤。
? ? ? ?必須說明徐伐,這里提到的一些說法參考自一些國外論文及其譯文,我只能考證其說法而沒有辦法考證原作者募狂。雖然在博文內(nèi)容上我要求自己按照論文來寫办素,但是引文上沒有辦法考證的我就只考證說法的正確性而不注明出處了,大家見諒