<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    飛艷小屋

    程序--人生--哲學___________________歡迎艷兒的加入

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      52 Posts :: 175 Stories :: 107 Comments :: 0 Trackbacks

    有人可能擔心自己既沒有學過計算機原理,也沒有學過操作系統原理,更不懂匯編語言,對C語言也一知半解,能寫操作系統嗎?答案是沒問題。我將帶大家一步一步完成自己的操作系統。當然如果學一學上述內容再好不過。
          開始還是補充一下基本知識:
    什么是保護模式


    自從1969年推出第一個微處理器以來,Intel處理器就在不斷地更新換代,從8086、8088、80286,到80386、80486、奔騰、奔騰Ⅱ、奔騰4等,其體系結構也在不斷變化。80386以后,提供了一些新的功能,彌補了8086的一些缺陷。這其中包括內存保護、多任務及使用640KB以上的內存等,并仍然保持和8086家族的兼容性。也就是說80386仍然具備了8086和80286的所有功能,但是在功能上有了很大的增強。早期的處理器是工作在實模式之下的,80286以后引入了保護模式,而在80386以后保護模式又進行了很大的改進。在80386中,保護模式為程序員提供了更好的保護,提供了更多的內存。事實上,保護模式的目的不是為了保護程序,而是要保護程序以外的所有程序(包括操作系統)。

    簡言之,保護模式是處理器的一種最自然的模式。在這種模式下,處理器的所有指令及體系結構的所有特色都是可用的,并且能夠達到最高的性能。

    保護模式和實模式


    從表面上看,保護模式和實模式并沒有太大的區別,二者都使用了內存段、中斷和設備驅動來處理硬件,但二者有很多不同之處。我們知道,在實模式中內存被劃分成段,每個段的大小為64KB,而這樣的段地址可以用16位來表示。內存段的處理是通過和段寄存器相關聯的內部機制來處理的,這些段寄存器(CS、DS、SS和ES)的內容形成了物理地址的一部分。具體來說,最終的物理地址是由16位的段地址和16位的段內偏移地址組成的。用公式表示為:

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

    在保護模式下,段是通過一系列被稱之為“描述符表”的表所定義的。段寄存器存儲的是指向這些表的指針。用于定義內存段的表有兩種:全局描述符表(GDT)和局部描述符表(LDT)。GDT是一個段描述符數組,其中包含所有應用程序都可以使用的基本描述符。在實模式中,段長是固定的(為64KB),而在保護模式中,段長是可變的,其最大可達4GB。LDT也是段描述符的一個數組。與GDT不同,LDT是一個段,其中存放的是局部的、不需要全局共享的段描述符。每一個操作系統都必須定義一個GDT,而每一個正在運行的任務都會有一個相應的LDT。每一個描述符的長度是8個字節,格式如圖3所示。當段寄存器被加載的時候,段基地址就會從相應的表入口獲得。描述符的內容會被存儲在一個程序員不可見的影像寄存器(shadow register)之中,以便下一次同一個段可以使用該信息而不用每次都到表中提取。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實模式和保護模式的不同可以從圖1和圖2中很清楚地看出來。

    此外,還有一個中斷描述符表(IDT)。這些中斷描述符會告訴處理器到那里可以找到中斷處理程序。和實模式一樣,每一個中斷都有一個入口,但是這些入口的格式卻完全不同。因為在切換到保護模式的過程中沒有使用到IDT,所以在此就不多做介紹了。

    進入保護模式


    80386有4個32位控制寄存器,名字分別為CR0、CR1、CR2和CR3。CR1是保留在未來處理器中使用的,在80386中沒有定義。CR0包含系統的控制標志,用于控制處理器的操作模式和狀態。CR2和CR3是用于控制分頁機制的。在此,我們關注的是CR0寄存器的PE位控制,它負責實模式和保護模式之間的切換。當PE=1時,說明處理器運行于保護模式之下,其采用的段機制和前面所述的相應內容對應。如果PE=0,那么處理器就工作在實模式之下。

    切換到保護模式,實際就是把PE位置為1。為了把系統切換到保護模式,還要做一些其它的事情。程序必須要對系統的段寄存器和控制寄存器進行初始化。把PE位置1后,還要執行跳轉指令。過程簡述如下:

    1.創建GDT表;

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

    3.執行跳轉以清除在實模式下讀取的任何指令。 



    首先要明確處理器(也就是CPU)控制著計算機。對PC而言,啟動的時候,CPU都處在實模式狀態,相當于只是一個Intel 8086處理器。也就是說,即使你現在擁有一個奔騰處理器,它的功能也只能是8086級別。從這一點上來講,可以使用一些軟件把處理器轉換到著名的保護模式。只有這樣,我們才可以充分利用處理器的強大功能。

    編寫操作系統開始是對BIOS控制,取出存儲在ROM里的程序。BIOS是用來執行POST(Power On Self Test,自檢)的。自檢是檢查計算機的完整性(比如外設是否工作正常、鍵盤是否連接等)。這一切完成以后,你就會聽到PC喇叭發出一聲清脆的響聲。如果一切正常,BIOS就會選擇一個啟動設備,并且讀取該設備的第一扇區(即啟動扇區),然后控制過程就會轉移到指定位置。啟動設備可能是一個軟盤、光盤、硬盤,或者其它所選擇的設備。在此我們把軟盤作為啟動設備。如果我們已經在軟盤的啟動扇區里寫了一些代碼,這時它就被執行。因此,我們的目的很明確,就是往軟盤的啟動扇區寫一些程序。

    首先使用8086匯編來寫一個小程序,然后將其拷貝至軟盤的啟動扇區。為了實現拷貝,要寫一個C程序。最后,使用軟盤啟動計算機。


    需要的工具


    ● as86:這是一個匯編程序,它負責把寫的代碼轉換成目標文件。

    ● ld86:這是一個連接器,as86產生的目標代碼由它來轉換成真正的機器語言。機器語言是8086能夠解讀的形式。

    ● GCC:著名的C編程器。因為我們需要寫一個C程序將自己的OS轉移到軟盤中。

    ● 一張空軟盤:它用于存儲編寫的操作系統,也是啟動設備。

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

    在大部分標準Linux發行版中都會帶有as86和ld86。在我使用的Red Hat 7.3中就包含有這兩個工具,并且在默認的情況下,它已經安裝在機器里。如果使用的Linux沒有這兩個工具,可以從網上下載(http://www.cix.co.uk/~mayday/),這兩個工具都包含在一個名為bin86的軟件包中。此外,有關的文檔也可以在網上獲得(www.linux.org/docs/ldp/howto/Assembly-HOWTO/as86.html)。


    開始工作


    使用一個你喜歡的編輯器輸入以下內容:

    entry start
    start:
    mov ax,#0xb800
    mov es,ax
    seg es
    mov [0],#0x41
    seg es
    mov [1],#0x1f
    loop1: jmp loop1



    這是as86可以讀懂的一段匯編程序。第一個句子指明了程序的入口點,聲明整個過程從start處開始。第二行指明了start的位置,說明整個程序要從start處開始執行。0xb800是顯存的開始地址。#表明其后是一個立即數。執行語句:

    mov ax,#oxb800



    ax寄存器的值就變為0xb800,這就是顯存的地址。下面再將這個值移至es寄存器,es是附加段寄存器。請記住8086有一個分段的體系結構。它的各段寄存器為代碼段、數據段、堆棧段和附加段,對應的寄存器名稱分別為cs、ds、ss和es。事實上,我們把顯存地址送入了附加段,因此,任何送入附加段的東西都會被送到顯存中。

    要在屏幕上顯示字符,就需要向顯存中寫兩個字節。前一個是所要顯示字符的ASCⅡ值,第二個字節表示該字符的屬性。屬性包括字符的前景色、背景色及是否閃爍等等。seg es指明下一個將要執行的指令是指向es段的。所以,我們把值0x41(在ASCⅡ中表示的字符是A)送到顯存的第一個字節中。接下來要把字符的屬性送到下一個字節當中。在此輸入的是0x1f,該屬性指的是在藍色背景下顯示白色的字符。因此,如果執行這個程序,就可以在屏幕上得到顯示在藍底上的一個白色的A。接著是一個循環。因為在執行完顯示字符的任務后,要么讓程序結束,要么使用一個循環使其永遠運行下去。把該文件命名為boot.s,然后存盤。

    此處顯存的概念說得不是很清楚,有必要進一步解釋一下。假設屏幕由80列×25行組成,那么第一行就需要160字節,其中一個字節用于表示字符,另外一個字節用于表示字符的屬性。如果要在第三行顯示某一字符的話,就要跳過顯存的第0和1字節(它們是用于顯示第1列的),第2和3字節(它們是用于顯示第2列的),然后把需要顯示字符的ASCⅡ碼值入第4字節,把字符的屬性寫入第5字節。


    把程序寫至啟動扇區


    下面寫一個C程序,把我的操作系統寫入軟盤第一扇區。程序內容如下:

    #i nclude /* unistd.h 需要這個文件 */
    #i nclude /* 包含有read和write函數 */
    #i nclude
    int main()
    {
    char boot_buf[512];
    int floppy_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文件,然后在打開文件時把文件描述符復制到file_desc變量中。從文件中讀取510個字符,或者讀取直到文件結束。在本例中由于文件很小,所以是讀取至文件結束。然后關閉文件。

    最后4行代碼打開軟盤驅動設備(一般來說是/dev/fd0)。使用lseek找到文件開始處,然后從緩沖中向軟盤寫512個字節。

    在read、write、open和lseek的幫助頁中,可以看到與函數所有有關的參數及其使用方法。程序中有兩行比較難懂:

    boot_buf[510] = 0x55;
    boot_buf[511] = 0xaa;



    該信息是用于BIOS的,如果它識別出該設備是一個可啟動的設備,那么在第510和511的位置,該值就應該是0x55和0xaa。程序會把文件boot讀至名為boot_buf的緩沖中。它要求改變第510和第511字節,然后把boot_buf寫至軟盤之上。如果執行代碼,軟盤上的前512字節就包含了啟動代碼。最后,把文件存為write.c。


    編譯運行


    使用下面的命令把文件變為可執行文件:

    as86 boot.s -o boot.o
    ld86 -d boot.o -o boot
    cc write.c -o write



    首先將boot.s文件編譯成目標文件boot.o,然后將該文件連接成最終的boot文件。最后C程序編譯成可執行的write文件。

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

    ./write



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

    啟動完成后,在屏幕上可以看到一個字母A(藍底白字),啟動速度很快,幾乎是在瞬間完成。這就意味著系統已經從我們制作的軟盤上啟動了,并且執行了剛才寫入啟動扇區的程序。現在,它正處在一個無限循環的狀態。所以,如果想進入Linux,必需拿掉軟盤,并且重啟機器。

    至此,這個操作系統就算完成了,雖然它沒有實現什么功能,但是它已經可以啟動機器了。

    作者:伊梅 本文選自:開放系統世界——賽迪網 2002年11月01日

    上一期,我講述了如何在軟盤的啟動扇區寫一些代碼,然后再從軟盤啟動的過程。制作好一個啟動扇區,在切換到保護模式之前,我們還應該知道如何使用BIOS中斷。BIOS中斷是一些由BIOS提供的、為了使操作系統的創建更容易的低級程序。在本文中,我們將學習處理BIOS的中斷。


    為什么要用BIOS


    BIOS會把啟動扇區拷貝至RAM中,并且執行這些代碼。除此之外,BIOS還要做很多其它的事情。當一個操作系統剛開始啟動時,系統中并沒有顯卡驅動、軟盤驅動等任何驅動程序。因此,啟動扇區中不可能包含任何一個驅動程序,我們要采取其它的途徑。這個時候,BIOS就可以幫助我們了。BIOS中包含有各種可以使用的程序,包括檢測安裝的設備、控制打印機、計算內存大小等用于各種目的的程序。這些程序就是所說的BIOS中斷。


    如何調用BIOS中斷


    在一般的程序設計語言中,函數的調用是一件非常容易的事情。比如在C語言中,如果有一個名為display的程序,它帶有兩個參數,其中參數noofchar表示顯示的字符數,參數attr表示顯示字符的屬性。那么要調用它,只需給出程序的名稱即可。對于中斷的調用,我們使用的是匯編語言中的int指令。

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

    display(nofchar,attr);



    而使用BIOS時,要實現相同功能使用的指令如下:

    int 0x10




    如何傳遞參數


    在調用BIOS中斷之前,我們需要先往寄存器中送一些特定的值。假設要使用BIOS的中斷13h,該中斷的功能是把數據從軟盤傳送至內存之中。在調用該中斷之前,要先指定拷貝數據的段地址,指定驅動器號、磁道號、扇區號,以及要傳送的扇區數等等。然后,就要往相應的寄存器送入相應的值。在進行下面的步驟前,讀者有必要對這一點有比較明確地認識。

    此外,一個比較重要的事實是同一個中斷往往可以實現各種不同的功能。中斷所實現的確切功能取決于所選擇的功能號,功能號一般都存在ah寄存器之中。比如中斷13h可以用于讀磁盤、寫磁盤等功能,如果把3送入ah寄存器中,那么中斷選擇的功能就是寫磁盤;如果把2送入ah寄存器中,選擇的功能則是讀磁盤等。


    我們要做的事情


    這次我們的源代碼由兩個匯編語言程序和一個C程序組成。第一個匯編文件是引導扇區的代碼。在引導扇區中,我們寫的代碼是要把軟盤中第二扇區拷貝至內存段的0x500處(地址是0x5000,即偏移地址為0)。這時我們需要使用BIOS的中斷13h。這時啟動扇區的代碼就會把控制權轉移至0x500處。在第二個匯編文件中,代碼會使用BIOS中斷10h在屏幕上顯示一個信息。C程序實現的功能則是把可執行的文件1拷貝至啟動扇區,把可執行的文件2拷貝至軟盤的第二扇區。


    啟動扇區代碼


    使用中斷13h,啟動扇區把軟盤第二扇區里的內容加載至內存的0x5000處(段地址為0x500)。下面的代碼是用于實現這一目的的代碼,將其保存至文件sbect.s中。

    LOC1=0x500
    entry start
    start:
    mov ax,#LOC1
    mov es,ax
    mov bx,#0
    mov dl,#0
    mov dh,#0
    mov ch,#0
    mov cl,#2
    mov al,#1
    mov ah,#2
    int 0x13
    jmpi 0,#LOC1



    上面代碼第一行類似于一個宏。接下去的兩行則是把值0x500加載至es寄存器中,這是軟盤上第二扇區代碼將拷貝到的地方(第一扇區是啟動扇區)。這時,把段內的偏移設為0。

    接下來把驅動器號送入dl寄存器中,其中磁頭號送入dl寄存器中,磁道號送入ch寄存器中,扇區號送入cl寄存器中,扇區數送入al寄存器之中。我們想要實現的功能是把扇區2、磁道號為0、驅動器號為0的內容送至段地址0x500處。所有這些參數都和1.44MB的軟盤相對應。

    把2送入ah寄存器中,是選擇了由中斷13h提供的相應功能,即實現從軟驅轉移數據的功能。

    最后調用中斷13h,并且轉至偏移為0的段地址0x500處。


    第二個扇區的代碼


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

    entry start
    start:
    mov ah,#0x03
    xor bh,bh
    int 0x10

    mov cx,#26
    mov bx,#0x0007
    mov bp,#mymsg
    mov ax,#0x1301
    int 0x10

    loop1: jmp loop1
    mymsg:
    .byte 13,10
    .ascii “Operating System is Loading......”



    上面代碼將被加載至段地址為0x500處,并且被執行。在這段代碼中,使用了中斷10h來獲取目前的光標位置,然后顯示信息。

    從第3行到第5行用于得到目前光標的位置,在此中斷10h選用的是功能3。然后,清除了bh寄存器的內容,并把字符串送至ch寄存器中。在bx中,我們送入了頁碼及顯示的屬性。此處,我們想要在黑背景上顯示白色的字符。然后,把要顯示字符的地址送到bp之中,信息由兩個字節組成,其值分別為13的10,它們分別對應回車和LF(換行)的ASCⅡ值。接下來是一個由29個字符組成的串;在下面實現的功能是輸出字符串然后移動光標;最后是調用中斷,然后進入循環。


    C程序代碼


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

    #i nclude /* unistd.h needs this */
    #i nclude /* contains read/write */
    #i nclude
    int main()
    {
    char boot_buf[512];
    int floppy_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);
    }



    在上一期中,我曾經介紹過如何操作能啟動的軟盤。現在這一個過程稍微有點不同,首先把由bsect.s編譯出來的可執行文件bsect拷貝至軟盤的啟動扇區。然后再把由sect2.s產生的可執行文件sect2拷貝至軟盤的第二個扇區。

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

    as86 bsect.s -o bsect.o
    ld86 -d bsect.o -o bsect



    對sect2.s文件重復以上的操作,得出可執行文件sect2。編譯write.c,插入軟盤后執行write文件,命令如下所示:

    cc write.c -o write
    ./write




    下一步我們要做的事情


    從軟盤啟動以后,可以看到顯示出來的字符串。這是使用了BIOS中斷來完成的。下一期要做的事情是在這個操作系統中實現實模式向保護模式的轉換。

    在上兩期中(自己動手寫操作系統1,2),我向大家講述了如何使用Linux提供的開發工具在軟盤的啟動扇區寫一些代碼,以及如何調用BIOS的問題。現在,這個操作系統已經越來越接近當年Linus Torvalds的那個具有“歷史意義”的Linux內核了。因此,要馬上把這個系統切換到保護模式之下。


    什么是保護模式


    自從1969年推出第一個微處理器以來,Intel處理器就在不斷地更新換代,從8086、8088、80286,到80386、80486、奔騰、奔騰Ⅱ、奔騰4等,其體系結構也在不斷變化。80386以后,提供了一些新的功能,彌補了8086的一些缺陷。這其中包括內存保護、多任務及使用640KB以上的內存等,并仍然保持和8086家族的兼容性。也就是說80386仍然具備了8086和80286的所有功能,但是在功能上有了很大的增強。早期的處理器是工作在實模式之下的,80286以后引入了保護模式,而在80386以后保護模式又進行了很大的改進。在80386中,保護模式為程序員提供了更好的保護,提供了更多的內存。事實上,保護模式的目的不是為了保護程序,而是要保護程序以外的所有程序(包括操作系統)。

    簡言之,保護模式是處理器的一種最自然的模式。在這種模式下,處理器的所有指令及體系結構的所有特色都是可用的,并且能夠達到最高的性能。


    保護模式和實模式


    從表面上看,保護模式和實模式并沒有太大的區別,二者都使用了內存段、中斷和設備驅動來處理硬件,但二者有很多不同之處。我們知道,在實模式中內存被劃分成段,每個段的大小為64KB,而這樣的段地址可以用16位來表示。內存段的處理是通過和段寄存器相關聯的內部機制來處理的,這些段寄存器(CS、DS、SS和ES)的內容形成了物理地址的一部分。具體來說,最終的物理地址是由16位的段地址和16位的段內偏移地址組成的。用公式表示為:

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

    在保護模式下,段是通過一系列被稱之為“描述符表”的表所定義的。段寄存器存儲的是指向這些表的指針。用于定義內存段的表有兩種:全局描述符表(GDT)和局部描述符表(LDT)。GDT是一個段描述符數組,其中包含所有應用程序都可以使用的基本描述符。在實模式中,段長是固定的(為64KB),而在保護模式中,段長是可變的,其最大可達4GB。LDT也是段描述符的一個數組。與GDT不同,LDT是一個段,其中存放的是局部的、不需要全局共享的段描述符。每一個操作系統都必須定義一個GDT,而每一個正在運行的任務都會有一個相應的LDT。每一個描述符的長度是8個字節,格式如圖3所示。當段寄存器被加載的時候,段基地址就會從相應的表入口獲得。描述符的內容會被存儲在一個程序員不可見的影像寄存器(shadow register)之中,以便下一次同一個段可以使用該信息而不用每次都到表中提取。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實模式和保護模式的不同可以從圖1和圖2中很清楚地看出來。

    此外,還有一個中斷描述符表(IDT)。這些中斷描述符會告訴處理器到那里可以找到中斷處理程序。和實模式一樣,每一個中斷都有一個入口,但是這些入口的格式卻完全不同。因為在切換到保護模式的過程中沒有使用到IDT,所以在此就不多做介紹了。


    進入保護模式


    80386有4個32位控制寄存器,名字分別為CR0、CR1、CR2和CR3。CR1是保留在未來處理器中使用的,在80386中沒有定義。CR0包含系統的控制標志,用于控制處理器的操作模式和狀態。CR2和CR3是用于控制分頁機制的。在此,我們關注的是CR0寄存器的PE位控制,它負責實模式和保護模式之間的切換。當PE=1時,說明處理器運行于保護模式之下,其采用的段機制和前面所述的相應內容對應。如果PE=0,那么處理器就工作在實模式之下。

    切換到保護模式,實際就是把PE位置為1。為了把系統切換到保護模式,還要做一些其它的事情。程序必須要對系統的段寄存器和控制寄存器進行初始化。把PE位置1后,還要執行跳轉指令。過程簡述如下:

    1.創建GDT表;

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

    3.執行跳轉以清除在實模式下讀取的任何指令。

    下面使用代碼來實現這個切換過程。


    需要的東西


    ◆ 一張空白軟盤

    ◆ NASM編譯器

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

    org 0x07c00; 起始地址是0000:7c00
    jmp short begin_boot ; 跳過其它的數據,跳轉到引導程序的開始處
    bootmesg db "Our OS boot sector loading ......"
    pm_mesg db "Switching to protected mode ...."
    dw 512 ; 每一扇區的字節數
    db 1 ; 每一簇的扇區數
    dw 1 ; 保留的扇區號
    db 2
    dw 0x00e0
    dw 0x0b40
    db 0x0f0
    dw 9
    dw 18
    dw 2 ; 讀寫扇區號
    dw 0 ; 隱藏扇區號
    print_mesg :
    mov ah,0x13 ; 使用中斷10h的功能13,在屏幕上寫一個字符串
    mov al,0x00 ; 決定調用函數后光標所處的位置
    mov bx,0x0007 ; 設置顯示屬性
    mov cx,0x20 ; 在此字符串長度為32
    mov dx,0x0000 ; 光標的起始行和列
    int 0x10 ; 調用BIOS的中斷10h
    ret ; 返回調用程序
    get_key :
    mov ah,0x00
    int 0x16 ; Get_key使用中斷16h的功能0,讀取下一個字符
    ret
    clrscr :
    mov ax,0x0600 ; 使用中斷10h的功能6,實現卷屏,如果al=0則清屏
    mov cx,0x0000 ; 清屏
    mov dx,0x174f ; 卷屏至23,79
    mov bh,0 ; 使用顏色0來填充
    int 0x10 ; 調用10h中斷
    ret
    begin_boot :
    call clrscr ; 先清屏
    mov bp,bootmesg ; 提供串地址
    call print_mesg ; 輸出信息
    call get_key ; 等待用戶按下任一鍵
    bits 16
    call clrscr ; 清屏
    mov ax,0xb800 ; 使gs指向顯示內存
    mov gs,ax ; 在實模式下顯示一個棕色的A
    mov word [gs:0],0x641 ; 顯示
    call get_key ; 調用Get_key等待用戶按下任一鍵
    mov bp,pm_mesg ; 設置串指針
    call print_mesg ; 調用print_mesg子程序
    call get_key ; 等待按鍵
    call clrscr ; 清屏
    cli ; 關中斷
    lgdt[gdtr] ; 加載GDT
    mov eax,cr0
    or al,0x01 ; 設置保護模式位
    mov cr0,eax ; 將更改后的字送至控制寄存器中
    jmp codesel:go_pm
    bits 32
    go_pm :
    mov ax,datasel
    mov ds,ax ; 初始化ds和es,使其指向數據段
    mov es,ax
    mov ax,videosel ; 初始化gs,使其指向顯示內存
    mov gs,ax
    mov word [gs:0],0x741 ; 在保護模式下顯示一個白色的字符A
    spin : jmp spin ; 循環
    bits 16
    gdtr :
    dw gdt_end-gdt-1 ; gdt的長度
    dd gdt ; gdt的物理地址
    gdt
    nullsel equ $-gdt ; $指向當前位置,所以nullsel = 0h
    gdt0 ; 空描述符
    dd 0
    dd 0 ; 所有的段描述符都是64位的
    codesel equ $-gdt ; 這是8h也就是gdt的第二個描述符
    code_gdt
    dw 0x0ffff ; 段描述符的界限是4Gb
    dw 0x0000
    db 0x00
    db 0x09a
    db 0x0cf
    db 0x00
    datasel equ $-gdt
    data_gdt
    dw 0x0ffff
    dw 0x0000
    db 0x00
    db 0x092
    db 0x0cf
    db 0x00
    videosel equ $-gdt
    dw 3999
    dw 0x8000 ; 基址是0xb8000
    db 0x0b
    db 0x92
    db 0x00
    db 0x00
    gdt_end
    times 510-($-$$) db 0
    dw 0x0aa55



    把上面的代碼存在一個名為abc.asm的文件之中,使用命令nasm abc.asm,將得出一個名為abc的文件。然后插入軟盤,輸入命令:dd if=abc of=/dev/fd0。該命令將把文件abc寫入到軟盤的第一扇區之中。然后重新啟動系統,就會看到如下的信息:

    *Our os booting................
    * A (棕色)
    * Switching to protected mode....
    * A (白色)




    對代碼的解釋


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

    ◆ 使用的函數

    下面是代碼中一些函數的說明:

    print_mesg 該子程序使用了BIOS中斷10h的功能13h,即向屏幕寫一字符串。屬性控制是通過向一些寄存器中送入不同的值來實現的。中斷10h是用于各種字符串操作,我們把子功能號13h送到ah中,用于指明要打印一個字符串。al寄存器中的0說明了光標返回的起始位置,0表示調用函數后光標返回到下一行的行首。如果al為1則表示光標位于最后一個字符處。

    顯存被分成了幾頁,在同一時刻只能顯示其中的一頁。bh指明的是頁號;bl則指明要顯示字符的顏色;cx指明要顯示字符串的長度;dx指明光標的位置(即起始的行和列)。所有相關寄存器初始化完成以后,就可以調用BIOS中斷10h了。

    get_key 使用中斷16h的子功能00h,從屏幕得到下一個字符。

    clrscr 該函數使用了中斷10h的另外一個子功能06h,用于輸出開始前清屏。初始化時給al中送入0。寄存器cx和dx指明要清屏的屏幕范圍,在本例中是整個屏幕。寄存器bh指明屏幕填充的顏色,在本例中是黑色。

    ◆ 其它內容

    程序一開始是一條短跳轉指令,跳到begin_boot處。在實模式下,在此打印一個棕色的“A”,并且設置一個GDT。切換到保護模式,并且打印一個白色的“A”。這兩種模式使用的都是自己的尋址方法。

    在實模式下,使用段寄存器gs指示顯存位置,我們使用的是CGA顯卡(默認基址是0xb8000)。在代碼中是不是漏了一個0呢?沒有,因為實模式下會提供一個附加的0。這種方式也被80386繼承下來了。A的ASCⅡ是0x41,0x06指明了需要一個棕色的字符。該顯示會一直持續直至按下任意鍵。下面要在屏幕上顯示一句話,告訴使用者下面馬上要進入保護模式了。

    啟動到保護模式,在進行切換時不希望此時有中斷的影響,故要關閉所有的中斷(使用cli來實現)。然后對GDT初始化。在整個切換過程中,對4個描述符進行了初始化。這些描述符對代碼段(code_gdt)、數據和堆棧段(data_gdt),以及為了訪問顯存而對顯示段進行初始化。此外,還會對一個空描述符進行初始化。

    GDT的基址要加載至GDTR系統寄存器之中。gdtr段的第一個字加載的是GDT的大小,在下一個雙字中則加載的是基址。然后,lgdt指令把把gdt段加載至GDTR寄存器中。現在已經做好了切換到保護模式前的所有準備。最后一件事情就是把CR0寄存器的PE位置1。不過,即使這樣還沒有處于保護模式狀態之下。

    設置了PE位以后,還需要通過執行JMP指令來清除處理器指令預取隊列。在80386中,使用指令前總是先將其從內存中取出,并且進行解碼和尋址。然而,當進入保護模式以后,預取指令信息(它還處于實地址模式)就無效了。使用JMP指令的目的就是強迫處理器放棄無效的信息。

    現在,已經在保護模式下了。那么,如何檢測是在保護模式狀態之下呢?讓我們來看一看屏幕上這個白色的字母A。在這里,使用了數據段選擇符(datase1)對數據段和附加段進行了初始化,使用顯示段選擇符(videose1)對gs進行了初始化。告示的字符“A”其ASCⅡ值和屬性位于[gs:0000]處,也就是b8000:0000處。循環語句使得該字符一直在屏幕上顯示,直至重新啟動系統。


    下一步要做的事


    現在,這個操作系統已經工作在保護模式下了,但是實際上它并不實現什么具體的功能。你可以在這個基礎上為它增加各種操作系統所具有的功能。我們自己動手寫操作系統到此也就告一段落。

    任何技術,只要掌握了方法則都能舉一反三,“師傅領進門,修行在個人”。天極網上關于系統優化的文章相當多,但這次講的內容和其它優化文章比起來,還是有較大的不同。各位如果在閱讀下面的內容時,遇到技術疑難,都可以在天極網的操作系統欄目的相關文章中尋找到答案——學會查詢資料,也是提高的必要技巧之一呢。

      一個操作系統,必定是建立在硬件基礎上的。而硬件,則可大致分為CPU、主板、內存、外存幾個部分。關于CPU超頻、內存在BIOS中的設置,開啟硬盤的DMA66支持等等的介紹已經相當多,在此我就不贅述了。

      一個操作系統的使用,依次會涉及到硬盤引導、操作系統引導、載入基本操作系統、定義臨時目錄、定義虛擬內存盤、載入系統服務、載入自定義服務、定義GUI這幾個步驟,這是不管Windows、Linux還是Freebsd等操作系統都是如此。也就是說,我們如果能盡量優化上面每個步驟,則就能把系統的性能提升起來。接下來,就讓我們一起把每個步驟做到最優。

      1、硬盤引導

      從硬盤的0磁道開始的第一個扇區處讀取信息,以載入操作系統引導程序,在這一步上,由于系統能讀取的只是一個扇區的數據資料,只有512Kb,因此不能直接將操作系統的引導程序放入其中,而只能讀入一個很小巧的程序,再由那個程序來引導操作系統,以Windows為例,在這一步被讀入的是IO.SYS和MSDOS.SYS(安裝了Win98后有這個)。由于一般來說這個程序都是由各個基礎操作系統所默認的,因此一般沒有辦法進行自定義優化。不過值得一提的是如果使用的是Windows98系統,那么通過定制MSDOS.SYS文件,可以在速度上達到一定的提高,讓我們打開瞧瞧:

      [Paths]

      WinDir=C:\Windows;Windows所在的目錄

      WinBootDir=C:\Windows ;引導目錄

      HostWinBootDrv=C ;引導盤(建議這三個別改動)

      [Options]

      BootMulti=1;是否按f8出菜單,以及是否f4/f2快捷功能菜單有效,值得注意,美萍等管理軟件之所以能屏蔽啟機時候按f8/f4/f2無效果就是在這里動的手腳

      BootGUI=1;是否圖形引導

      DoubleBuffer=1;雙倍緩沖,建議設置為1

      AutoScan=1;是否每次啟機檢查硬盤,這對非法關機后修復磁盤很有幫助,不過如果對自己的Win98很有信心,不妨設置成0

      WinVer=4.10.2222;Windows的版本號

      BootWin=1;以Windows方式引導

      DrvSpace=1;(這個選項功能不明)

      DblSpace=1;這個選項功能不明)

      LOGO=1;是否顯示開機畫面,事實上Windows的啟機畫面載入大概會花費1秒左右的時間,既然我們想優化,那么就設置成0吧

      BootDelay=0;引導延遲,設置成0最快

      DisableLog=0;不記錄引導時候的log,如果追求速度,可以設置成1

      2、操作系統引導

      Windows2000/XP的Boot、Linux和Freebsd的LILO、Grub都是非常出色的操作系統引導程序。如果想優化,就把自己最常使用的操作系統設置為默認項目,并將默認的啟動時間修改為1秒。以Windows2k/xp為例,可以用記事本等文字編輯工具打開系統盤根目錄下的boot.ini文件(注意,這個文件本身是系統+隱藏屬性),其中有一行為timeout=xx,其中這里的xx,就是系統在引導系統時候的等待時間。為了達到減少時間的目的,我們可以寫成timeout=1,注意別寫timeout=0,這表示無限等待,直到用戶手工選定了為止。同樣的,在grub中有一個menu.lst文件,其中的timeout參數的值與上面提到的Windows系統中boot.ini的timeout參數作用、設置方法上完全一樣(這也是天緣提倡地學好一個操作系統貴在了解其原理和工作流程,自然就會一通百通的道理。)

      3、載入基本操作系統

      這一部分中,操作系統將自身的程序、連接文件載入,由于載入的是基本文件,在Windows中就是Windows的內核,而在UNIX中,則可以把這步理解為內核的載入。由于Windows的內核是保密的,因此沒有辦法擅自修改,而在UNIX中,則可以利用重新生成內核的命令,嘗試去掉自己不需要的驅動、設備支持和功能來縮減內核的功能并減少啟動時間。這也就是為什么人們很看好Linux在嵌入式行業發展的原因——由于內核完全可以定制,所以可以只保留需要的功能,整個內核可以做得非常小巧。Ok,回過來,因為內核程序速度非常快,所需要的時間本身就很少,而關于定制Linux的內核,可以參考天極網的相關文章。各位朋友切記一點:“由于操作系統所在的分區本身就時常進行讀寫操作,因此最好為操作系統單獨劃分一個分區,而把臨時目錄、暫存盤、文件、游戲、備份等放到其他分區去。”這一點是我們進行下面的優化步驟的大前提,以下我們的幾步操作,都是以此為大前提來進行的。

      4、定義臨時目錄

      由于操作系統在執行一些煩瑣的運算、解壓縮文件的時候,都是先將文件臨時放在某個目錄下,在任務執行完后再刪除。Windows下默認是放在操作系統下的temp目錄中,UNIX下默認是放在/tmp中。如果我們能想辦法提高其讀寫速度,則就能在這步中達到優化的效果。由于硬盤的物理形態因素,導致硬盤在內區讀寫速度會比外區更快一些,因此考慮將臨時目錄放在靠近磁盤內區物理位置的地方。在Windows、UNIX等大多數操作系統情況下,都是越分在前面的分區越靠近內區,越分在后面的分區越靠近外區。UNIX下可在劃分了/boot后,馬上劃分/tmp分區;在Windows下由于根據第3條中提到的盡量減少操作系統所在分區的讀寫操作,因此我們將臨時目錄建在D盤,針對Win9x和2000的方法略有出入:

      Win9x:

      1.在D盤下新建立一個目錄temp;

      2.用記事本打開c:\autoexec.bat(如沒有,可自行建立一個),輸入以下兩行;

      @set temp=d:\temp

      @ set tmp=d:\temp

      Win2000/XP:

      1.在D盤下新建立一個目錄temp;

      2.打開“控制面板”——“屬性”——“高級”;

      3.在“系統變量”這里,將temp和tmp的值,都改為d:\temp;

      好了,重新啟機之后,就生效了。不過由于Windows仍然有某些程序的默認臨時目錄不是我們所指定的temp目錄,所以還需要手工指定一下。以IE為例:“工具”——“Internet選項”——“Internet臨時文件”這里的“設置”——“移動文件夾”,將臨時目錄指定成我們的d:\temp就行了。

      值得一提的是,不管是Windows也好,UNIX也好,相當一部分用了臨時文件后沒有清除它,因此可以定期每周把d:\temp清空。在UNIX下對于這樣的定期命令可以通過cron來完成。

      5、定義虛擬內存盤

      我們的操作系統在調用程序,相關的資源文件的時候,都需要將程序由速度較慢的外存,調用到速度較快的內存中之后再進行操作。由于外存的價格相對內存為低,因此大多數用戶在內存不夠充裕的條件下,一般會選擇用外存硬盤來虛擬內存使用。需要說明的是,這只是在技術上的虛擬內存,并不能真正使這部分硬盤的讀寫速度有任何提升。因此在資金允許的情況下,建議用戶能夠升級到512M內存為比較適合。天緣常常見到很多用戶盲目追求高速cpu,而忽略了對內存的需求。事實上只有類似Photoshop、3D MAX、WinAMP等需要即時演算、解碼操作(圖形類的渲染大多可以通過顯卡來完成來減輕cpu負擔),大多數常用的辦公軟件、第三方工具其實對CPU并沒有很大的消耗,而是需要大量高速內存的支持。按照我們上一步中的知識,自然虛擬內存盤的讀寫速度也應該是越快越好了?所以很多書上在介紹unux安裝的時候,會建議swap分區靠前;而Windows下,我們則可以指定把虛擬目錄放到d盤下去。同樣,針對Win9x和Win2k/xp有兩種方式來完成。

      Win 9x: 

      1.打開“控制面板”——“屬性”——“性能”——“虛擬內存”;

      2.將虛擬內存指定為自定義,選擇d盤;

      3.重新啟動計算機;

      Win 2k:

      1.打開“控制面板”——“屬性”——“高級”——“性能選項”;

      2.在這里,如果您的機器是自己用,就選“應用程序”,如果是提供Ftp或者Web服務,就選擇“后臺服務”。(由此可見,微軟是為了節約開發成本,將Win2k的pro/server/advance server三種版本用同樣的構架搭建出來的)

      3.選中“虛擬內存”這里的“更改”

      4.將c盤的虛擬內存去掉,將d盤的虛擬內存根據需要進行適當設置;

      5.重新啟動計算機;

      恩,經過這么一來。當計算機發現內存不夠的時候,就會在d盤下建立虛擬磁盤來模擬內存使用了。虛擬出來的內存是一個在Win9x下名為Win386.swp,Win2k下名為pagefile.sys的文件。別忘記將原來的c盤下的同名文件刪除,以增加c盤的可用空間喲。當然,硬盤的讀寫速度是遠遠不及內存的,因此這只是權宜之計,添置更多的物理內存才是正解。

      6、載入系統服務

      在這一步中,系統將會載入基本的服務。例如Win2k下的“控制面版”——“控制工具”——“服務”中的項目;UNIX下也類似。在這里,一般來說我們不能對服務的內部進行改造以增加效率,但是我們只選擇需要的服務,而關閉不必要的服務。在這里,個人用戶和服務器管理員都要記住的一條定律會起作用“可開可不開的一定不開,可用可不用的一定不用”,這樣不但會減少系統的啟動時間、增加系統的可用內存、并且也盡量地避免了安全漏洞。記得前輩曾經指點過我:“服務器提供的服務越多,則可能存在的漏洞也越多,越容易被攻擊”。但是不管在w2k還是在UNIX中,默認打開的一些服務是我們所不需要的,甚至是危險的。以Win2k為例,“遠程控制注冊表”、“dhcp服務器”等等這些功能居然都是默認開著的,而UNIX下的不少操作系統默認時候“sendmail”、“smaba”也是開著的。

      所以,根據自己的選擇,恰當的選擇必要的服務。這一步會相當消耗時間,而且也會遇到對某些服務的疑問,但性能的提升也具有最大潛力。值得一提的是,一些后臺運行的程序也將自己添加到其中,常見的例如殺毒軟件,以及令人討厭的沖擊波病毒。關于詳細的介紹,天極網上介紹操作系統的一些文章中都有詳細描述,我在這里一一寫出,就有騙稿費的嫌疑了。

      7、載入自定義服務

      之所以要把這一步與上面的一步分開,一來是因為他們存放的啟動文件位置有差異,二來有的系統服務是必須啟動的,如果不啟動則連操作系統也無法按照常規方式運行起來。例如Win2k服務中的“Logical Disk Manager(邏輯磁盤管理器監視狗服務)”就是專門對硬盤進行管理的。自定義的服務項目,在Windows中,存在注冊表的run系列鍵中(Software\Microsoft\Windows\CurrentVersion\Run、Software\Microsoft\Windows\CurrentVersion\Runonce、SOFTWARE\Microsoft\Windows\CurrentVersion\Run、SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce、SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx、SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices);而在UNIX則是用特定位置的文本文件來保存,例如redhat下是/etc/rc.local文件,一行一條shell命令,非常簡單明了。一般來說,這一部分的服務即使全部去掉,也不會影響系統的啟動,但有的操作系統“原裝”服務可以令我們使用的時候更得心應手。同時在這里,也是很多Windows木馬藏身的地方。

      在自定義服務中,可以將自己不需要,或者很少用到的一些服務去掉(例如天緣就把音量調節的服務去掉了,因為我從來都喜歡直接擺弄音響);也可以把自己每次啟動系統都要運行的一些程序加入進去(例如天緣在Linux下的fvwm啟動就加在/etc/rc.local中)。合理的使用它,選擇恰當的程序去掉無用的程序,也可以達到相當好的性能優化目的。順便為Windows的朋友們推薦一個我很喜歡的注冊表編輯工具,名字是RegHance,非常簡單方便。

      8、定義GUI

      在這里,為什么特別提到GUI呢?Windows的用戶可能比較有疑惑,因為Windows的圖形界面是嵌入內核的,不過在UNIX下則是獨立的。在這一部分上,由于操作系統的獨立性,因此要詳細地講解不大可能。我只給出一個思路:“盡量縮減無用的資源消耗”。例如:控制GUI的加載字體數量。事實的確如此,任何載入的資源都會消耗掉系統的內存,由于中文的特殊性(文字眾多,非字母組合),導致一個中文字庫比一個英文字庫大上很多,自然消耗的內存也大了很多(現在明白了為什么傳呼機、手機、嵌入系統等等rom/ram受限的場合一般采用英語了吧?因為它總共就26個字母,在這點上,的確比漢字具有優越性。同樣的道理從我們所用的鍵盤也能體現出來)。

      天緣認識幾個從事藝術行業的朋友,經常習慣將用到的字體都放在Font目錄中,其實這樣在每次啟動的時候都會載入到內存中(順便一提,我們曾經試過,Win98下Font目錄Copy字體到400m左右就無法再增加了)會嚴重地影響到啟動速度。值得采納的做法是將一些不常用的字體Copy到其他目錄中備用,在需要的時候再調入到Font目錄中,然后重新計算機就可以了。雖然的確是煩瑣了一點,不過在有錢購買1G的內存前,節約幾百M的內存也是很有必要的。類似的道理,UNIX管理員都知道在服務器上不需要跑xWindows就不要跑的道理。以上的小例子希望可以幫助大家開動自己的腦筋,好好想想其他值得優化的地方。

      當文章寫到這里,已是接近尾聲。油然想起當我告訴原野編輯我要寫操作系統優化的時候他對我說的:“介紹系統優化的文章已經很多了呀。”這句略帶警醒的話。是的,Windows平臺下、UNIX平臺下介紹系統優化的文章數不勝數;“超級兔子”、“優化大師”、“webmin”這些優秀的系統設置/優化工具不斷更新。但正如“鞋子只有自己買的才最合腳”這個道理一樣,天緣嘗試將自己優化系統的心得總結與大家分享。IT行業日新月異,新的操作系統層出不窮,掌握了一個優化軟件,或許在新的操作系統面前依然束手無策。學習學習,不在于學其形,貴在學其神。明白了操作系統優化的原理,依照著以上的8個環節,針對自己的機器情況進行思考分析,那么即使面對的是一個全新的操作系統,也能很快地將其優化,提高自己工作、學習、娛樂的效率。中國人的習俗,春節吃魚代表“年年有余”。而授人予魚不如授人以漁,希望這篇小文能幫助大家把自己愛機的潛力充分發揮到極致。 
    主要特點:
    ----------
    多配置啟動菜單
    全面的支持中英文長文件名
    支持NTFS驅動器
    各種光驅支持
    RAMDISK 虛擬磁盤
    中文漢字操作系統
    方便的文件管理
    較強通用性和穩定性
    許多實用的小工具

    ---------
    已寫文件列表
    ---------
    aspi2dos.sys 18,802 實模式的 Adaptec CD-ROM 驅動程序
    aspi4dos.sys 8,913 實模式的 Adaptec CD-ROM 驅動程序
    aspi8dos.sys 22,077 實模式的 Adaptec CD-ROM 驅動程序
    aspi8u2.sys 24,001 實模式的 Adaptec CD-ROM 驅動程序
    aspicd.sys 10,002 實模式的 Adaptec CD-ROM 驅動程序
    ASPIDISK.SYS 6,499 SCSI驅動器驅動程序
    ASPIOHCI.SYS 16,001 Iomega公司出的OHCI接口的USB驅動器的驅動程序
    ASPIUHCI.SYS 16,624 Iomega公司出的UHCI接口的USB驅動器的驅動程序
    Attrib.com 5,277 XATTRIB.COM查看、設置文件/目錄屬性
    AUTOEXEC.BAT 3,991 自動批處理文件
    CABFIND.COM 2,609 在CAB包中搜索文件的工具
    CCD.EXE 1,110 目錄快速轉換工具
    Cdrom.bat 2,133 安裝通用光驅驅動程序
    Choice.com 510 選擇命令,返回按鍵的ERRORLEVEL值
    Cmos.com 630 清除/保存COMOS信息
    Command.com 94,292 MS-DOS 7.1 命令解釋程序
    Config.sys 2,523 啟動配置文件,加載設備驅動程序
    CP936UNI.TBL 15,505 DOSLFN 0.32n 簡體中文代碼頁
    CtMouse.exe 4,898 鼠標驅動程序CTMOUSE v1.9,可驅動COM和PS2口鼠標
    Debug.com 14,593 V0.95c 程序調試命令
    Deltree.com 3,069 V1.2c 刪除整個目錄,從FREEDOS中補充的外部命令
    DI1000DD.SYS 8,483 Motto Hairu中的USB硬盤的驅動程序
    Doskey.com 4,640 V1.5 命令行記憶程序,Tab/Shift+Tab 選擇文件或目錄
    Doslfn.com 11,020 V0.32n,DOS中文/英文長文件名驅動程序
    DOSVER.COM 2,156 V2.11 實用的設置DOS版本號的工具
    DRVLOAD.COM 1,716 加載驅動程序的工具
    Ebd98.cab 159,944 包含實用程序的 Cab壓縮包
    ECHO.SYS 194 在CONFIG.SYS中顯示字符文字的程序
    Edit.exe 46,338 V2.0.026 全屏幕文本編輯器,可以編輯二進制文件
    EDIT.HLP 1,971 EDIT的幫助文件
    escape.exe 1,087 在任何時候都可以按F12鍵退回到DOS方式下,以防止死機
    Extract.exe 49,133 解壓CAB壓縮包
    Fdisk.exe 66,937 SPFDisk V2000-03kc 分區及啟動管理(Boot Manager)程序
    FINDCD.EXE 3,128 最好用的光驅查找工具 (作者: Wengier).
    Findramd.exe 2,464 查找虛擬盤的工具
    Himem.sys 10,306 XMS 內存管理程序
    Ifshlp.sys 2,784 增強的文件管理驅動程序,支持WIN的VFAT系統(Windows必需)
    Io.sys 213,977 系統引導文件
    Killer.exe 2,435 killr100可以自動截獲非法指令,防止死機
    Key.com 977 KPUSH.COM V2.0 鍵盤ASCII表查詢及清理工具
    LFNXLAT.386 867 為DOSLFN長文件名驅動程序提供Win 3.x下的長文件名支持
    Low.exe 29,491 硬盤低級格式化程序
    LOWDMA.SYS 662 提供軟盤的ISA DMA UMB支持
    MCD.BAT 180 建立多層目錄
    More.com 1,295 小巧的分屏顯示工具
    mousclip.exe 4,456 V1.10 很實用的在DOS下用鼠標復制/粘帖的工具
    Msdos.sys 122 引導選項信息(路徑、多層引導等等)
    Msdos.sy_ 1,661 win98系統啟動配置文件msdos.sys備份.
    Ne.exe 36,148 V1.24.2! 仿照PCTOOLS5的文件管理工具,十六進制編器.
    Nset.com 974 從輸出中取得變量以設置,FINDCD -a|NSET CDROM=$1
    NTFSDOS.EXE 26,507 V3.02R DOS的NTFS驅動程序
    Off.com 451 Shutdown 非常好的命令行ATX電源重新啟動/軟關機程序
    QF.EXE 23,313 FDISK和FORMAT加速,可節省時間
    readme.txt 6,077 本說明文件
    Reboot.com 16 重新啟動計算機
    RESET.COM 588 重新啟動DOS系統
    Shsucdx.exe 6,800 v1.4b 光驅驅動程序,可取代MSCDEX
    Sm.exe 13,272 磁盤緩沖工具SMARTDRV
    SORT.COM 1,630 小巧的排序工具
    SRCBOOT.COM 2,590 保存/恢復/比較磁盤的啟動扇區的小工具
    SRCFAT.COM 2,715 保存/恢復/比較磁盤的文件分配表(FAT)的小工具
    SRCMBR.COM 2,516 保存/恢復/比較磁盤的主引導記錄(MBR)的小工具
    SUBST.COM 1,469 小巧的設置虛擬驅動器的程序
    Sys.com 9,321 DOS系統文件傳輸程序
    tw.bat 1,241 啟動天匯中文DOS漢字系統
    Tway.cab 253,936 天匯3.1中文DOS漢字操作系統壓縮包
    Umbpci.sys 5,684 v3.45,很有用的UMB驅動程序,可以提供高達160多K的UMB
    USBASPI.SYS 15,480 Motto Hairu中的USB驅動程序
    USBCD.SYS 5,509 Motto Hairu中的USB/SCSI光驅的驅動程序
    Vc.bat 446 啟動DOS下的文件管理器Volkov Commander的啟動程序
    Vc.cab 80,260 V4.99.08 很實用的文件管理器,支持FAT32和長文件名
    Vers.com 1,500 修改DOS版本號工具
    Vide-cdd.sys 6,192 ATAPI CD-ROM 驅動器的通用設備驅動程序,占用內存只有5K
    Xcopy.exe 16,442 V1.1 加強的COPY命令,可復制整個目錄
    xdel.exe 1,651 刪除文件和目錄樹,謹用!
    XFIND.COM 1,992 在文件中查找字符的工具
    XMSDSK.EXE 11,627 V1.9i 虛擬存盤工具,占很少的內存
    xren.com 128 文件或目錄改名

    78 file(s) 1,224,004 bytes

    ------------------
    EBD98.CAB中的文件
    ------------------
    format.bat 550 21:41 磁盤格式化
    Format98.com 49,655 6:22 磁盤格式化工具(WIN98)
    Mem.exe 32,306 22:22 內存查看工具(WIN98)
    Scandisk.exe 245,924 18:54 磁盤掃描程序(WINME)
    Scandisk.ini 7,329 17:00 磁盤掃描程序配置文件

    -----------------
    TWAY.CAB中的文件
    -----------------
    Key.com 12,712 加載中文輸入法
    quit.com 7 系統退出程序(兼容UCDOS, TWAY系統)
    Qw.exe 5,632 區位碼查看程序
    Tw.bat 730 啟動天匯漢字系統
    tway.exe 204,531 系統主程序
    Tway.ini 6,599 TWAY 3.1 系統初始化配置文件

    DataPY.MB 24,238 拼音、雙拼輸入法
    DataPY000.DT 12,008 拼音自造詞編碼文件(系統自動生成)
    DataWB.MB 33,136 五筆輸入法
    DataWB000.DT 12,008 拼音自造詞編碼文件(系統自動生成)

    ----------------
    FINDCD使用說明 *****以下內容已做更正,感謝Wengier指出*****
    ----------------
    FINDCD 0: 設置光驅數目;
    FINDCD 2: 設置第2個光驅的盤符;不加參數則設置第1個光驅的盤符;
    FINDCD /N:只在屏幕上顯示,而不設置環境變量;
    FINDCD /Q:不在屏幕上顯示,而只設置環境變量;
    FINDCD /S:全部設置模式
    FINDCD /?:幫助;

    ==========
    工具下載:
    1、UMBPCI.SYS v3.45 :
    http://www.uwe-sieber.de/files/umbpci_e.zip
    2、NE.EXE V1.24.2!:
    http://member.netease.com/~lihailin/(推薦)
    3、Doslfn.com V0.32n :
    http://www-user.tu-chemnitz.de/~heha/hs_freeware/doslfn.zip

    上一期,我講述了如何在軟盤的啟動扇區寫一些代碼,然后再從軟盤啟動的過程。制作好一個啟動扇區,在切換到保護模式之前,我們還應該知道如何使用BIOS中斷。BIOS中斷是一些由BIOS提供的、為了使操作系統的創建更容易的低級程序。在本文中,我們將學習處理BIOS的中斷。

    為什么要用BIOS


    BIOS會把啟動扇區拷貝至RAM中,并且執行這些代碼。除此之外,BIOS還要做很多其它的事情。當一個操作系統剛開始啟動時,系統中并沒有顯卡驅動、軟盤驅動等任何驅動程序。因此,啟動扇區中不可能包含任何一個驅動程序,我們要采取其它的途徑。這個時候,BIOS就可以幫助我們了。BIOS中包含有各種可以使用的程序,包括檢測安裝的設備、控制打印機、計算內存大小等用于各種目的的程序。這些程序就是所說的BIOS中斷。

    如何調用BIOS中斷


    在一般的程序設計語言中,函數的調用是一件非常容易的事情。比如在C語言中,如果有一個名為display的程序,它帶有兩個參數,其中參數noofchar表示顯示的字符數,參數attr表示顯示字符的屬性。那么要調用它,只需給出程序的名稱即可。對于中斷的調用,我們使用的是匯編語言中的int指令。

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

    display(nofchar,attr);


    而使用BIOS時,要實現相同功能使用的指令如下:

    int 0x10


    如何傳遞參數


    在調用BIOS中斷之前,我們需要先往寄存器中送一些特定的值。假設要使用BIOS的中斷13h,該中斷的功能是把數據從軟盤傳送至內存之中。在調用該中斷之前,要先指定拷貝數據的段地址,指定驅動器號、磁道號、扇區號,以及要傳送的扇區數等等。然后,就要往相應的寄存器送入相應的值。在進行下面的步驟前,讀者有必要對這一點有比較明確地認識。

    此外,一個比較重要的事實是同一個中斷往往可以實現各種不同的功能。中斷所實現的確切功能取決于所選擇的功能號,功能號一般都存在ah寄存器之中。比如中斷13h可以用于讀磁盤、寫磁盤等功能,如果把3送入ah寄存器中,那么中斷選擇的功能就是寫磁盤;如果把2送入ah寄存器中,選擇的功能則是讀磁盤等。

    我們要做的事情


    這次我們的源代碼由兩個匯編語言程序和一個C程序組成。第一個匯編文件是引導扇區的代碼。在引導扇區中,我們寫的代碼是要把軟盤中第二扇區拷貝至內存段的0x500處(地址是0x5000,即偏移地址為0)。這時我們需要使用BIOS的中斷13h。這時啟動扇區的代碼就會把控制權轉移至0x500處。在第二個匯編文件中,代碼會使用BIOS中斷10h在屏幕上顯示一個信息。C程序實現的功能則是把可執行的文件1拷貝至啟動扇區,把可執行的文件2拷貝至軟盤的第二扇區。

    啟動扇區代碼


    使用中斷13h,啟動扇區把軟盤第二扇區里的內容加載至內存的0x5000處(段地址為0x500)。下面的代碼是用于實現這一目的的代碼,將其保存至文件sbect.s中。

    LOC1=0x500
    entry start
    start:
      mov ax,#LOC1
      mov es,ax
      mov bx,#0 
      mov dl,#0 
      mov dh,#0 
      mov ch,#0 
      mov cl,#2 
      mov al,#1 
      mov ah,#2 
      int 0x13
      jmpi 0,#LOC1


    上面代碼第一行類似于一個宏。接下去的兩行則是把值0x500加載至es寄存器中,這是軟盤上第二扇區代碼將拷貝到的地方(第一扇區是啟動扇區)。這時,把段內的偏移設為0。

    接下來把驅動器號送入dl寄存器中,其中磁頭號送入dl寄存器中,磁道號送入ch寄存器中,扇區號送入cl寄存器中,扇區數送入al寄存器之中。我們想要實現的功能是把扇區2、磁道號為0、驅動器號為0的內容送至段地址0x500處。所有這些參數都和1.44MB的軟盤相對應。

    把2送入ah寄存器中,是選擇了由中斷13h提供的相應功能,即實現從軟驅轉移數據的功能。

    最后調用中斷13h,并且轉至偏移為0的段地址0x500處。

    第二個扇區的代碼


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

    entry start
    start:
      mov     ah,#0x03                
      xor     bh,bh
      int     0x10
    
      mov     cx,#26                  
      mov     bx,#0x0007              
      mov     bp,#mymsg
      mov     ax,#0x1301              
      int     0x10
    
    loop1:  jmp     loop1
    mymsg:
      .byte  13,10
      .ascii “Operating System is Loading......”


    上面代碼將被加載至段地址為0x500處,并且被執行。在這段代碼中,使用了中斷10h來獲取目前的光標位置,然后顯示信息。

    從第3行到第5行用于得到目前光標的位置,在此中斷10h選用的是功能3。然后,清除了bh寄存器的內容,并把字符串送至ch寄存器中。在bx中,我們送入了頁碼及顯示的屬性。此處,我們想要在黑背景上顯示白色的字符。然后,把要顯示字符的地址送到bp之中,信息由兩個字節組成,其值分別為13的10,它們分別對應回車和LF(換行)的ASCⅡ值。接下來是一個由29個字符組成的串;在下面實現的功能是輸出字符串然后移動光標;最后是調用中斷,然后進入循環。

    C程序代碼


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

    #include  /* unistd.h needs this */
    #include     /* contains read/write */
    #include 
    int main()
    {
      char boot_buf[512];
      int floppy_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);
    }


    在上一期中,我曾經介紹過如何操作能啟動的軟盤。現在這一個過程稍微有點不同,首先把由bsect.s編譯出來的可執行文件bsect拷貝至軟盤的啟動扇區。然后再把由sect2.s產生的可執行文件sect2拷貝至軟盤的第二個扇區。

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

    as86 bsect.s -o bsect.o
    ld86 -d bsect.o -o bsect


    對sect2.s文件重復以上的操作,得出可執行文件sect2。編譯write.c,插入軟盤后執行write文件,命令如下所示:

    cc write.c -o write
    ./write


    下一步我們要做的事情


    從軟盤啟動以后,可以看到顯示出來的字符串。這是使用了BIOS中斷來完成的。下一期要做的事情是在這個操作系統中實現實模式向保護模式的轉換。
    posted on 2005-11-21 15:08 天外飛仙 閱讀(1968) 評論(0)  編輯  收藏 所屬分類: 其它
    主站蜘蛛池模板: 免费无码婬片aaa直播表情| 日本视频一区在线观看免费| 国产91免费视频| 日本久久久久亚洲中字幕| 99久久成人国产精品免费| 国产亚洲美女精品久久久2020| 污网站免费在线观看| 久久亚洲AV无码西西人体| 精品乱子伦一区二区三区高清免费播放| 免费一级毛片在线播放| 日本精品久久久久久久久免费| 亚洲精品色婷婷在线影院| 中文字幕视频在线免费观看| 国产亚洲美女精品久久久久狼 | 视频一区在线免费观看| 亚洲v国产v天堂a无码久久| 深夜a级毛片免费无码| 狠狠亚洲狠狠欧洲2019| APP在线免费观看视频| 亚洲欧洲中文日产| 成人免费午夜视频| 国产精品永久免费视频| 亚洲av福利无码无一区二区 | www.av在线免费观看| 1000部拍拍拍18勿入免费视频软件| 亚洲AV永久无码精品一百度影院| 免费精品国产自产拍观看| 国产午夜免费秋霞影院| 99在线免费视频| 噜噜噜亚洲色成人网站∨| 成人毛片18岁女人毛片免费看| 青草青草视频2免费观看| 国产亚洲AV夜间福利香蕉149| 欧洲精品99毛片免费高清观看| 亚洲国产乱码最新视频| 亚洲成A人片在线观看无码3D | 国产免费AV片在线播放唯爱网| 小说专区亚洲春色校园| 亚洲国产精品第一区二区| 日韩午夜免费视频| 污污网站免费观看|