什麼是實模式、保護模式和虛擬8086方式

1:實模式:尋址採用和8086相同的16位段和偏移量,最大尋址空間1MB,最大分段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。
2:保護模式:尋址採用32位段和偏移量,最大尋址空間4GB,最大分段4GB (Pentium Pre及以後爲64GB)。在保護模式下CPU可以進入虛擬8086方式,這是在保護模式下的實模式程序運行環境。

第一:實模式下程序的運行回顧.
   程序運行的實質是什麼?其實很簡單,就是指令的執行,顯然CPU是指令得以執行的硬件保障,那麼CPU如何知道指令在什麼地方呢?
對了,80x86系列是使用CS寄存器配合IP寄存器來通知CPU指令在內存中的位置.
   程序指令在執行過程中一般還需要有各種數據,80x86系列有DS、ES、FS、GS、SS等用於指示不同用途的數據段在內存中的位置。程序可能需要調用系統的服務子程序,80x86系列使用中斷機制來實現系統服務。
   總的來說,這些就是實模式下一個程序運行所需的主要內容(其它如跳轉、返回、端口操作等相對來說比較次要。)

第二:保護模式---從程序運行說起
   無論實模式還是保護模式,根本的問題還是程序如何在其中運行。因此我們在學習保護模式時應該時刻圍繞這個問題來思考。和實模式下一樣,保護模式下程序運行的實質仍是“CPU執行指令,操作相關數據”,因此實模式下的各種代碼段、數據段、堆棧段、中斷服務程序仍然存在,且功能、作用不變。
   那麼保護模式下最大的變化是什麼呢?答案可能因人而異,我的答案是“地址轉換方式”變化最大。

第三:地址轉換方式比較
   先看一下實模式下的地址轉換方式,假設我們在ES中存入0x1000,DI中存入0xFFFF,那麼ES:DI=0x1000*0x10+0xFFFF=0x1FFFF ,這就是衆所周知的“左移4位加偏移”。
   那麼如果在保護模式下呢?假設上面的數據不變ES=0x1000,DI=0xFFFF,現在ES:DI等於什麼呢?
   公式如下:(注:0x1000=1000000000000b= 10 0000 0000 0 00)
   ES:DI=全局描述符表中第0x200項描述符給出的段基址+0xFFFF(註解:描述符爲8字節,按照ES中的地址在GDT中尋址描述符)
   現在比較一下,好象是不一樣。再仔細看看,又好象沒什麼區別!
   爲什麼說沒什麼區別,因爲我的想法是,既然ES中的內容都不是真正的段地址,憑什麼實模式下稱ES爲“段寄存器”,而到了保護模式就說是“選擇子”?
   其實它們都是一種映射,只是映射規則不同而已:在實模式下這個“地址轉換方式”是“左移4位”;在保護模式下是“查全局/局部描述表”。前者是系統定義的映射方式,後者是用戶自定義的轉換方式。而它
影響的都是“shadow register”
  從函數的觀點來看,前者是表達式函數,後者是列舉式函數:
    實模式:  F(es-->segment)={segment |segment=es*0x10}
    保護模式:F(es-->segment)={segment |(es,segment)∈GDT/LDT}
其中GDT、LDT分別表示全局描述符表和局部描述符表。

第四:保護模式基本組成
   保護模式最基本的組成部分是圍繞着“地址轉換方式”的變化增設了相應的機構。
   1、數據段
   前面說過,實模式下的各種代碼段、數據段、堆棧段、中斷服務程序仍然存在,我將它們統稱爲“數據段”,本文從此向下凡提到數據段都是使用這個定義。
   2、描述符
   保護模式下引入描述符來描述各種數據段,所有的描述符均爲8個字節(0-7),由第5個字節說明描述符的類型,類型不同,描述符的結構也有所不同。
   若干個描述符集中在一起組成描述符表,而描述符表本身也是一種數據段,也使用描述符進行描述。
   從現在起,“地址轉換”由描述符表來完成,從這個意義上說,描述符表是一張地址轉換函數表。
   3、選擇子
   選擇子是一個2字節的數,共16位,最低2位表示RPL,第3位表示查表是利用GDT(全局描述符表)還是LDT(局部描述符表)進行,最高13位給出了所需的描述符在描述符表中的地址。(注:13位正好足夠尋址8K項)

   有了以上三個概念之後可以進一步工作了,現在程序的運行與實模式下完全一樣!!!各段寄存器仍然給出一個“段值”,只是這個“假段值”到真正的段地址的轉換不再是“左移4位”,而是利用描述符表來完成。但現在出現一個新的問題是:系統如何知道GDT/LDT在內存中的位置呢?
   爲了解決這個問題,顯然需要引入新的寄存器用於指示GDT/LDT在內存中的位置。在80x86系列中引入了兩個新寄存器GDR和LDR,其中GDR用於表示GDT在內存中的段地址和段限(就是表的大小),因此GDR是一個48位的寄存器,其中32位表示段地址,16位表示段限(最大64K,每個描述符8字節,故最多有64K/8=8K個描述符)。LDR用於表示LDT在內存中的位置,但是因爲LDT本身也是一種數據段,它必須有一個描述符,且該描述符必須放在GDT中,因此LDR使用了與DS、ES、CS等相同的機制,其中只存放一個“選擇子”,通過查GDT表獲得LDT的真正內存地址。
   對了,還有中斷要考慮,在80x86系列中爲中斷服務提供中斷/陷阱描述符,這些描述符構成中斷描述符表(IDT),並引入一個48位的全地址寄存器存放IDT的內存地址。理論上IDT表同樣可以有8K項,可是因爲80x86只支持256箇中斷,因此IDT實際上最大只能有256項(2K大小)。

第五:新要求---任務篇
   前面介紹了保護模式的基本問題,也是核心問題,解決了上面的問題,程序就可以在保護模式下運行了。
   但衆所周知80286以後在保護模式下實現了對多任務的硬件支持。我的第一反應是:爲什麼不在實模式下支持多任務,是不能還是不願?思考之後,我的答案是:實模式下能實現多任務(也許我錯了:)。因爲多任務的關鍵是有了描述符,可以給出關於數據段的額外描述,如權限等,進而在這些附加信息的基礎上進行相應的控制,而實模式下缺乏描述符,但假設我們規定各段的前2個字節或若干字節用於描述段的附加屬性,我覺得和使用描述符這樣的機制沒有本質區別,如果再附加其他機制...
   基於上述考慮,我更傾向於認爲任務是獨立於保護模式之外的功能。下面我們來分析一下任務。任務的實質是什麼呢?很簡單,就是程序嘛!!所謂任務的切換其實就是程序的切換!!
   現在問題明朗了。實模式下程序一個接一個運行,因此程序運行的“環境”不必保存;保護模式下可能一個程序在運行過程中被暫停,轉而執行下一個程序,我們要做什麼?很容易想到保存程序運行的環境就行了(想想遊戲程序的保存進度功能),比如各寄存器的值等。
   顯然這些“環境”數據構成了一類新的數據段(即TSS)。延用前面的思路,給這類數據段設置描述符(TSS描述符),將該類描述符放在GDT中(不能放在LDT中,因爲80x86不允許:),最後再加一個TR寄存器用於查表(TR相當於先前的段寄存器,用來定位GDT中TSS數據段的描述符,進而得到TSS的段地址)。TR是一個起“選擇子”作用的寄存器,16位。好了,任務切換的基本工作就是將原任務的“環境”存入TSS數據段,更新TR寄存器,系統將自動查GDT表獲得並裝載新任務的“環境”,然後轉到新任務執行。

第六:附加要求---分頁篇
   爲什麼叫附加要求,因爲現在任務還不能很好地工作。前面說過,任務實質上是程序,不同的程序是由不同的用戶寫的,所有這些程序完全可能使用相同的地址空間,而任務的切換過程一般不會包括內存數據的刷新,不是不可能,而是如果那樣做太浪費了。因此必須引入分頁機制纔可能有效地完成對多任務的支持。
   分頁引入的主要目標就是解決不同任務相互之間發生地址衝突的問題。分頁的實質就是實現程序內地址到物理地址的映射,這也是一個“地址轉換”機制,同樣可以使用前面的方案(即類似GDT的做法):首先建立頁表這樣一種數據段,在80x86中使用二級頁表方案,增設一個CR3寄存器用於存放一級頁表(又稱爲頁目錄)在內存中的地址,CR3共32位,其低12位總是爲零,高20位指示頁目錄的內存地址,因此頁目錄總是按頁對齊的。CR3作爲任務“環境”的一部分在任務切換時被存入TSS數據段中。
   當然還得有相應的缺頁中斷機制及其相關寄存器CR2(頁故障線性地址寄存器)。

第七:總結
   保護模式下增加了什麼?
   1、寄存器 GDR LDR IDR TR CR3
   2、數據段 描述符表(GDT LDT) 任務數據段(TSS) 頁表(頁目錄 二級頁表)
   3、機制   權限檢測(利用選擇子/描述符/頁表項的屬性位)
                 線性地址到物理地址的映射

第八:保護模式常用名詞解釋
   前面內容中出現過的不再解釋。
   1、RPL  選擇子當中的權限位確定的權限
   2、CPL  特指CS中的選擇子當中的權限位確定的權限
   3、EPL  EPL=Max(RPL,CPL),即RPL和CPL中數值較大的,或說權限等級較小的
   4、DPL  描述符中的權限位確定的權限
   5、PL   泛指以上4種特權級
   6、任務特權    =CPL
   7、I/O特權     由EFLAGS寄存器的位13、14確定的權限
   8、一致代碼段  一種特殊的代碼段,它在CPL>=DPL時允許訪問,正常的代碼段在CPL=DPL RPL<=DPL時才允許訪問
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章