編寫MBR從硬盤啓動linux0.11

 

計算機啓動時BIOS會把啓動盤第一個扇區的數據讀入內存0x7C00開始處,然後跳到這裏繼續執行。從硬盤啓動和從軟盤啓動唯一的區別就是映象文件存儲方式的不同:

1. 對於從軟盤啓動的方式,映象文件連續地存放在軟盤開始的位置處。放在第一個扇區的bootsect.s被BIOS讀入內存後,就會把餘下的映象文件讀入內存,然後繼續執行

2. 對於從硬盤啓動的方式,映象文件存放在Minix格式的硬盤分區裏,MBR(硬盤第一個扇區)中的程序需要根據硬盤的參數和Minix文件系統的存儲格式讀出它

本文描述瞭如何編寫MBR中的程序,把存放在硬盤第一個分區根目錄下的linux0.11映像文件Image讀入內存。

文章中小字體的括號裏的數字表示參考文獻的編號(見後面的參考文獻列表)。

本文分5個部分: 1、硬盤簡介

2、Minix 1.0文件系統簡介

3、程序流程

4、上機實驗

5、程序代碼(以附件形式給出)

一.硬盤簡介(1)

圖1. 硬盤扇區編號(此圖來源文獻1)

我們需要了解的是物理扇區編號方式和絕對扇區編號方式。物理扇區號直接按柱面、磁頭、扇區3者的組合來定位某個扇區。對於硬盤的第一個扇區,其編號爲“0柱面0磁頭1扇區”。我們假設硬盤磁頭數爲16,每磁道扇區數爲63,下面描述遍歷整個硬盤時柱面號、磁頭號、扇區號的變化規律(以(x,y,z)表示x柱面y磁頭z扇區): (0,0,1)、(0,0,2)、……、(0,0,63)、

(0,1,1)、(0,1,2)、……、(0,1,63)、

(0,2,1)、(0,2,2)、……、(0,2,63)、

……

(0,15,1)、(0,15,2)、……、(0,15,63)、

(1,0,1)、(1,0,2)、……、(1,0,63)、

(1,1,1)、(1,1,2)、……、(1,1,63)、

換句話說就是扇區號是從1到63的63進制,磁頭號是0到15的16進制,“百位”是柱面號,“十位”是磁頭號,“個位”是扇區號。

絕對扇區號從0開始,遍歷硬盤時依次增1。

兩者的換算關係如下(abs_sector表示絕對扇區號,cyl表示柱面號,head表示磁頭號,sector表示扇區號,nheads表示磁頭數,nspt表示每磁道扇區數):

sector = abs_sector % nspt + 1

track = abs_sector / nspt

head = track % nheads

cyl = track / nheads

如何知道上面說的磁頭數nheads、每磁道扇區數nspt呢?啓動時BIOS會把硬盤參數表放在內存某個位置。對於第一個硬盤,硬盤參數表的首地址放在中斷0x41處,即內存地址4*0x41=0x104開始的4個字節表示硬盤參數表的段地址(後面2字節)和偏移地址(前面2字節)。硬盤參數表的結構如下:

dw cylinders

db nheads

dw 0

dw write pre-comp

db 0

db 0 "control byte"

db 0, 0, 0

dw landing zone

db nspt(sectors/track)

db 0

第二個硬盤的參數表地址放在BIOS中斷向量0x46處。

對於硬盤,我們還需要稍微知道一點分區表的信息。分區表放在硬盤第一個扇區的0x1be~0x1fd處(共64字節,第一個分區的信息在0x1be~0x1ce)。我們需要使用的僅僅是存放在0x1c6處的“分區起始絕對扇區號”(對應於程序中的start_sect變量)

二.Minix 1.0文件系統簡介(2) (3)

關於Minix 1.0文件系統的更詳細知識請參考文獻2、3,下面僅介紹理解本程序需要了解的知識。

Minix 1.0格式的分區結構如下:

引導塊

超級塊

i點位圖塊…

邏輯塊位圖塊…

i節點塊…

數據區………

1、對於Minix 1.0,每個盤塊佔1k字節(即2個扇區)。引導塊的第一個扇區就是本分區的第一個扇區,扇區號存在MBR中0x1c6處(就是上文的“分區起始絕對扇區號”)。盤塊從0開始編號,對於盤塊n,其絕對扇區號 = 2*n +分區起始絕對扇區號。

2、i點位圖塊和邏輯塊位圖塊的大小、數據區的起始盤塊號等信息存放在超級塊中,超級塊的數據結構如下:

struct d_super_block{

unsigned short s_ninodes; //節點數

unsigned short s_nzones; //邏輯塊數

unsigned short s_imap_blocks; //i節點位圖所佔用的數據塊數

unsigned short s_zmap_blocks; //邏輯塊位圖所佔用的數據塊數

unsigned short s_firstdatazone; //第一個數據邏輯塊

unsigned short s_log_zone_size; //log2(數據塊數/邏輯塊)

unsigned long s_max_size; //文件最大長度

unsigned short s_magic;}; //文件系統魔數

我們只需要知道開始存放i節點的盤塊號inode_start_zone和第一個數據邏輯塊號firstdatazone:

inode_start_zone = 2 + s_imap_blocks + s_zmap_blocks

firstdatazone = s_firstdatazone

3、每個i節點佔32字節,其數據結構如下:

struct d_inode{

unsigned short i_mode; //文件類型和屬性

unsigned short i_uid; //用戶id

unsigned long i_size; //文件大小(字節數)

unsigned long i_time; //修改時間(1970.1.1:0算起,秒)

unsigned char i_gid; //組id

unsigned char i_nlinks; //鏈接數

unsigned short i_zone[9];}; //直接(0~6)、間接(7)、雙重間接

//(8)邏輯塊號

根據其中的i_size可以計算出文件佔用的盤塊數 = (i_size + 1023) / 1024

文件數據的前面7k存放在稱爲直接塊的7個盤塊中,這7個盤塊的盤塊號存在i_zone[0]~i_zone[6]中。如果文件大於7k,則需要使用到一次間接塊(i_zone[7]),它對應的盤塊裏存放的不是文件數據,而是7k之後的文件數據存放的盤塊號。比如一次間接塊的第1、2字節指出第8k文件數據存放的盤塊號碼。一次間接塊可以存放512個盤塊號。如果文件大於(512+7)k,則需要使用二次間接塊i_zone[8]。圖示如下:

圖2. 文件數據存儲結構(此圖來源文獻3)

根據i_zone[0]~i_zone[6],可以直接讀出前面7k數據;然後讀出一次間接塊i_zone[7],根據其中的盤塊號即可讀出其餘的數據;忽略i_zone[8],因爲linux0.11映像文件沒那麼大。

圖3是映像文件Image一次間接塊的前面部分數據。每兩個字節表示一個盤塊號。“00 00”表示這1k的數據都是0(比如紅圈裏的),藍圈裏的“70 05”表示這1k數據存放的盤塊號是0x0570。

圖3. 映像文件Image一次間接塊的前面部分數據

4、第一個數據塊存放的就是根目錄文件的前1k數據,根目錄文件存放的是稱爲目錄項的信息。其數據結構如下:

struct dir_entry{

unsigned short inode; //i節點

char name[14];}; //文件名

圖4就是根目錄文件第一個盤塊的部分信息,圖中紅圈裏面的數據表示本本目錄項的i節點,藍圈裏面的數據表示該目錄形的名稱是Image。從圖上我們可以看到,前面兩個目錄項分別是目錄“.”和目錄“..”,緊隨其後的是bin、dev、etc、mnt、root、tmp、usr等目錄,再後面的是hello.c、Image、image文件(至於是目錄還是文件,需要找出相應的i節點根據其i_mode項來判斷)。

圖4. 根目錄文件第一個數據塊部分信息

三.程序流程

現在可以描述查找映像文件並讀出它的過程了:

a. 獲取硬盤參數——磁頭數、每磁道扇區數(以便計算絕對扇區號對應的柱面號、磁頭號、扇區號),獲取分區參數——第一個分區起始絕對扇區號(以定位Minix文件系統的邏輯塊)

b. 讀出超級塊,計算出i節點開始存放的盤塊號inode_start_zone和第一個數據邏輯塊號firstdatazone

c. 讀出根目錄文件(本程序只讀出了它前面的1k數據——即第一個數據邏輯塊)

d. 根據映像文件名Image找到對應的目錄項,取得其i節點編號(0x004A,圖4紅圈部分)

e. 根據映像文件i節點編號和inode_start_zone讀出i節點

f. 根據i節點的i_size信息確定要讀取的盤塊數,根據i_zone[0]~i_zone[6]讀出前面7k數據

g. 根據i_zone[7]讀出一次間接塊的數據

h. 根據一次間接塊確定的盤塊號,讀出

linux0.11映像文件由4部分組成:1、bootsect.s,2、setup.s,3、head.s,4、系統模塊。從軟盤啓動時,bootsect.s生成的可執行代碼(512字節)被讀入0x7C00處,它執行時先把自己移到0x90000處,然後把setup.s生成的可執行代碼(大小爲2k)從軟盤讀入到內存0x90200處,並把映像文件餘下部分讀到內存0x10000處。本MBR程序把映像文件前面2.5k數據(對應512字節的bootsect.s可執行代碼和2k的setup.s可執行代碼)讀到0x90000處,把映像文件餘下部分讀到內存0x10000處,然後跳到0x90200執行setup.s代碼。可見,本程序的功能只是與bootsect.s相似,bootsect.s從軟盤讀出映像文件,而本程序從硬盤中讀出。

程序代碼見第5部分的bootload.s,圖5是流程圖。

圖5. MBR程序流程圖

四.上機實驗

實驗工具:

1、Bochs PC仿真軟件上運行的SLS-Linux

下載地址:

http://oldlinux.org/Linux.old/bochs/sls-1.0.zip

2、linux-0.11-devel-040809.zip壓縮包(裏面有Bochs安裝程序)

下載地址:

http://oldlinux.org/Linux.old/bochs/linux-0.11-devel-040809.zip

3、DOS格式映像文件工具WinImage

下載地址:

http://ourworld.compuserve.com/homepages/gvollant/winima70.exe

實驗步驟:

hdc-0.11.img硬盤映像文件上有linux0.11根文件系統,但現在它不能引導linux0.11:把bochsrc-hd.bxrc文件中的“boot:a”改爲“boot:c”,運行bochsrc-hd.bxrc將導致引導失敗。下面修改其MBR使得可以引導:

1、把sls-1.0.zip和linux-0.11-devel-040809.zip解壓到同一個目錄下,安裝Bochs2.1.1。

2、用文本編輯器打開bochsrc.bxrc,把69行“floppyb:1_44=tmp1.imz, status=inserted”中的tmp1.imz改爲tmp.imz(原文有誤)

3、在bochsrc.bxrc中添加一行,掛接hdc-0.11.img:

“ata0-slave: type=disk, path="hdc-0.11.img", mode=flat, cylinders=121, heads=16, spt=63”

4、使用WimImage打開tmp.imz,把我們所寫的MBR程序bootload.s和makefile拖入,保存

5、雙擊運行bochsrc.bxrc,按空格鍵進入,使用root登錄

6、運行如下命令將linux0.11映像文件複製到hdb1的根目錄下:

mount /dev/hdb1 /mnt

cp /mnt/usr/src/linux/Image /mnt/Image

7、下面把存在b盤(即tmp.imz軟盤映像)中的bootload.s和makefile複製出來:

mkdir asm

cd asm

mcopy b:\makefile makefile

mcopy b:\bootload.s bootload.s

8、彙編、鏈接bootload.s,把可執行代碼寫到hdb1的MBR中去:

make //參考附錄makefile文件的說明

9、退出:

umount /mnt

關閉Bochs

步驟6~9的運行界面如圖6

圖6. 修改硬盤映像文件MBR

10、修改bochsrc-hd.bxrc,把boot:a改爲boot:c,雙擊運行。成功!界面如下:

圖7. 從硬盤啓動linux0.11

五.程序代碼

見隨本文件發佈的附件(一個是MBR程序bootload.s,一個是makefile文件)

參考文獻:

1、《帶您深入瞭解硬盤分區表與邏輯鎖

作者:邁克爾

來源:家緣硬件網

日期:2005.1.9

鏈接:

http://www.pcnethome.com/Article/NEWS/skill/200501/1037.html

2、《Linux0.11學習體會》

作者:chenfangjian

來源:http://www.oldlinux.org/論壇子論壇“Linux內核完全註釋

鏈接:

http://www.oldlinux.org/cgi-bin/LB5000XP/topic.cgi?forum=1&topic=1507

3、《Linux內核完全註釋》

作者:趙炯

機械工業出版社

4、 http://www.oldlinux.org/論壇子論壇“Linux 0.11系統的建立和實驗” 上linuxlala 回覆的一篇帖子,他詳細描述了編寫linux0.11引導程序的方法。

鏈接:

http://www.oldlinux.org/cgi-bin/LB5000XP/topic.cgi?forum=4&topic=226

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