版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 節(jié)約資源倡議書范文(30篇)
- 小學(xué)英語學(xué)期工作計劃(20篇)
- 身邊好人好事事跡材料素材15篇
- 購房借款的合同范本(20篇)
- 小班下學(xué)期個人計劃(14篇)
- 新教材高考地理二輪復(fù)習(xí)三10個長效熱點綜合專項訓(xùn)練熱點4農(nóng)業(yè)生產(chǎn)與鄉(xiāng)村振興含答案
- 吉林省長春市2025屆高三質(zhì)量監(jiān)測(一)物理試題(無答案)
- 2025年中考物理專項復(fù)習(xí):特殊方法測密度(含答案及解析)
- 山東省五年高考語文考題匯編-語言文字應(yīng)用
- 2024年標(biāo)準(zhǔn)委托管理協(xié)議書
- 臨床微生物學(xué)檢驗:實驗六 腸道桿菌的檢驗(一)
- 學(xué)校每月安全主題教育月(一月一主題)活動安排
- 煤礦重大生產(chǎn)安全事故隱患判定標(biāo)準(zhǔn)解讀課件
- 《生物技術(shù)制藥》課程教學(xué)大綱
- 婦科疾病護理質(zhì)量標(biāo)準(zhǔn)
- 讀《星星之火可以燎原》有感
- DB13T 5714-2023 道路運輸企業(yè)安全生產(chǎn)風(fēng)險分級管控規(guī)范
- “五愛”記心中愛祖國愛人民愛勞動愛科學(xué)愛社會主義課件
- 人教b版高中數(shù)學(xué)選修1-1同步練習(xí)題及答案全冊匯編
- 高考政治經(jīng)濟常識題答題技巧
- 研究生職業(yè)生涯規(guī)劃
評論
0/150
提交評論