本系列將以一種新奇的閱讀心態(tài)閱讀和欣賞Linux 0.11的所有核心代碼,從啟動(dòng)后的代碼執(zhí)行序列中了解操作系統(tǒng)的技術(shù)細(xì)節(jié)和設(shè)計(jì)思路。
你會(huì)跟著我,看著一個(gè)操作系統(tǒng)從無(wú)到有,最后一步一步實(shí)現(xiàn)它復(fù)雜而精致的設(shè)計(jì)看完這個(gè)系列,希望你能感嘆原來(lái)操作系統(tǒng)源代碼就是這個(gè)蠢東西以下是已發(fā)表文章的列表想詳細(xì)了解這個(gè)系列,可以從開(kāi)篇的話開(kāi)始
開(kāi)場(chǎng)白
第一次輸入的前兩行代碼
第二次,給自己挪個(gè)位置。
第三遍,做最基本的準(zhǔn)備工作。
本系列GitHub地址:點(diǎn)擊此處訪問(wèn)
—正文開(kāi)始—
上一次,上一次,我們說(shuō)操作系統(tǒng)的一些最基本的準(zhǔn)備已經(jīng)準(zhǔn)備好了。
如圖,操作系統(tǒng)此時(shí)只有幾行代碼,數(shù)據(jù)段寄存器ds和代碼段寄存器cs都設(shè)置為0x9000,方便代碼跳轉(zhuǎn)和數(shù)據(jù)訪問(wèn)此外,堆棧頂部的地址ss:sp被設(shè)置為0x9FF00,距離代碼的位置0x90000足夠遠(yuǎn),以確保堆棧在下降時(shí)不會(huì)輕易撞到代碼的位置
簡(jiǎn)單來(lái)說(shuō)就是設(shè)置數(shù)據(jù)的數(shù)據(jù)段如何訪問(wèn),代碼的代碼段如何訪問(wèn),棧頂指針如何訪問(wèn),也就是做一個(gè)初步的內(nèi)存規(guī)劃從CPU的角度來(lái)看,訪問(wèn)內(nèi)存的地方只有三個(gè)
做完基礎(chǔ)工作,就該輪到新的了我們繼續(xù)往下看
load_setup:movdx,# 0x0000drive0,head0movcx,# 0x0002扇區(qū)2,track0movbx,# 0x0200地址=512,in0x9000movax,# 0x 0200+4,service2,nrofsectorsint0x13readitjncok _ load _ setupok—continuemovdx,#0x0000movax,# 0x0000resettedisketteint 0x 13 jmp load _ setup ok _ load _ setup:...
這里有兩個(gè)我們還沒(méi)見(jiàn)過(guò)的int指令。
注意,這個(gè)int是匯編指令,不是高級(jí)語(yǔ)言中的整數(shù)變量Int13表示啟動(dòng)0x13中斷在該指令中,dx,cx,bx和ax被指定為該中斷程序的參數(shù)
中斷是什么如果你不懂,就不要管它如果你就是放不下,那就看看我之前的文章:認(rèn)真談中斷,很詳細(xì)
簡(jiǎn)而言之,這個(gè)中斷發(fā)起后,CPU會(huì)通過(guò)這個(gè)中斷號(hào)找到對(duì)應(yīng)中斷處理程序的入口地址,跳轉(zhuǎn)執(zhí)行,邏輯上相當(dāng)于執(zhí)行一個(gè)函數(shù)0x13中斷的處理程序是BIOS預(yù)先寫(xiě)好的,是讀盤(pán)相關(guān)函數(shù)的函數(shù)
進(jìn)入操作系統(tǒng)內(nèi)核后,中斷處理程序需要我們自己重新編寫(xiě)在后面的章節(jié)中,你會(huì)不斷看到每個(gè)模塊都注冊(cè)了自己相關(guān)的中斷處理程序,所以不用擔(dān)心此時(shí),為了方便起見(jiàn),請(qǐng)?zhí)崆笆褂肂IOS為我們編寫(xiě)程序
可見(jiàn),即使是操作系統(tǒng)的源代碼,有時(shí)為了自身的方便也需要調(diào)用現(xiàn)成的函數(shù),并不是車(chē)輪建設(shè)者要完全從零開(kāi)始構(gòu)建。
這段代碼的注釋已經(jīng)寫(xiě)的很清楚了這么說(shuō)吧,最后的功能是啟動(dòng)硬盤(pán)第二個(gè)扇區(qū),將數(shù)據(jù)加載到內(nèi)存0x90200,一共加載四個(gè)扇區(qū)這實(shí)際上是如圖所示的情況
可以看到,如果復(fù)制成功,就會(huì)跳轉(zhuǎn)到標(biāo)簽ok_load_setup如果失敗了,你會(huì)重復(fù)執(zhí)行這段代碼,也就是再試一次那么讓我們忘記重試邏輯,只看成功后跳轉(zhuǎn)的標(biāo)簽ok_load_setup后的代碼
確定_加載_設(shè)置:...movax,#0x1000moves,ax,0x10000callread_it段...jmpi0,0x9020
這段代碼省略了很多非主邏輯代碼,比如輸出加載系統(tǒng)...屏幕上的這個(gè)字符串是為了防止用戶厭倦等待。
其余的主要代碼就寫(xiě)在這里,只有幾行它的作用是將硬盤(pán)第6扇區(qū)的240個(gè)扇區(qū)加載到內(nèi)存0x10000中,與上一個(gè)相同
至此,整個(gè)操作系統(tǒng)的所有代碼都已經(jīng)從硬盤(pán)移到了內(nèi)存中。
然后通過(guò)一個(gè)大家熟悉的段間跳轉(zhuǎn)指令jmpi0,0x9020,跳轉(zhuǎn)到0x90200,也就是硬盤(pán)第二個(gè)扇區(qū)開(kāi)頭的內(nèi)容。
這里的內(nèi)容是什么別急,借此機(jī)會(huì)說(shuō)一下整個(gè)操作系統(tǒng)的編譯過(guò)程
1.將bootsect.s編譯成bootsect,放在硬盤(pán)的1扇區(qū)。
2.把setup.s編譯成setup,放在硬盤(pán)的2~5個(gè)扇區(qū)。
3.將所有剩余的代碼編譯到系統(tǒng)中,放入硬盤(pán)的下240個(gè)扇區(qū)。
所以整個(gè)路徑是這樣的。
所以我們要跳轉(zhuǎn)到的內(nèi)存中0x90200處的代碼是從硬盤(pán)第二扇區(qū)開(kāi)始加載到內(nèi)存中的在第二個(gè)扇區(qū)的開(kāi)頭,這是setup.s文件中的第一行代碼
這是什么代碼這個(gè)我們以后再說(shuō),但是先打開(kāi)setup.s文件看一下
start:movax,# 0x9000thisisdoneinbootsectalready,butmovds,axmovah,# 0x03readcursorposxorbh,bhint0x10saveitinknownplace,con_initfetchesmov,dx,itfrom0x90000。
好了,到目前為止,你覺(jué)得,我去,前面編譯放在硬盤(pán)上的位置,和后面代碼寫(xiě)的跳轉(zhuǎn)地址耦合的這么強(qiáng)嗎如果整件事都是錯(cuò)的呢
對(duì),就是這樣你怎么想呢操作系統(tǒng)剛建立的時(shí)候,完全是自己安排的,一個(gè)字節(jié)都不能有偏差就是這么強(qiáng)的耦合,需要小心翼翼,需要大腦時(shí)刻保持清醒,規(guī)劃好自己寫(xiě)的代碼在硬盤(pán)什么地方編譯存儲(chǔ),然后會(huì)加載到內(nèi)存里,不能搞混
但也很有好處,就是在這個(gè)階段,你完全知道如何設(shè)計(jì)和規(guī)劃跳轉(zhuǎn)和數(shù)據(jù)訪問(wèn)的每一步,沒(méi)有黑箱。
不像我們寫(xiě)高級(jí)語(yǔ)言的時(shí)候,我們不知道底層幫助我們做了多少工作雖然這樣讓程序員不用擔(dān)心底層細(xì)節(jié),但是遇到問(wèn)題或者想知道原理的時(shí)候就很煩了
更何況,之所以在頂層可以為所欲為,是因?yàn)楹芏嗟讓拥募?xì)節(jié)根本不需要考慮,非常省心正是因?yàn)橄窠裉煲约爸蟮拿恳徽赂鞣N底層代碼都做了大量精心的準(zhǔn)備
好了,本文到此結(jié)束。這也標(biāo)志著我們已經(jīng)完成了第一個(gè)操作系統(tǒng)源文件bootsect.s,開(kāi)始進(jìn)入下一個(gè)文件設(shè)置. s!
我們身后的世界越來(lái)越精彩欲知后事如何,且聽(tīng)下回分解
鄭重聲明:此文內(nèi)容為本網(wǎng)站轉(zhuǎn)載企業(yè)宣傳資訊,目的在于傳播更多信息,與本站立場(chǎng)無(wú)關(guān)。僅供讀者參考,并請(qǐng)自行核實(shí)相關(guān)內(nèi)容。