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

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

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

    飛艷小屋

    程序--人生--哲學(xué)___________________歡迎艷兒的加入

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

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


    自從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)的所有特色都是可用的,并且能夠達到最高的性能。

    保護模式和實模式


    從表面上看,保護模式和實模式并沒有太大的區(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),而在保護模式中,段長是可變的,其最大可達4GB。LDT也是段描述符的一個數(shù)組。與GDT不同,LDT是一個段,其中存放的是局部的、不需要全局共享的段描述符。每一個操作系統(tǒng)都必須定義一個GDT,而每一個正在運行的任務(wù)都會有一個相應(yīng)的LDT。每一個描述符的長度是8個字節(jié),格式如圖3所示。當(dāng)段寄存器被加載的時候,段基地址就會從相應(yīng)的表入口獲得。描述符的內(nèi)容會被存儲在一個程序員不可見的影像寄存器(shadow register)之中,以便下一次同一個段可以使用該信息而不用每次都到表中提取。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實模式和保護模式的不同可以從圖1和圖2中很清楚地看出來。

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

    進入保護模式


    80386有4個32位控制寄存器,名字分別為CR0、CR1、CR2和CR3。CR1是保留在未來處理器中使用的,在80386中沒有定義。CR0包含系統(tǒng)的控制標(biāo)志,用于控制處理器的操作模式和狀態(tài)。CR2和CR3是用于控制分頁機制的。在此,我們關(guān)注的是CR0寄存器的PE位控制,它負責(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)以清除在實模式下讀取的任何指令。 



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

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

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


    需要的工具


    ● as86:這是一個匯編程序,它負責(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。在我使用的Red Hat 7.3中就包含有這兩個工具,并且在默認的情況下,它已經(jīng)安裝在機器里。如果使用的Linux沒有這兩個工具,可以從網(wǎng)上下載(http://www.cix.co.uk/~mayday/),這兩個工具都包含在一個名為bin86的軟件包中。此外,有關(guān)的文檔也可以在網(wǎng)上獲得(www.linux.org/docs/ldp/howto/Assembly-HOWTO/as86.html)。


    開始工作


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

    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處開始執(zhí)行。0xb800是顯存的開始地址。#表明其后是一個立即數(shù)。執(zhí)行語句:

    mov ax,#oxb800



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

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

    此處顯存的概念說得不是很清楚,有必要進一步解釋一下。假設(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)容如下:

    #i nclude /* unistd.h 需要這個文件 */
    #i nclude /* 包含有read和write函數(shù) */
    #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文件,然后在打開文件時把文件描述符復(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í)行文件:

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



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

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

    ./write



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

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

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

    作者:伊梅 本文選自:開放系統(tǒng)世界——賽迪網(wǎng) 2002年11月01日

    上一期,我講述了如何在軟盤的啟動扇區(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中斷。


    如何調(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)相同功能使用的指令如下:

    int 0x10




    如何傳遞參數(shù)


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

    此外,一個比較重要的事實是同一個中斷往往可以實現(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
    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寄存器中,這是軟盤上第二扇區(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之中):

    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處,并且被執(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)。


    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);
    }



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

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

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



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

    cc write.c -o write
    ./write




    下一步我們要做的事情


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

    在上兩期中(自己動手寫操作系統(tǒng)1,2),我向大家講述了如何使用Linux提供的開發(fā)工具在軟盤的啟動扇區(qū)寫一些代碼,以及如何調(diào)用BIOS的問題。現(xiàn)在,這個操作系統(tǒng)已經(jīng)越來越接近當(dāng)年Linus Torvalds的那個具有“歷史意義”的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)的所有特色都是可用的,并且能夠達到最高的性能。


    保護模式和實模式


    從表面上看,保護模式和實模式并沒有太大的區(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),而在保護模式中,段長是可變的,其最大可達4GB。LDT也是段描述符的一個數(shù)組。與GDT不同,LDT是一個段,其中存放的是局部的、不需要全局共享的段描述符。每一個操作系統(tǒng)都必須定義一個GDT,而每一個正在運行的任務(wù)都會有一個相應(yīng)的LDT。每一個描述符的長度是8個字節(jié),格式如圖3所示。當(dāng)段寄存器被加載的時候,段基地址就會從相應(yīng)的表入口獲得。描述符的內(nèi)容會被存儲在一個程序員不可見的影像寄存器(shadow register)之中,以便下一次同一個段可以使用該信息而不用每次都到表中提取。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實模式和保護模式的不同可以從圖1和圖2中很清楚地看出來。

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


    進入保護模式


    80386有4個32位控制寄存器,名字分別為CR0、CR1、CR2和CR3。CR1是保留在未來處理器中使用的,在80386中沒有定義。CR0包含系統(tǒng)的控制標(biāo)志,用于控制處理器的操作模式和狀態(tài)。CR2和CR3是用于控制分頁機制的。在此,我們關(guān)注的是CR0寄存器的PE位控制,它負責(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編譯器

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

    org 0x07c00; 起始地址是0000:7c00
    jmp short begin_boot ; 跳過其它的數(shù)據(jù),跳轉(zhuǎn)到引導(dǎo)程序的開始處
    bootmesg db "Our OS boot sector loading ......"
    pm_mesg db "Switching to protected mode ...."
    dw 512 ; 每一扇區(qū)的字節(jié)數(shù)
    db 1 ; 每一簇的扇區(qū)數(shù)
    dw 1 ; 保留的扇區(qū)號
    db 2
    dw 0x00e0
    dw 0x0b40
    db 0x0f0
    dw 9
    dw 18
    dw 2 ; 讀寫扇區(qū)號
    dw 0 ; 隱藏扇區(qū)號
    print_mesg :
    mov ah,0x13 ; 使用中斷10h的功能13,在屏幕上寫一個字符串
    mov al,0x00 ; 決定調(diào)用函數(shù)后光標(biāo)所處的位置
    mov bx,0x0007 ; 設(shè)置顯示屬性
    mov cx,0x20 ; 在此字符串長度為32
    mov dx,0x0000 ; 光標(biāo)的起始行和列
    int 0x10 ; 調(diào)用BIOS的中斷10h
    ret ; 返回調(diào)用程序
    get_key :
    mov ah,0x00
    int 0x16 ; Get_key使用中斷16h的功能0,讀取下一個字符
    ret
    clrscr :
    mov ax,0x0600 ; 使用中斷10h的功能6,實現(xiàn)卷屏,如果al=0則清屏
    mov cx,0x0000 ; 清屏
    mov dx,0x174f ; 卷屏至23,79
    mov bh,0 ; 使用顏色0來填充
    int 0x10 ; 調(diào)用10h中斷
    ret
    begin_boot :
    call clrscr ; 先清屏
    mov bp,bootmesg ; 提供串地址
    call print_mesg ; 輸出信息
    call get_key ; 等待用戶按下任一鍵
    bits 16
    call clrscr ; 清屏
    mov ax,0xb800 ; 使gs指向顯示內(nèi)存
    mov gs,ax ; 在實模式下顯示一個棕色的A
    mov word [gs:0],0x641 ; 顯示
    call get_key ; 調(diào)用Get_key等待用戶按下任一鍵
    mov bp,pm_mesg ; 設(shè)置串指針
    call print_mesg ; 調(diào)用print_mesg子程序
    call get_key ; 等待按鍵
    call clrscr ; 清屏
    cli ; 關(guān)中斷
    lgdt[gdtr] ; 加載GDT
    mov eax,cr0
    or al,0x01 ; 設(shè)置保護模式位
    mov cr0,eax ; 將更改后的字送至控制寄存器中
    jmp codesel:go_pm
    bits 32
    go_pm :
    mov ax,datasel
    mov ds,ax ; 初始化ds和es,使其指向數(shù)據(jù)段
    mov es,ax
    mov ax,videosel ; 初始化gs,使其指向顯示內(nèi)存
    mov gs,ax
    mov word [gs:0],0x741 ; 在保護模式下顯示一個白色的字符A
    spin : jmp spin ; 循環(huán)
    bits 16
    gdtr :
    dw gdt_end-gdt-1 ; gdt的長度
    dd gdt ; gdt的物理地址
    gdt
    nullsel equ $-gdt ; $指向當(dāng)前位置,所以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寫入到軟盤的第一扇區(qū)之中。然后重新啟動系統(tǒng),就會看到如下的信息:

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




    對代碼的解釋


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

    ◆ 使用的函數(shù)

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

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

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

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

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

    ◆ 其它內(nèi)容

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

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

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

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

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

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


    下一步要做的事


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

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

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

      一個操作系統(tǒng)的使用,依次會涉及到硬盤引導(dǎo)、操作系統(tǒng)引導(dǎo)、載入基本操作系統(tǒng)、定義臨時目錄、定義虛擬內(nèi)存盤、載入系統(tǒng)服務(wù)、載入自定義服務(wù)、定義GUI這幾個步驟,這是不管Windows、Linux還是Freebsd等操作系統(tǒng)都是如此。也就是說,我們?nèi)绻鼙M量優(yōu)化上面每個步驟,則就能把系統(tǒng)的性能提升起來。接下來,就讓我們一起把每個步驟做到最優(yōu)。

      1、硬盤引導(dǎo)

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

      [Paths]

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

      WinBootDir=C:\Windows ;引導(dǎo)目錄

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

      [Options]

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

      BootGUI=1;是否圖形引導(dǎo)

      DoubleBuffer=1;雙倍緩沖,建議設(shè)置為1

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

      WinVer=4.10.2222;Windows的版本號

      BootWin=1;以Windows方式引導(dǎo)

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

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

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

      BootDelay=0;引導(dǎo)延遲,設(shè)置成0最快

      DisableLog=0;不記錄引導(dǎo)時候的log,如果追求速度,可以設(shè)置成1

      2、操作系統(tǒng)引導(dǎo)

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

      3、載入基本操作系統(tǒng)

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

      4、定義臨時目錄

      由于操作系統(tǒng)在執(zhí)行一些煩瑣的運算、解壓縮文件的時候,都是先將文件臨時放在某個目錄下,在任務(wù)執(zhí)行完后再刪除。Windows下默認是放在操作系統(tǒng)下的temp目錄中,UNIX下默認是放在/tmp中。如果我們能想辦法提高其讀寫速度,則就能在這步中達到優(yōu)化的效果。由于硬盤的物理形態(tài)因素,導(dǎo)致硬盤在內(nèi)區(qū)讀寫速度會比外區(qū)更快一些,因此考慮將臨時目錄放在靠近磁盤內(nèi)區(qū)物理位置的地方。在Windows、UNIX等大多數(shù)操作系統(tǒng)情況下,都是越分在前面的分區(qū)越靠近內(nèi)區(qū),越分在后面的分區(qū)越靠近外區(qū)。UNIX下可在劃分了/boot后,馬上劃分/tmp分區(qū);在Windows下由于根據(jù)第3條中提到的盡量減少操作系統(tǒng)所在分區(qū)的讀寫操作,因此我們將臨時目錄建在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.在“系統(tǒng)變量”這里,將temp和tmp的值,都改為d:\temp;

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

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

      5、定義虛擬內(nèi)存盤

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

      Win 9x: 

      1.打開“控制面板”——“屬性”——“性能”——“虛擬內(nèi)存”;

      2.將虛擬內(nèi)存指定為自定義,選擇d盤;

      3.重新啟動計算機;

      Win 2k:

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

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

      3.選中“虛擬內(nèi)存”這里的“更改”

      4.將c盤的虛擬內(nèi)存去掉,將d盤的虛擬內(nèi)存根據(jù)需要進行適當(dāng)設(shè)置;

      5.重新啟動計算機;

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

      6、載入系統(tǒng)服務(wù)

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

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

      7、載入自定義服務(wù)

      之所以要把這一步與上面的一步分開,一來是因為他們存放的啟動文件位置有差異,二來有的系統(tǒng)服務(wù)是必須啟動的,如果不啟動則連操作系統(tǒng)也無法按照常規(guī)方式運行起來。例如Win2k服務(wù)中的“Logical Disk Manager(邏輯磁盤管理器監(jiān)視狗服務(wù))”就是專門對硬盤進行管理的。自定義的服務(wù)項目,在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命令,非常簡單明了。一般來說,這一部分的服務(wù)即使全部去掉,也不會影響系統(tǒng)的啟動,但有的操作系統(tǒng)“原裝”服務(wù)可以令我們使用的時候更得心應(yīng)手。同時在這里,也是很多Windows木馬藏身的地方。

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

      8、定義GUI

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

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

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

    ---------
    已寫文件列表
    ---------
    aspi2dos.sys 18,802 實模式的 Adaptec CD-ROM 驅(qū)動程序
    aspi4dos.sys 8,913 實模式的 Adaptec CD-ROM 驅(qū)動程序
    aspi8dos.sys 22,077 實模式的 Adaptec CD-ROM 驅(qū)動程序
    aspi8u2.sys 24,001 實模式的 Adaptec CD-ROM 驅(qū)動程序
    aspicd.sys 10,002 實模式的 Adaptec CD-ROM 驅(qū)動程序
    ASPIDISK.SYS 6,499 SCSI驅(qū)動器驅(qū)動程序
    ASPIOHCI.SYS 16,001 Iomega公司出的OHCI接口的USB驅(qū)動器的驅(qū)動程序
    ASPIUHCI.SYS 16,624 Iomega公司出的UHCI接口的USB驅(qū)動器的驅(qū)動程序
    Attrib.com 5,277 XATTRIB.COM查看、設(shè)置文件/目錄屬性
    AUTOEXEC.BAT 3,991 自動批處理文件
    CABFIND.COM 2,609 在CAB包中搜索文件的工具
    CCD.EXE 1,110 目錄快速轉(zhuǎn)換工具
    Cdrom.bat 2,133 安裝通用光驅(qū)驅(qū)動程序
    Choice.com 510 選擇命令,返回按鍵的ERRORLEVEL值
    Cmos.com 630 清除/保存COMOS信息
    Command.com 94,292 MS-DOS 7.1 命令解釋程序
    Config.sys 2,523 啟動配置文件,加載設(shè)備驅(qū)動程序
    CP936UNI.TBL 15,505 DOSLFN 0.32n 簡體中文代碼頁
    CtMouse.exe 4,898 鼠標(biāo)驅(qū)動程序CTMOUSE v1.9,可驅(qū)動COM和PS2口鼠標(biāo)
    Debug.com 14,593 V0.95c 程序調(diào)試命令
    Deltree.com 3,069 V1.2c 刪除整個目錄,從FREEDOS中補充的外部命令
    DI1000DD.SYS 8,483 Motto Hairu中的USB硬盤的驅(qū)動程序
    Doskey.com 4,640 V1.5 命令行記憶程序,Tab/Shift+Tab 選擇文件或目錄
    Doslfn.com 11,020 V0.32n,DOS中文/英文長文件名驅(qū)動程序
    DOSVER.COM 2,156 V2.11 實用的設(shè)置DOS版本號的工具
    DRVLOAD.COM 1,716 加載驅(qū)動程序的工具
    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 分區(qū)及啟動管理(Boot Manager)程序
    FINDCD.EXE 3,128 最好用的光驅(qū)查找工具 (作者: Wengier).
    Findramd.exe 2,464 查找虛擬盤的工具
    Himem.sys 10,306 XMS 內(nèi)存管理程序
    Ifshlp.sys 2,784 增強的文件管理驅(qū)動程序,支持WIN的VFAT系統(tǒng)(Windows必需)
    Io.sys 213,977 系統(tǒng)引導(dǎo)文件
    Killer.exe 2,435 killr100可以自動截獲非法指令,防止死機
    Key.com 977 KPUSH.COM V2.0 鍵盤ASCII表查詢及清理工具
    LFNXLAT.386 867 為DOSLFN長文件名驅(qū)動程序提供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下用鼠標(biāo)復(fù)制/粘帖的工具
    Msdos.sys 122 引導(dǎo)選項信息(路徑、多層引導(dǎo)等等)
    Msdos.sy_ 1,661 win98系統(tǒng)啟動配置文件msdos.sys備份.
    Ne.exe 36,148 V1.24.2! 仿照PCTOOLS5的文件管理工具,十六進制編器.
    Nset.com 974 從輸出中取得變量以設(shè)置,FINDCD -a|NSET CDROM=$1
    NTFSDOS.EXE 26,507 V3.02R DOS的NTFS驅(qū)動程序
    Off.com 451 Shutdown 非常好的命令行ATX電源重新啟動/軟關(guān)機程序
    QF.EXE 23,313 FDISK和FORMAT加速,可節(jié)省時間
    readme.txt 6,077 本說明文件
    Reboot.com 16 重新啟動計算機
    RESET.COM 588 重新啟動DOS系統(tǒng)
    Shsucdx.exe 6,800 v1.4b 光驅(qū)驅(qū)動程序,可取代MSCDEX
    Sm.exe 13,272 磁盤緩沖工具SMARTDRV
    SORT.COM 1,630 小巧的排序工具
    SRCBOOT.COM 2,590 保存/恢復(fù)/比較磁盤的啟動扇區(qū)的小工具
    SRCFAT.COM 2,715 保存/恢復(fù)/比較磁盤的文件分配表(FAT)的小工具
    SRCMBR.COM 2,516 保存/恢復(fù)/比較磁盤的主引導(dǎo)記錄(MBR)的小工具
    SUBST.COM 1,469 小巧的設(shè)置虛擬驅(qū)動器的程序
    Sys.com 9,321 DOS系統(tǒng)文件傳輸程序
    tw.bat 1,241 啟動天匯中文DOS漢字系統(tǒng)
    Tway.cab 253,936 天匯3.1中文DOS漢字操作系統(tǒng)壓縮包
    Umbpci.sys 5,684 v3.45,很有用的UMB驅(qū)動程序,可以提供高達160多K的UMB
    USBASPI.SYS 15,480 Motto Hairu中的USB驅(qū)動程序
    USBCD.SYS 5,509 Motto Hairu中的USB/SCSI光驅(qū)的驅(qū)動程序
    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 驅(qū)動器的通用設(shè)備驅(qū)動程序,占用內(nèi)存只有5K
    Xcopy.exe 16,442 V1.1 加強的COPY命令,可復(fù)制整個目錄
    xdel.exe 1,651 刪除文件和目錄樹,謹用!
    XFIND.COM 1,992 在文件中查找字符的工具
    XMSDSK.EXE 11,627 V1.9i 虛擬存盤工具,占很少的內(nèi)存
    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 內(nèi)存查看工具(WIN98)
    Scandisk.exe 245,924 18:54 磁盤掃描程序(WINME)
    Scandisk.ini 7,329 17:00 磁盤掃描程序配置文件

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

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

    ----------------
    FINDCD使用說明 *****以下內(nèi)容已做更正,感謝Wengier指出*****
    ----------------
    FINDCD 0: 設(shè)置光驅(qū)數(shù)目;
    FINDCD 2: 設(shè)置第2個光驅(qū)的盤符;不加參數(shù)則設(shè)置第1個光驅(qū)的盤符;
    FINDCD /N:只在屏幕上顯示,而不設(shè)置環(huán)境變量;
    FINDCD /Q:不在屏幕上顯示,而只設(shè)置環(huán)境變量;
    FINDCD /S:全部設(shè)置模式
    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

    上一期,我講述了如何在軟盤的啟動扇區(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中斷。

    如何調(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)相同功能使用的指令如下:

    int 0x10


    如何傳遞參數(shù)


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

    此外,一個比較重要的事實是同一個中斷往往可以實現(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
    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寄存器中,這是軟盤上第二扇區(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之中):

    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處,并且被執(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)。

    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);
    }


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

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

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


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

    cc write.c -o write
    ./write


    下一步我們要做的事情


    從軟盤啟動以后,可以看到顯示出來的字符串。這是使用了BIOS中斷來完成的。下一期要做的事情是在這個操作系統(tǒng)中實現(xiàn)實模式向保護模式的轉(zhuǎn)換。
    posted on 2005-11-21 15:08 天外飛仙 閱讀(1968) 評論(0)  編輯  收藏 所屬分類: 其它
    主站蜘蛛池模板: 中文字幕精品亚洲无线码二区| 国产精品亚洲а∨无码播放不卡| 伊在人亚洲香蕉精品区麻豆| 日韩精品无码免费一区二区三区 | 亚洲女初尝黑人巨高清| 成年丰满熟妇午夜免费视频| 无码日韩精品一区二区三区免费| 一区在线免费观看| 亚洲AV永久无码精品网站在线观看| 久久久久亚洲AV无码专区首| 亚洲国产免费综合| 免费观看美女裸体网站| xx视频在线永久免费观看| 中文字幕在线免费看线人| 全黄A免费一级毛片| 亚洲国产精品自在自线观看| 亚洲a级成人片在线观看| 久久亚洲sm情趣捆绑调教| 亚洲精品无码久久一线| 亚洲精品97久久中文字幕无码| 蜜臀91精品国产免费观看| 在线视频观看免费视频18| 国产四虎免费精品视频| 久久精品私人影院免费看| 久久99久久成人免费播放| 五月天婷婷精品免费视频| 黄色免费在线网址| 日韩久久无码免费毛片软件| MM1313亚洲精品无码久久| 亚洲AV无码一区二区三区网址 | 日韩大片在线永久免费观看网站| 亚洲啪AV永久无码精品放毛片| 亚洲色欲色欲www| 亚洲啪啪免费视频| 亚洲人配人种jizz| 国产亚洲精品VA片在线播放| 亚洲激情视频图片| 亚洲日韩AV无码一区二区三区人| 亚洲第一男人天堂| 亚洲av无码成人影院一区| 免费无码午夜福利片|