80386的頁式內存管理
INTEL 1985年推出的80386晶元.
它是80x86系列中的第一種32位微處理器,而且製造工藝也有了很大的進步,與80286相比,80386內部內含27.5萬個晶體管,時鐘頻率為12.5MHz,後提高到20MHz,25MHz,33MHz。80386的內部和外部數據匯流排都是32位,地址匯流排也是32位,可定址高達4GB內存。它除具有實模式和保護模式外,還增加了一種叫虛擬86的工作方式,可以通過同時模擬多個80x86處理器來提供多任務能力。除了標準的80386晶元,也就是80386DX外,出於不同的市場和應用考慮,INTEL又陸續推出了一些其它類型的80386晶元:80386SX、80386SL、80386DL等。
80386最經典的產品為80386DX-33MHz,一般我們說的80386就是指得它。針對內存的速度瓶頸,英特爾為80386設計了高速緩存(Cache),採取預讀內存的方法來緩解這個速度瓶頸。本來最初的設計,80386將內置L1 Cache,但由於工藝、成本、工期等等方面的限制,80386最後並沒有內置L1 Cache,而是將專門開發的L1 Cache晶元放置在CPU之外的主板上,但從此以後,Cache就和CPU成為了如影隨形的東西。另外,80386的內存管理非常先進,有頁式、段式、段頁式三種管理方式,可以管理巨大的內存空間,從而為應用程序提供足夠的舞台.三存內存管理方式實際上就是對應分段部件、分頁部分的各自啟用和同時啟用。
如圖所示, 從算術邏輯單元(ALU)中出來兩路32位地址線,分別用來讀源操作數據和目的操作數,地址首先發給分段部件,如果分段部件沒有啟用,就會透明發給分頁部件。ALU發出的地址稱為邏輯地址,邏輯地址輸入給分段部件後,輸出線性地址(在Linux中也叫虛擬地址),線性地址輸入給分頁部件後,分頁部件輸出物理地址。
分頁部件將內存整齊地劃分為4K大小的頁框,並將這將頁框組件成二級目錄結構。一個線性地址也被理解為由三部分組成,即目錄索引、頁表索引和頁內偏移。
? 目錄索引PD(Page Derectory) ? 頁表索引PT(Page Table) 目錄索引從目錄表中中取得一個目錄項,目錄項是一個指向頁表的指針,頁表索引從頁表中取得一個頁表項,頁表項是一個頁框編號,分頁部件通過頁框編號,頁框編號與頁內編移組合得到線性地址對應的實際物理地址。
通常把各級頁目錄和頁表泛稱為頁表,頁表和段描述符表一樣是每個進程一份,每個進程在恢復執行時,將頁表的首地址放在CR3寄存器里。
CPU在遇到一個訪存指令時,邏輯地址翻譯成線程地址是非常簡單的,具體就是將當前數據段/指令段/附加段選擇子中段基址與指令中的偏移地址相加即可。由於段選擇子對應的段描述符內容已經載入到段選擇子對應的影子寄存器中,這個過程中是不會涉及訪問內存來取得段描述符的。CPU在一定時間內只會訪問內存段選擇子對應的段描述符所描述的段內的數據,當需要段切換時,程序會顯式修改CS/DS/ES寄存器。
線性地址翻譯成物理地址則不然,由於程序訪問的內存在哪個物理頁上是完全不能預測的,因而線程地址翻譯成物理地址時是需要去內存中訪問對應的頁表項(或頁目錄項)的。要訪問一個內存就必需先訪問另一個內存是很搞笑的。因而CPU中增加了一個TLB,即Translation Lookaside Buffer。TLB就是對頁表的一個高速緩存,相當於一段專用的Cache。由於程序的運行也有一定的局部性,因則TLB hit的情況非常高。雖然如此,在TLB miss時,CPU仍然需要去內存中載入頁表以確定這個線程地址對應的物理地址是什麼。 TLB的條目的數量較少,80386有32個。每一個TLB寄存器的每個條目包含一個頁面的信息:有效位,虛頁面號,修改位,保護碼,和頁面所在的物理頁面號,它們和頁面表中的表項一一對應。 由於TLB是頁表的緩存,每個進程都有不同的頁表,CR3存儲著當前進程的頁表道地址,故進程切換時會重新裝載CR3,重新裝載CR3時,TLB裡面的內容會失效。CR3的內容裝載前後一樣的情況下,TLB的刷新也會發生,因為常用這種方式來刷新TLB。
80386僅支持兩級頁表結構,因為當時的內存還都很小。4M 內存就算大的了(是Windows 95的最低要求),運行DOS只需要1M。Pentium Pro下分頁可以是三級。
頁目錄項與頁表項
一個兩級頁表的組織方式如下圖所示: 給定一個線性地址被分成3部分,DIR, TABLE, OFFSET。 翻成物理地址分三步,(1)首先CR3是頁目錄的啟始地址,CR3+DIR處即頁表的啟始地址,(2)從頁表中拿TABLE去索引,得到頁表項,(3)從頁表項中取得bit 12~31為物理地址的高24位地址,拿線性地址的低12位即OFFSET做為物理地址的低12位,組成一個32位物理地址。 一個32位的頁表項中除高24位為物理地址的高32位(也是頁框號),還有12位,被用做一些標記位。用來標記當前頁框是否是髒的,是否可讀可寫,是用戶內存還是系統內存,該內存有沒有被訪問過等。
Linux內核是最期採用3級頁表,2.6.11之後採用4級頁表,原理與兩級頁表一樣。
對於支持多級頁表的處理器,OS可以通過配置寄存器來選擇自己支持幾級頁表,每一級用線程地址中的幾個位來表示。(具體是哪個寄存器暫時沒找到資料,後面補上)。
控制寄存器
段式存儲中,段描述符表的首地址是載入到LDTR寄存器中的。頁式內存管理中,頁表的首地址是載入到CR3寄存器中的。
分段部件可以通過CR0的bit 0來使能,分頁部件則是通過CR0的bit 31來使能。兩者都使能則是段頁式內存管理方式。
CR0
CR0的低16位包含了與80286的MSW一致的位定義,保持了和80286的兼容,同時也兼容了從80286開始的兩條指令LMSW/SMSW。指令LMSW和SMSW分別用於裝入和保存機器狀態字信息,可以通過MOV指令對CR0進行讀寫操作。CR0中各位含義如下: PE(Protection Enable)保護模式允許位,用來啟動CPU進入虛地址保護方式。PE=0表示CPU工作在實地址方式;PE=1表示CPU工作在虛地址保護方式。 MP(Monitor Coprocessor)監控協處理器,MP=1表示協處理器在工作;MP=0表示協處理器未工作。 EM(Emulation)協處理器模擬,當MP=0,EM=1時,表示正在使用軟體模擬協處理器工作。 TS(Task Switched)任務轉換,每當進行任務轉換時,TS=1;任務轉換完畢,TS=0。TS=1時不允許協處理器工作。 ET(Extension Type)處理器擴展類型,反映了所擴展的協處理器的類型,ET=0為80287,ET=1為80387。 PG(Paging)頁式管理機制使能,PG=1時頁式管理機制工作,否則不工作。 NE(Numeric Error)數值異常中斷控制,NE=1時,如果運行協處理器指令發生故障,則用異常中斷處理,NE=0時,則用外部中斷處理。 WP(Write Protect)防寫,當WP=1時,對只讀頁面進行寫操作會產生頁故障。 AM(Alignment Mask)對齊標誌,AM=1時,允許對齊檢查,AM=0時不允許,關於對齊,在EFLAGS的AC標誌時介紹過,在80486以後的CPU中,CPU進行對齊檢查需要滿足三個條件,AC=1、AM=1並且當前特權級為3。 NW(Not Write-through)和CD(Cache Disable),這兩個標誌都是用來控制CPU內部的CACHE的,當NW=0且CD=0時,CACHE使能,其它的組合比較複雜。 前4個定義從80286開始,接著的2個定義從80386開始存在, 後面4個是從80486開始定義的。
CR1
CR1寄存器用來保留給Intel微處理器將來開發使用;
CR2
CR2寄存器包含一個32位的線性地址,指向發生最後一次也故障的地址,只有在PG=1時,CR2才有效,當頁故障處理程序被激活時,壓入頁故障處理程序堆棧中的錯誤碼提供頁故障的狀態信息;
CR3
CR3寄存器中包含頁物理目錄表的物理基地址,由於每4KB為一頁,80386中的頁目錄表總在頁的整數邊界上,CR3的低13位總是為0,只有當CR0中的PG=1時,CR3的頁目錄基地址才有效。
推薦閱讀:
※我想學習x86下的linux內核,該怎麼起步?
※80286與保護模式
※ARM處理器簡介
※如果說 RISC 的性能不如 CISC,那為什麼很多超算是 RISC 架構的?