如何編寫自己的操作系統(tǒng)_第1頁
如何編寫自己的操作系統(tǒng)_第2頁
如何編寫自己的操作系統(tǒng)_第3頁
如何編寫自己的操作系統(tǒng)_第4頁
如何編寫自己的操作系統(tǒng)_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

如何編寫自己的操作系統(tǒng)

2008年10月15日星期三09:51

如何編寫自己的操作系統(tǒng)

有人可能擔(dān)心自己既沒有學(xué)過計算機原理,也沒有學(xué)過操作系統(tǒng)原理,更不懂匯編語言,

對C語言也一知半解,能寫操作系統(tǒng)嗎?答案是沒問題。我將帶大家一步一步完成自己的操作系統(tǒng)。

當(dāng)然如果學(xué)一學(xué)上述內(nèi)容再好不過。

首先要明確處理器(也就是CPU)控制著計算機。對PC而言,啟動的時候,CPU都處在實模式狀態(tài),

相當(dāng)于只是一個Intel8086處理器。也就是說,即使你現(xiàn)在擁有一個奔騰處理器,它的功能也只能

是8086級別。從這一點上來講,可以使用一些軟件把處理器轉(zhuǎn)換到著名的保護模式。只有這樣,

我們才可以充分利用處理器的強大功能。

編寫操作系統(tǒng)開始是對BIOS控制,取出存儲在ROM里的程序。BIOS是用來執(zhí)行POST(PowerOnSelfTest,

自檢)的。自檢是檢查計算機的完整性(比如外設(shè)是否工作正常、鍵盤是否連接等)。這一切完成以后,

你就會聽到PC喇叭發(fā)出一聲清脆的響聲。如果一切正常,BIOS就會選擇一個啟動設(shè)備,

并且讀取該設(shè)備的第一扇區(qū)(即啟動扇區(qū)),然后控制過程就會轉(zhuǎn)移到指定位置。

啟動設(shè)備可能是一個軟盤、光盤、硬盤,或者其它所選擇的設(shè)備。在此我們把軟盤作為啟動設(shè)備。

如果我們已經(jīng)在軟盤的啟動扇區(qū)里寫了一些代碼,這時它就被執(zhí)行。因此,我們的目的很明確,

就是往軟盤的啟動扇區(qū)寫一些程序。

首先使用8086匯編來寫一個小程序,然后將其拷貝至軟盤的啟動扇區(qū)。為了實現(xiàn)拷貝,要寫一個C程序。

最后,使用軟盤啟動計算機。

需要的工具

●as86:這是一個匯編程序,它負(fù)責(zé)把寫的代碼轉(zhuǎn)換成目標(biāo)文件。

●ld86:這是一個連接器,as86產(chǎn)生的目標(biāo)代碼由它來轉(zhuǎn)換成真正的機器語言。

機器語言是8086能夠解讀的形式。

●GCC:著名的C編程器。因為我們需要寫一個C程序?qū)⒆约旱腛S轉(zhuǎn)移到軟盤中。

●一張空軟盤:它用于存儲編寫的操作系統(tǒng),也是啟動設(shè)備。

●一臺裝有Linux的計算機:這臺機器可以很舊,386、486都可以。

在大部分標(biāo)準(zhǔn)Linux發(fā)行版中都會帶有as86和ld86。在我使用的RedHat7.3中就包含有這兩個工具,

并且在默認(rèn)的情況下,它已經(jīng)安裝在機器里。如果使用的Linux沒有這兩個工具,可以從網(wǎng)上下載

(http://www.cix.co.uk/~mayday/),這兩個工具都包含在一個名為bin86的軟件包中。

此外,有關(guān)的文檔也可以在網(wǎng)上獲得(/docs/ldp/howto/Assembly-HOWTO/as86.html)。

開始工作

使用一個你喜歡的編輯器輸入以下內(nèi)容:

entrystart

start:

movax,#0xb800

moves,ax

seges

mov[0],#0x41

seges

mov[1],#0x1f

loop1:jmploop1

這是as86可以讀懂的一段匯編程序。第一個句子指明了程序的入口點,聲明整個過程從start處開始。

第二行指明了start的位置,說明整個程序要從start處開始執(zhí)行。0xb800是顯存的開始地址。

#表明其后是一個立即數(shù)。執(zhí)行語句:

movax,#oxb800

ax寄存器的值就變?yōu)?xb800,這就是顯存的地址。下面再將這個值移至es寄存器,es是附加段寄存器。

請記住8086有一個分段的體系結(jié)構(gòu)。它的各段寄存器為代碼段、數(shù)據(jù)段、堆棧段和附加段,

對應(yīng)的寄存器名稱分別為cs、ds、ss和es。事實上,我們把顯存地址送入了附加段,因此,

任何送入附加段的東西都會被送到顯存中。

要在屏幕上顯示字符,就需要向顯存中寫兩個字節(jié)。前一個是所要顯示字符的ASCⅡ值,

第二個字節(jié)表示該字符的屬性。屬性包括字符的前景色、背景色及是否閃爍等等。

seges指明下一個將要執(zhí)行的指令是指向es段的。所以,我們把值0x41(在ASCⅡ中表示的字符是A)送到

顯存的第一個字節(jié)中。接下來要把字符的屬性送到下一個字節(jié)當(dāng)中。在此輸入的是0x1f,

該屬性指的是在藍(lán)色背景下顯示白色的字符。因此,如果執(zhí)行這個程序,

就可以在屏幕上得到顯示在藍(lán)底上的一個白色的A。接著是一個循環(huán)。

因為在執(zhí)行完顯示字符的任務(wù)后,要么讓程序結(jié)束,要么使用一個循環(huán)使其永遠(yuǎn)運行下去。

把該文件命名為boot.s,然后存盤。

--------------------------------------------------------------------------------

2如何編寫自己的操作系統(tǒng)

此處顯存的概念說得不是很清楚,有必要進一步解釋一下。假設(shè)屏幕由80列×25行組成,

那么第一行就需要160字節(jié),其中一個字節(jié)用于表示字符,另外一個字節(jié)用于表示字符的屬性。

如果要在第三行顯示某一字符的話,就要跳過顯存的第0和1字節(jié)(它們是用于顯示第1列的),

第2和3字節(jié)(它們是用于顯示第2列的),然后把需要顯示字符的ASCⅡ碼值入第4字節(jié),

把字符的屬性寫入第5字節(jié)。

把程序?qū)懼羻由葏^(qū)

下面寫一個C程序,把我的操作系統(tǒng)寫入軟盤第一扇區(qū)。程序內(nèi)容如下:

#include/*unistd.h需要這個文件*/

#include/*包含有read和write函數(shù)*/

#include

intmain()

{

charboot_buf[512];

intfloppy_desc,file_desc;

file_desc=open("./boot",O_RDONLY);

read(file_desc,boot_buf,510);

close(file_desc);

boot_buf[510]=0x55;

boot_buf[511]=0xaa;

floppy_desc=open("/dev/fd0",O_RDWR);

lseek(floppy_desc,0,SEEK_CUR);

write(floppy_desc,boot_buf,512);

close(floppy_desc);

}

首先,以只讀模式打開boot文件,然后在打開文件時把文件描述符復(fù)制到file_desc變量中。

從文件中讀取510個字符,或者讀取直到文件結(jié)束。在本例中由于文件很小,所以是讀取至文件結(jié)束

。然后關(guān)閉文件。

最后4行代碼打開軟盤驅(qū)動設(shè)備(一般來說是/dev/fd0)。使用lseek找到文件開始處,

然后從緩沖中向軟盤寫512個字節(jié)。

在read、write、open和lseek的幫助頁中,可以看到與函數(shù)所有有關(guān)的參數(shù)及其使用方法。

程序中有兩行比較難懂:

boot_buf[510]=0x55;

boot_buf[511]=0xaa;

該信息是用于BIOS的,如果它識別出該設(shè)備是一個可啟動的設(shè)備,那么在第510和511的位置,

該值就應(yīng)該是0x55和0xaa。程序會把文件boot讀至名為boot_buf的緩沖中。

它要求改變第510和第511字節(jié),然后把boot_buf寫至軟盤之上。如果執(zhí)行代碼,

軟盤上的前512字節(jié)就包含了啟動代碼。最后,把文件存為write.c。

編譯運行

使用下面的命令把文件變?yōu)榭蓤?zhí)行文件:

as86boot.s-oboot.o

ld86-dboot.o-oboot

ccwrite.c-owrite

首先將boot.s文件編譯成目標(biāo)文件boot.o,然后將該文件連接成最終的boot文件。

最后C程序編譯成可執(zhí)行的write文件。

插入一個空白軟盤,運行以下程序:

./write

重新啟動電腦,進行BIOS的界面設(shè)置,并且把軟盤設(shè)為第一個啟動的設(shè)備。然后插入軟盤,

電腦從軟盤上啟動。

啟動完成后,在屏幕上可以看到一個字母A(藍(lán)底白字),啟動速度很快,幾乎是在瞬間完成。

這就意味著系統(tǒng)已經(jīng)從我們制作的軟盤上啟動了,并且執(zhí)行了剛才寫入啟動扇區(qū)的程序。

現(xiàn)在,它正處在一個無限循環(huán)的狀態(tài)。所以,如果想進入Linux,必需拿掉軟盤,并且重啟機器。

至此,這個操作系統(tǒng)就算完成了,雖然它沒有實現(xiàn)什么功能,但是它已經(jīng)可以啟動機器了。

下一期我將在這個啟動扇區(qū)程序里加入一些代碼,使它可以做一些比較復(fù)雜的事情

(比如使用BIOS中斷、保護模式切換等等)。

自己動手寫操作系統(tǒng)(二)

作者:伊梅

上一期,我講述了如何在軟盤的啟動扇區(qū)寫一些代碼,然后再從軟盤啟動的過程。

制作好一個啟動扇區(qū),在切換到保護模式之前,我們還應(yīng)該知道如何使用BIOS中斷。

BIOS中斷是一些由BIOS提供的、為了使操作系統(tǒng)的創(chuàng)建更容易的低級程序。在本文中,

我們將學(xué)習(xí)處理BIOS的中斷。

為什么要用BIOS

BIOS會把啟動扇區(qū)拷貝至RAM中,并且執(zhí)行這些代碼。除此之外,BIOS還要做很多其它的事情。

當(dāng)一個操作系統(tǒng)剛開始啟動時,系統(tǒng)中并沒有顯卡驅(qū)動、軟盤驅(qū)動等任何驅(qū)動程序。

因此,啟動扇區(qū)中不可能包含任何一個驅(qū)動程序,我們要采取其它的途徑。

這個時候,BIOS就可以幫助我們了。BIOS中包含有各種可以使用的程序,

包括檢測安裝的設(shè)備、控制打印機、計算內(nèi)存大小等用于各種目的的程序。

這些程序就是所說的BIOS中斷。

--------------------------------------------------------------------------------

3如何編寫自己的操作系統(tǒng)

如何調(diào)用BIOS中斷

在一般的程序設(shè)計語言中,函數(shù)的調(diào)用是一件非常容易的事情。比如在C語言中,

如果有一個名為display的程序,它帶有兩個參數(shù),其中參數(shù)noofchar表示顯示的字符數(shù),

參數(shù)attr表示顯示字符的屬性。那么要調(diào)用它,只需給出程序的名稱即可。對于中斷的調(diào)用

,我們使用的是匯編語言中的int指令。

比如,在C語言中要顯示一些東西時,使用的指令如下所示:

display(nofchar,attr);

而使用BIOS時,要實現(xiàn)相同功能使用的指令如下:

int0x10

如何傳遞參數(shù)

在調(diào)用BIOS中斷之前,我們需要先往寄存器中送一些特定的值。假設(shè)要使用BIOS的中斷13h,

該中斷的功能是把數(shù)據(jù)從軟盤傳送至內(nèi)存之中。在調(diào)用該中斷之前,要先指定拷貝數(shù)據(jù)的段地址

,指定驅(qū)動器號、磁道號、扇區(qū)號,以及要傳送的扇區(qū)數(shù)等等。然后,就要往相應(yīng)的寄存器送入

相應(yīng)的值。在進行下面的步驟前,讀者有必要對這一點有比較明確地認(rèn)識。

此外,一個比較重要的事實是同一個中斷往往可以實現(xiàn)各種不同的功能。中斷所實現(xiàn)的確切功

能取決于所選擇的功能號,功能號一般都存在ah寄存器之中。比如中斷13h可以用于讀磁盤、

寫磁盤等功能,如果把3送入ah寄存器中,那么中斷選擇的功能就是寫磁盤;如果把2送入ah寄存

器中,選擇的功能則是讀磁盤等。

我們要做的事情

這次我們的源代碼由兩個匯編語言程序和一個C程序組成。第一個匯編文件是引導(dǎo)扇區(qū)的代碼。

在引導(dǎo)扇區(qū)中,我們寫的代碼是要把軟盤中第二扇區(qū)拷貝至內(nèi)存段的0x500處(地址是0x5000,

即偏移地址為0)。這時我們需要使用BIOS的中斷13h。這時啟動扇區(qū)的代碼就會把控制權(quán)轉(zhuǎn)移至0x500處。

在第二個匯編文件中,代碼會使用BIOS中斷10h在屏幕上顯示一個信息。C程序?qū)崿F(xiàn)的功能則是把可

執(zhí)行的文件1拷貝至啟動扇區(qū),把可執(zhí)行的文件2拷貝至軟盤的第二扇區(qū)。

啟動扇區(qū)代碼

使用中斷13h,啟動扇區(qū)把軟盤第二扇區(qū)里的內(nèi)容加載至內(nèi)存的0x5000處(段地址為0x500)。

下面的代碼是用于實現(xiàn)這一目的的代碼,將其保存至文件sbect.s中。

LOC1=0x500

entrystart

start:

movax,#LOC1

moves,ax

movbx,#0

movdl,#0

movdh,#0

movch,#0

movcl,#2

moval,#1

movah,#2

int0x13

jmpi0,#LOC1

上面代碼第一行類似于一個宏。接下去的兩行則是把值0x500加載至es寄存器中,

這是軟盤上第二扇區(qū)代碼將拷貝到的地方(第一扇區(qū)是啟動扇區(qū))。這時,把段內(nèi)的偏移設(shè)為0。

接下來把驅(qū)動器號送入dl寄存器中,其中磁頭號送入dl寄存器中,磁道號送入ch寄存器中,

扇區(qū)號送入cl寄存器中,扇區(qū)數(shù)送入al寄存器之中。我們想要實現(xiàn)的功能是把扇區(qū)2、磁道號為0、驅(qū)動器號為0的內(nèi)容送至段地址0x500處。所有這些參數(shù)都和1.44MB的軟盤相對應(yīng)。

把2送入ah寄存器中,是選擇了由中斷13h提供的相應(yīng)功能,即實現(xiàn)從軟驅(qū)轉(zhuǎn)移數(shù)據(jù)的功能。

最后調(diào)用中斷13h,并且轉(zhuǎn)至偏移為0的段地址0x500處。

第二個扇區(qū)的代碼

第二個扇區(qū)中的代碼如下所示(把這些代碼保存至文件sbect2.s之中):

entrystart

start:

movah,#0x03

xorbh,bh

int0x10

movcx,#26

movbx,#0x0007

movbp,#mymsg

movax,#0x1301

int0x10

loop1:jmploop1

mymsg:

.byte13,10

.ascii"OperatingSystemisLoading......"

上面代碼將被加載至段地址為0x500處,并且被執(zhí)行。在這段代碼中,使用了中斷10h來獲取目前的光標(biāo)

位置,然后顯示信息。

從第3行到第5行用于得到目前光標(biāo)的位置,在此中斷10h選用的是功能3。然后,清除了bh寄存器的內(nèi)容,

并把字符串送至ch寄存器中。在bx中,我們送入了頁碼及顯示的屬性。此處,我們想要在黑背景上顯示

白色的字符。然后,把要顯示字符的地址送到bp之中,信息由兩個字節(jié)組成,其值分別為13的10,

它們分別對應(yīng)回車和LF(換行)的ASCⅡ值。接下來是一個由29個字符組成的串;在下面實現(xiàn)的功能是

輸出字符串然后移動光標(biāo);最后是調(diào)用中斷,然后進入循環(huán)。

--------------------------------------------------------------------------------

4如何編寫自己的操作系統(tǒng)

C程序代碼

C程序的源代碼如下所示,將其存儲為write.c文件。

#include/*unistd.hneedsthis*/

#include/*containsread/write*/

#include

intmain()

{

charboot_buf[512];

intfloppy_desc,file_desc;

file_desc=open("./bsect",O_RDONLY);

read(file_desc,boot_buf,510);

close(file_desc);

boot_buf[510]=0x55;

boot_buf[511]=0xaa;

floppy_desc=open("/dev/fd0",O_RDWR);

lseek(floppy_desc,0,SEEK_SET);

write(floppy_desc,boot_buf,512);

file_desc=open("./sect2",O_RDONLY);

read(file_desc,boot_buf,512);

close(file_desc);

lseek(floppy_desc,512,SEEK_SET);

write(floppy_desc,boot_buf,512);

close(floppy_desc);

}

在上一期中,我曾經(jīng)介紹過如何操作能啟動的軟盤?,F(xiàn)在這一個過程稍微有點不同,

首先把由bsect.s編譯出來的可執(zhí)行文件bsect拷貝至軟盤的啟動扇區(qū)。然后再把由sect2.s產(chǎn)生的可執(zhí)行

文件sect2拷貝至軟盤的第二個扇區(qū)。

把上述文件置于同一目錄之下,然后分別對其進行編譯,方法如下所示:

as86bsect.s-obsect.o

ld86-dbsect.o-obsect

對sect2.s文件重復(fù)以上的操作,得出可執(zhí)行文件sect2。編譯write.c,插入軟盤后執(zhí)行write文件,

命令如下所示:

ccwrite.c-owrite

./write

下一步我們要做的事情

從軟盤啟動以后,可以看到顯示出來的字符串。這是使用了BIOS中斷來完成的。

下一期要做的事情是在這個操作系統(tǒng)中實現(xiàn)實模式向保護模式的轉(zhuǎn)換。

自己動手寫操作系統(tǒng)(三)

在上兩期中(自己動手寫操作系統(tǒng)1,2),我向大家講述了如何使用Linux提供的開發(fā)工具在軟盤的啟動

扇區(qū)寫一些代碼,以及如何調(diào)用BIOS的問題。現(xiàn)在,這個操作系統(tǒng)已經(jīng)越來越接近當(dāng)年LinusTorvalds的

那個具有"歷史意義"的Linux內(nèi)核了。因此,要馬上把這個系統(tǒng)切換到保護模式之下。

什么是保護模式

自從1969年推出第一個微處理器以來,Intel處理器就在不斷地更新?lián)Q代,從8086、8088、80286,

到80386、80486、奔騰、奔騰Ⅱ、奔騰4等,其體系結(jié)構(gòu)也在不斷變化。80386以后,

提供了一些新的功能,彌補了8086的一些缺陷。這其中包括內(nèi)存保護、多任務(wù)及使用640KB以上的內(nèi)存等,

并仍然保持和8086家族的兼容性。也就是說80386仍然具備了8086和80286的所有功能,

但是在功能上有了很大的增強。早期的處理器是工作在實模式之下的,80286以后引入了保護模式,

而在80386以后保護模式又進行了很大的改進。在80386中,保護模式為程序員提供了更好的保護,

提供了更多的內(nèi)存。事實上,保護模式的目的不是為了保護程序,而是要保護程序以外的所有程序

(包括操作系統(tǒng))。

簡言之,保護模式是處理器的一種最自然的模式。在這種模式下,處理器的所有指令及體系結(jié)構(gòu)的所有

特色都是可用的,并且能夠達(dá)到最高的性能。

保護模式和實模式

從表面上看,保護模式和實模式并沒有太大的區(qū)別,二者都使用了內(nèi)存段、中斷和設(shè)備驅(qū)動來處理硬件

,但二者有很多不同之處。我們知道,在實模式中內(nèi)存被劃分成段,每個段的大小為64KB,

而這樣的段地址可以用16位來表示。內(nèi)存段的處理是通過和段寄存器相關(guān)聯(lián)的內(nèi)部機制來處理的,

這些段寄存器(CS、DS、SS和ES)的內(nèi)容形成了物理地址的一部分。具體來說,最終的物理地址是由

16位的段地址和16位的段內(nèi)偏移地址組成的。用公式表示為:

物理地址=左移4位的段地址+偏移地址。

在保護模式下,段是通過一系列被稱之為"描述符表"的表所定義的。段寄存器存儲的是指向這

些表的指針。用于定義內(nèi)存段的表有兩種:全局描述符表(GDT)和局部描述符表(LDT)。GDT是一個段描述

符數(shù)組,其中包含所有應(yīng)用程序都可以使用的基本描述符。在實模式中,段長是固定的(為64KB),

而在保護模式中,段長是可變的,其最大可達(dá)4GB。LDT也是段描述符的一個數(shù)組。與GDT不同,

LDT是一個段,其中存放的是局部的、不需要全局共享的段描述符。每一個操作系統(tǒng)都必須定義一個GDT,

而每一個正在運行的任務(wù)都會有一個相應(yīng)的LDT。每一個描述符的長度是8個字節(jié),格式如圖3所示。

當(dāng)段寄存器被加載的時候,段基地址就會從相應(yīng)的表入口獲得。描述符的內(nèi)容會被存儲在一個程序員不可

見的影像寄存器(shadowregister)之中,以便下一次同一個段可以使用該信息而不用每次都到表中提取

。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實模式和保護模式的不同可以從圖1

和圖2中很清楚地看出來。

--------------------------------------------------------------------------------

5如何編寫自己的操作系統(tǒng)

圖1實模式的尋址

圖2保護模式下的尋址

圖3段描述俯的格式

此外,還有一個中斷描述符表(IDT)。這些中斷描述符會告訴處理器到那里可以找到中斷處理程序。

和實模式一樣,每一個中斷都有一個入口,但是這些入口的格式卻完全不同。

因為在切換到保護模式的過程中沒有使用到IDT,所以在此就不多做介紹了。

進入保護模式

80386有4個32位控制寄存器,名字分別為CR0、CR1、CR2和CR3。CR1是保留在未來處理器中使用的,

在80386中沒有定義。CR0包含系統(tǒng)的控制標(biāo)志,用于控制處理器的操作模式和狀態(tài)。CR2和CR3是用于

控制分頁機制的。在此,我們關(guān)注的是CR0寄存器的PE位控制,它負(fù)責(zé)實模式和保護模式之間的切換。

當(dāng)PE=1時,說明處理器運行于保護模式之下,其采用的段機制和前面所述的相應(yīng)內(nèi)容對應(yīng)。如果PE=0,

那么處理器就工作在實模式之下。

切換到保護模式,實際就是把PE位置為1。為了把系統(tǒng)切換到保護模式,還要做一些其它的事情。

程序必須要對系統(tǒng)的段寄存器和控制寄存器進行初始化。把PE位置1后,還要執(zhí)行跳轉(zhuǎn)指令。

過程簡述如下:

1.創(chuàng)建GDT表;

2.通過置PE位為1進入保護模式;

3.執(zhí)行跳轉(zhuǎn)以清除在實模式下讀取的任何指令。

下面使用代碼來實現(xiàn)這個切換過程。

需要的東西

◆一張空白軟盤

◆NASM編譯器

下面是整個程序的源代碼:

org0x07c00;起始地址是0000:7c00

jmpshortbegin_boot;跳過其它的數(shù)據(jù),跳轉(zhuǎn)到引導(dǎo)程序的開始處

bootmesgdb"OurOSbootsectorloading......"

pm_mesgdb"Switchingtoprotectedmode...."

dw512;每一扇區(qū)的字節(jié)數(shù)

db1;每一簇的扇區(qū)數(shù)

dw1;保留的扇區(qū)號

db2

dw0x00e0

dw0x0b40

db0x0f0

dw9

dw18

dw2;讀寫扇區(qū)號

dw0;隱藏扇區(qū)號

print_mesg:

movah,0x13;使用中斷10h的功能13,在屏幕上寫一個字符串

moval,0x00;決定調(diào)用函數(shù)后光標(biāo)所處的位置

movbx,0x0007;設(shè)置顯示屬性

movcx,0x20;在此字符串長度為32

movdx,0x0000;光標(biāo)的起始行和列

int0x10;調(diào)用BIOS的中斷10h

ret;返回調(diào)用程序

get_key:

movah,0x00

int0x16;Get_key使用中斷16h的功能0,讀取下一個字符

ret

clrscr:

movax,0x0600;使用中斷10h的功能6,實現(xiàn)卷屏,如果al=0則清屏

movcx,0x0000;清屏

movdx,0x174f;卷屏至23,79

movbh,0;使用顏色0來填充

int0x10;調(diào)用10h中斷

ret

begin_boot:

callclrscr;先清屏

movbp,bootmesg;提供串地址

callprint_mesg;輸出信息

callget_key;等待用戶按下任一鍵

bits16

callclrscr;清屏

movax,0xb800;使gs指向顯示內(nèi)存

movgs,ax;在實模式下顯示一個棕色的A

movword[gs:0],0x641;顯示

callget_key;調(diào)用Get_key等待用戶按下任一鍵

movbp,pm_mesg;設(shè)置串指針

callprint_mesg;調(diào)用print_mesg子程序

callget_key;等待按鍵

callclrscr;清屏

cli;關(guān)中斷

lgdt[gdtr];加載GDT

moveax,cr0

oral,0x01;設(shè)置保護模式位

movcr0,eax;將更改后的字送至控制寄存器中

jmpcodesel:go_pm

bits32

go_pm:

movax,datasel

movds,ax;初始化ds和es,使其指向數(shù)據(jù)段

moves,ax

movax,videosel;初始化gs,使其指向顯示內(nèi)存

movgs,ax

movword[gs:0],0x741;在保護模式下顯示一個白色的字符A

spin:jmpspin;循環(huán)

bits16

gdtr:

dwgdt_end-gdt-1;gdt的長度

ddgdt;gdt的物理地址

gdt

nullselequ$-gdt;$指向當(dāng)前位置,所以nullsel=0h

gdt0;空描述符

dd0

dd0;所有的段描述符都是64位的

codeselequ$-gdt;這是8h也就是gdt的第二個描述符

--------------------------------------------------------------------------------

6如何編寫自己的操作系統(tǒng)

code_gdt

dw0x0ffff;段描述符的界限是4Gb

dw0x0000

db0x00

db0x09a

db0x0cf

db0x00

dataselequ$-gdt

data_gdt

dw0x0ffff

dw0x0000

db0x00

db0x092

db0x0cf

db0x00

videoselequ$-gdt

dw3999

dw0x8000;基址是0xb8000

db0x0b

db0x92

db0x00

db0x00

gdt_end

times510-($-$$)db0

dw0x0aa55

把上面的代碼存在一個名為abc.asm的文件之中,使用命令nasmabc.asm,將得出一個名為abc的文件。

然后插入軟盤,輸入命令:ddif=abcof=/dev/fd0。該命令將把文件abc寫入到軟盤的第一扇區(qū)之中。

然后重新啟動系統(tǒng),就會看到如下的信息:

*Ourosbooting................

*A(棕色)

*Switchingtoprotectedmode....

*A(白色)

對代碼的解釋

上面給出了所有的代碼,下面我對上述代碼做一些解釋。

◆使用的函數(shù)

下面是代碼中一些函數(shù)的說明:

print_mesg該子程序使用了BIOS中斷10h的功能13h,即向屏幕寫一字符串。屬性控制是通過向一些寄

存器中送入不同的值來實現(xiàn)的。中斷10h是用于各種字符串操作,我們把子功能號13h送到ah中,

用于指明

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論