 |
 |
培訓信息 |
|
|
|
 |
 |
贊助商 |
|
|
|
|
 |
 |
Linux開機過程的分析(關(guān)于bootsect.S ) |
|
|
| Linux開機過程的分析(關(guān)于bootsect.S ) |
| 作者:佚名 來源:單片機 錄入:jdzj868 更新時間:2009-8-12 16:56:29 點擊數(shù):0 |
【字體:
】 |
發(fā)信人: huzq (你快樂所以我快樂), 信區(qū): LINUX 標 題: [轉(zhuǎn)載]Linux開機過程的分析 發(fā)信站: 武漢白云黃鶴站 (Sat Feb 10 14:37:30 2001), 站內(nèi)信件 這篇文章的目的,在將linuxkernel的boot部份做一個介紹,因為筆者覺得很少有這樣的 文章介紹一個作業(yè)系統(tǒng)最最開始的一步--把kernel本身載入至內(nèi)存中,同時進行一些機 器相關(guān)(machinedependent)的初始化工作,由于linux剛好使用的是大家最熟悉的386, 486系列PC,所以在說明其程序流程時,也剛好可以對其相關(guān)的PC硬體架構(gòu)做探討,可以 說是一舉兩得,不過,我必須假設(shè)讀者對于組合語言及PC最基礎(chǔ)的架構(gòu),如寄存器,分 段,分頁,中斷服務(wù)等有大概的認識。 讀者可在linuxsourcecode的/boot子目錄下找到幾個以.S作為副檔名的組合語言檔 ,本文要說明的即是其中的bootsect.S及setup.S兩個檔案,及盡量簡單的說明其所牽涉 的相關(guān)硬體部份。 bootsect.S 這個程序是linuxkernel的第一個程序,包括了linux自己的bootstrap程序,但是在 說明這個程序前,必須先說明一般IBMPC開機時的動作(此處的開機是指"打開PC的電源" ): 一般PC在電源一開時,是由內(nèi)存中地址FFFF:0000開始執(zhí)行(這個地址一定在ROMBIO S中,ROMBIOS一般是在FEOOOh到FFFFFh中),而此處的內(nèi)容則是一個jump指令,jump到另 一個位于ROMBIOS中的位置,開始執(zhí)行一系列的動作,包括了檢查RAM,keyboard,顯示 器,軟硬磁盤等等,這些動作是由系統(tǒng)測試碼(systemtestcode)來執(zhí)行的,隨著制作BI OS廠商的不同而會有些許差異,但都是大同小異,讀者可自行觀察自家機器開機時,螢 幕上所顯示的檢查訊息。 緊接著系統(tǒng)測試碼之后,控制權(quán)會轉(zhuǎn)移給ROM中的啟動程序(ROMbootstraproutine) ,這個程序會將磁盤上的零道零扇區(qū)讀入內(nèi)存中(這就是一般所謂的bootsector,如果你 曾接觸過電腦病毒,就大概聽過它的大名),至于被讀到內(nèi)存的哪里呢?--絕對位置07C0 :0000(即07C00h處),這是IBM系列PC的特性。而位在linux開機磁盤的bootsector上的正 是linux的bootsect程序,也就是說,bootsect是第一個被讀入內(nèi)存中并執(zhí)行的程序,F(xiàn) 在,我們可以開始來看看到底bootsect做了什么。 第一步 首先,bootsect將它"自己"從被ROMBIOS載入的絕對地址0x7C00處搬到0x90000處, 然后利用一個jmpi(jumpindirectly)的指令,跳到新位置的jmpi的下一行去執(zhí)行,關(guān)鍵 的assemblycode如下: . (搬移bootsect本身) . . jmpigo,INITSEC g . . . 表示將跳到CS為0x9000,IP為offset"go"的位置(CS:IP=0x9000:offsetgo),其中I NITSEC=0x9000定義于程序開頭的部份,而go這個label則恰好是下一行指令所在的位置 。 第二步 接著,將其它segmentregisters包括DS,ES,SS都指向0x9000這個位置,與CS看齊 。另外將SP及DX指向一任意位移地址(offset),這個地址等一下會用來存放磁盤參數(shù)表 (diskpara-metertable) 提到磁盤參數(shù)表,就必須提到BIOS中斷1Eh。先簡單的介紹一下BIOS的中斷服務(wù):80 x86將內(nèi)存最低的256*4byte保留給256個中斷向量(每個interruptvector大小為4byte, 所以一共有256*4=1024byte),而其中的第1Eh個向量指向"磁盤參數(shù)表",這個表會告訴 電腦如何去讀取磁盤機,而我們所要做的事是搬移磁盤參數(shù)表到剛才所設(shè)定的任意地址 。 接著,改變搬移來的參數(shù)表的參數(shù),以符合我們的需要。再將中斷向量1Eh指向我們 所修改過的磁盤參數(shù)表,然后呼叫BIOSinterrupt的int13h(function0,即AH=0)重置磁 盤控制卡及磁盤驅(qū)動器,之后磁盤機就會照我們的意思動作了。如果你曾trace過DOS的 kernel,你會發(fā)現(xiàn),上述的動作在DOS中也有類似的對應(yīng)流程。 現(xiàn)在讓我們來看看關(guān)鍵的程序碼:. . . push#0 popfs movbx,#0x78 . (使GS:SI=FS:BX,指向磁盤參數(shù)表, 再將GS:SI所指地址的內(nèi)容搬移6個 word至ES:DI所指的地址) . . 此段程序是將FS:BX調(diào)整成0000:0078,接著再將GS:SI的內(nèi)容設(shè)成與FS:BX相同,此 處0x78h即為int1Eh的起始位置(7*16+8=120,(1*16+14)*4=120)。調(diào)整ES:DI為剛才所設(shè) 定的任意地址,從GS:SI搬移6個word(即12byte)到ES:DI所指的位置,顯然磁盤參數(shù)表的 長度就是6個word,(不過事實上,磁盤參數(shù)表的確實長度是11個byte)。關(guān)于磁盤參數(shù)表 ,有興趣的讀者可自行參閱講述BIOSinterruptservices的技術(shù)手冊,會有詳細的說明。 讀者可以用debug自行觀察自家機器上DOS的磁盤參數(shù)表的起始位置(即int1Eh的內(nèi)容 )。以下是筆者機器的情形(筆者使用的作業(yè)系統(tǒng)是MSDOS6.2): C:>debug -d0000:0000 0000:00008A101601F4067000-1600CB04F4067000......p.......p. 0000:0010F40670000301790E-43EB00F0EBEA00F0..p...y.C....... 0000:002004108E340C118E34-5700CB046F00CB04...4...4W...o... 0000:00308700CB0408079433-B700CB04F4067000.......3......p. 0000:00400C01790E4DF800F0-41F800F0BA165F06..y.M...A....._. 0000:005039E700F01B01790E-70118E341201790E9.....y.p..4..y. 0000:006000E000F085175F06-6EFE00F0EE067000......_.n.....p. 0000:007053FF00F0A4F000F0-220500003E4600C0S......."...>F.. ^^^^^^^^ 由上圖中可知,在DOS中磁盤參數(shù)表的起始位置(int1Eh的內(nèi)容)為0000:0522。接著觀察 DOS中位置0000:0522開始的11個byte,也就是磁盤參數(shù)表的內(nèi)容 C:>debug -d0000:0520l10 0000:05204D53DF022502121B-FF54F60F08000000MS..%....T...... ^^^^^^^^^^^^^^^^^^^^^^ 此11byte即為磁盤參數(shù)表的內(nèi)容(分別是byte00h到0Ah) 在程序中我們所更動的是第五個byte(byte04h),改為18h(在上圖例子中為12h),這 個byte的功能是定義磁軌上一個磁區(qū)的資料筆數(shù)。關(guān)鍵的程序碼如下: . movb4(di),*18 . 第叁步 接著利用BIOS中斷服務(wù)int13h的第0號功能,重置磁盤控制器,使得剛才的設(shè)定發(fā)揮 功能。 . . xorah,ah xordl,dl int0x13 . . 第四步 完成重置磁盤控制器之后,bootsect就從磁盤上讀入緊鄰著bootsect的setup程序, 也就是以后將會介紹的setup.S,此讀入動作是利用BIOS中斷服務(wù)int13h的第2號功能。 setup的image將會讀入至程序所指定的內(nèi)存絕對地址0x90200處,也就是在內(nèi)存中緊鄰著 bootsect所在的位置。待setup的image讀入內(nèi)存后,利用BIOS中斷服務(wù)int13h的第8號功 能讀取目前磁盤機的參數(shù)。 第五步 再來,就要讀入真正linux的kernel了,也就是你可以在linux的根目錄下看到的"v mlinuz"。在讀入前,將會先呼叫BIOS中斷服務(wù)int10h的第3號功能,讀取游標位置,之 后再呼叫BIOS中斷服務(wù)int10h的第13h號功能,在螢?zāi)簧陷敵鲎址?Loading",這個字 符串在bootlinux時都會首先被看到,相信大家應(yīng)該覺得很眼熟吧。 linux的kernel將會被讀入至內(nèi)存絕對地址0x10000處,鍵關(guān)的程序碼如下: . . movax,#SYSSEG moves,ax callread_it callkill_motor . . 其中SYSSEG于程序開頭時定義為0x1000,先將ES內(nèi)容設(shè)為0x1000,接著在read_it這 個子程序便以ES為目的地的節(jié)地址,將kernel讀入內(nèi)存中,至于read_it子程序的詳細內(nèi) 容筆者并不想一一介紹,不過聰明的讀者們應(yīng)該已經(jīng)猜到,read_it一定又利用了BIOSi nt13h與磁盤有關(guān)的I/O中斷服務(wù)了。 至于kill_motor子程序,它的功能在于停止軟盤機的馬達(各位聰明的讀者會不會覺 得這個子程序的名稱取得頗為傳神呢?),其程序碼如下: . . kill_motor: pushdx movdx,#0x3f2 xoral,al outb popdx ret . . 首先利用DX指定要輸出的port,而03f2這個port則是代表了軟盤控制器(floppydis kcontroller)的所在,再利用outb將資料送出,而我們送出的資料,當然就是歸零過的 AL了。如此一來,軟盤的馬達就停止了。 第六步 接下來做的事是檢查rootdevice,之后就仿照一開始的方法,利用indirectjump跳
至剛剛已讀入的setup部份,程序碼如下: . . jmpi0,SETYPSEG 其中SETUPSEG已在先前定義為0x9020,所以CS:IP會設(shè)定為9020:0000,即跳到絕對 地址為0x90200,也就是setup的起點。而bootsect也大功告成了。 到此為止,內(nèi)存的內(nèi)容應(yīng)該如下圖所示: 比較 把大家所熟知的MSDOS與linux的開機部份做個粗淺的比較,MSDOS由位于磁盤上boo tsector的boot程序負責把IO.SYS載入內(nèi)存中,而IO.SYS則負有把DOS的kernel--MSDOS. SYS載入內(nèi)存的重責大任。而linux則是由位于bootsector的bootsect程序負責把setup及 linux的kernel載入內(nèi)存中,再將控制權(quán)交給setup。 至于setup.S,就留到下一次再來討論了。
|
|
|
發(fā)表評論 告訴好友 打印此文 收藏此頁 關(guān)閉窗口 返回頂部 |
|
|
 |
 |
網(wǎng)友評論:(只顯示最新5條。) |
|
|
|
|
|