一步步編寫操作系統 08 bios跳轉到神奇的內存地址0x7c00

爲什麼是0x7c00

計算機執行到這份上,bios也即將完成自己的歷史使命了,完成之後,它又將睡去。想到這裏,心中不免一絲憂傷,甚至有些許挽留它的想法。可是,這就是它的命,它生來被設計成這樣,在它短暫的一生中已經爲後人創造了足夠的精彩。何況,在下一次開機時,bios還會重複這段輪迴,它並沒有消失。好了,讓傷感停止,讓夢想前行。

先說重點,bios最後一項工作校驗啓動盤中,位於0盤0道1扇區的內容。在此插播一段小告示:在計算機中是習慣以0做爲起始索引的,因爲人們已經習慣了偏移量的概念,無論是機器眼裏和程序員眼裏,用“相對”的概念,即偏移量來表示位置顯得很直觀,所以很多指令中的操作數都是用偏移量表示的。0盤0道1扇區本質上就相當於0盤0道0扇區。爲什麼稱爲1呢,因爲硬盤扇區的表示法有兩種,我們描述0盤0道1扇區用的便是其中的一種:CHS方法,即柱面Cylinder 磁頭Header 扇區Sector(另外一種是LBA方式,暫不關心),“0盤”說的是0磁頭,因爲一張盤是有上下兩個盤面的,一個盤面上對應一個磁頭,所以用磁頭Header來表示盤面。“0道”是指0柱面,柱面Cylinder指的是所有盤面上、編號相同的磁道的集合,形象一點描述就是把很多環疊摞在一起的樣子,組合在一起之後是一個立體的管狀。“1扇區”纔是我們要解釋的部分,將磁道等距劃分成一段段的小區間,由於磁道是圓形,確切地說是圓環,所以這些被劃分出來的小區間便是扇形,所以稱爲扇區。好了,背景交待完了,重點來了,在CHS方式中扇區的編號是從1開始的,不是0,不是0,原諒我說了兩次,良苦用心你懂的,所以0盤0道1扇區是其實就相當於0盤0道0扇區,它就是磁盤上最開始的那個扇區。而LBA方式中,扇區編號是從0開始的。關於硬盤的知識我會在以後章節專門來講,這裏我若沒表達清楚,大家先不要着急,只要知道MBR所在的位置是磁盤上最開始的那個扇區就行了。繼續說,如果此扇區末尾的兩個字節分別是魔數0x55和0xaa,bios便認爲此扇區中確實存在可執行的程序(在此先劇透一下,此程序便是久聞大名的主引導記錄MBR),便加載到物理地址0x7c00,隨後跳轉到此地址,繼續執行。

這裏有個小細節,bios跳轉到0x7c00是用jmp 0:0x7c00實現的,這是jmp指令的直接絕對遠轉移用法,段寄存器cs會被替換,這裏的段基址是0,即cs由之前的0xf000變成了0。如果此扇區的最後2個不是0x55和0xaa,即使裏面有可執行代碼也無濟於事了,bios不認,它也許還認爲此扇區是沒格乾淨呢,嘿嘿。

不過,這就又拋出兩個問題:

  1. 1.爲什麼是0盤0道1扇區的內容。
  2. 2.爲什麼是物理地址0x7c00而不是個好記或好看的其它地址。

先回答第1個,我想這個問題不用官方解釋了,因爲官方確實沒什麼好說的,不過他們出於尊重客戶,還是會像我一樣說出類似下面的話。

我就個人觀點給大家一個理由,未經覈實,僅是自己一面之詞,請大家提高警惕,小心謹慎^—^。

在計算機中處處充滿了協議、約定,所以,將0盤0道1扇區做爲mbr的棲身之地,我完全可以理解爲規定。我們反證一下,如果不存在這個“規定”,會發生什麼。當然,此扇區最初是給bios使用的,咱們設想一下bios的工作將變成怎樣。

主引導記mbr是段程序,無論是位於軟盤、硬盤、或者其它介質,總該有個地方保存它。Ok,現在不告訴bios 它存儲在哪個位置了。bios只好將所有檢測到的存儲設備上的每一個存儲單位都翻一遍,挨個對比,如果發現該存儲單位最後的兩個字節是0x55和0xaa,就認爲它mbr。這就好比查字典一樣,不用偏旁部首和拼音檢索的方法,只能一頁一頁翻了。

幾經花開花落,找到mbr的那一刻,bios滿臉疲憊地說:“你是我找了好久好久的那個人”。mbr擡起經不起歲月等待的臉:“難得你還認得我,我等你等到花兒都謝了”。其實bios的心聲是:“看我手忙腳亂的樣子,你們這是要鬧哪樣啊。就那麼512字節的內容,害我找遍全世界,我們是在跑接力賽啊,下一棒的選手我都不知道在哪裏……以後讓它站在固定的位置等我!”。

由於0盤0道1扇區是磁盤的第一個扇區,mbr選擇了離bios最近的位置站好了,從此以後再也不擔心被bios罵了。

計算機中處處有固定寫死的東西,還用舉個例子嗎?不用了吧?因爲任何一個魔數都是啊^_^,有請下一個魔數0x7c00登場。

至於0x7c00,很久之前,比我好奇心大的人查遍了intel開發手冊都沒找到相關的說明。要想知道事情的來龍去脈,還是要從個人電腦的老祖宗說起,同樣是很久很久以前……1981年8月,IBM公司生產了世界上第一臺個人電腦PC 5150,所以它就是現代x86個人電腦兼容機的祖先。說到有關歷史的東西,不給來點真相就感覺氣場不足,上圖啦,這是IBM PC 5150,有沒有感受到計算機文化底蘊呢。

一步步編寫操作系統 8  bios跳轉到神奇的內存地址0x7c00

 

既然intel開發手冊中沒有相關說明,那咱們就朝其它方向找答案,換句話說,既然不是cpu的硬性規定,那很可能就是代碼中寫死的。爲了搞清楚0x7c00是哪裏來的,咱們先探索下 "IBM PC 5150"的bios的祕密。請先深深呼吸一大口氣,“0x7C00”最早出現在IBM 公司出產的個人電腦PC5150的ROM BIOS的 INT19H中斷處理程序中,說了這麼多定語,感覺氣都喘不上來了。

通電開機之後,bios處理程序開始自檢,隨後,調用bios中斷0x19h,即 call int 19h。在此中斷處理函數中,bios要檢測這臺電腦有多少硬盤或軟盤,如果檢測到了任何可用的磁盤,bios就把它的第一個扇區加載到0x7c00.

現在應該搞清楚了爲什麼在x86手冊裏找不到它的說明了,它是屬於bios中的規範。似乎這下好辦了,既然是bios中的規範,那肯定是IBM PC 5150 BIOS 開發團隊規定的這個數。

個人計算機肯定要運行操作系統,在這臺計算機上,運行的操作系統是DOS 1.0,不清楚此係統要求的最小內存是16KB還是32KB,反正PC 5150 BIOS研發工程師就假定其是32K,所以此版本bios是按最小內存32KB研發的。

MBR不是隨便放在哪裏都行的,首先不能覆蓋已有的數據,其次,不能過早的被其它數據覆蓋。不覆蓋已有數據,這個好理解。說一下後面這個“其次”。通常,MBR的任務是加載某個程序(這個程序一般是內核加載器,很少有直接加載內核的)到指定位置,並將控制權交給它。所謂的交控制權就是jmp過去而已。之後MBR就沒用了,被覆蓋也沒關係。我說的過早被覆蓋,是指不能讓mbr破壞自己,比如被加載的程序,如內核加載器,其放置的內存位置若是MBR自己所在的範圍,這不就是破壞自己了嗎,這就是我所說的“過早”了,怎麼也得等mbr執行完才行。

重現一下當時的內存使用情況:8086cpu要求物理地址0x0~0x3FF存放中斷向量表,所以此處不能動了,再選新的地方看看。按DOS 1.0要求的最小內存32KB來說,MBR希望給人家儘可能多的預留空間,這樣也是保全自己的作法,免得過早被覆蓋。所以MBR只能放在32KB的末尾。MBR本身也是程序,是程序就要用到棧,棧也是在內存中的,所以MBR雖然本身只有512字節,但還要爲其所用的棧分配點空間,所以其實際所用的內存空間要大於512字節,估計1k內存夠用了。結合以上三點,選擇32KB中的最後1K最爲合適,那此地址是多少呢。32KB換算爲16進製爲0x8000,減去1K(0x400)的話,等於0x7c00。這就是倍受質疑的0x7c00的由來,這下清楚了。可見,加載MBR的位置是取決於操作系統本身所佔內存大小和內存佈局。

我想大家現在都心癢癢了吧,說了這麼久,cpu中運行的都是bios的代碼,連自己一句代碼都沒跑起來呢。事不宜遲,馬上寫一個MBR,先讓它跑起來再說。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章