32位和64位

系統32位和64位應該指的是地址線位數,但是不是物理地址總線地址,而應該是虛擬地址。對於Linux而言,就是線性地址寬度(沒有使用分段機制,以及開啓分頁機制)。

64位的內核不是意味着就有64根地址線(虛擬地址)。因爲沒必要,實際不需要那麼大內存。假設你有38位地址線(虛擬地址),可以尋址到2048G的內存,也按照3:1劃分,那麼內核態就有512G範圍,你的512G物理內存可以一次性的全部映射到內核空間,根本不需要高端內存。

Intel 32位有四種,32-bit(4KB頁大小和4MB頁大小)和PAE(4KB頁大小和2MB頁大小)。

然而, 大型服務器需要大於4GB的RAM來同時運行數以錢計的進程, 所以必須擴展32位80x86架構所支持的RAM容量.

Intel通過在它的處理器上把管腳數從32增加到36滿足這樣的需要, 從Pentinum Pro開始, Intel所有處理器的尋址能力可達到2^36=64GB, 但是隻有引入一種新的分頁機制才能把32位現行地址轉換爲36位物理地址才能使用所增加的物理地址.

從Pentinum Pro處理器開始, Intel引入一種叫做物理地址擴展(Physical Address Extension, PAE)的機制.

從Pentium模型開始,80x86微處理器引入了擴展分頁(externded paging),也叫頁大小擴展[Page Size Extension], 它允許頁框大小爲4MB而不是4KB。擴展分頁用於把大段連續的線性地址轉換成相應的物理地址,在這種情況下,內核可以不用中間頁表進行地址轉換,從而節省內存並保留TLB項。

Linux沒有采用4MB頁大小

正如前面所述,通過設置頁目錄項的Page Size標誌啓用擴展分頁功能。在這種情況下,分頁單元把32位線性地址分成兩個字段: Directory:最高10位。 Offfset:其餘22位。

擴展分頁和正常分頁的頁目錄項基本相同,除了

  • Page Size標誌必須被設置。
  • 20位物理地址字段只有最高10位是有意義的。這是因爲每一個物理地址都是在以4MB爲邊界的地方開始的,故這個地址的最低22位爲0。

通過設置cr4處理器寄存器的PSE標誌能使擴展分頁與常規分頁共存

Intel爲了支持PAE改變了分頁機制

  • 64GB的RAM被分成了2^24個頁框,頁表項的物理地址字段從20位擴展到了24位.因爲PAE頁表項必須包含12個標誌位(4K頁大小,偏移offset位數需要12位)和24個物理地址位(因爲頁框是2^24個,所以需要24位物理地址位),總數之和爲36,頁表項大小從32位擴展到了64位,結果,一個4KB的頁表項包含512個表項而不是1024個表項

  • 引入一個頁目錄指針表(Page Directory Pointer Table,PDPT)的頁表新級別,它由4個64位表項組成.

  • cr3控制寄存器包含一個27位的頁目錄指針表(PDPT)基地址字段.因爲PDPT存放在RAM的前4GB中,並在32字節(2^5)的倍數上對其, 因此27位足以表示這種表的基地址

  • 當把線性地址映射到4KB的頁時(頁目錄項中的PS標準清0), 32位線性地址將按照如下方式解釋

config

當把現行地址映射到2MB的頁時(頁目錄項中的PS標誌置爲1), 32位線性地址按照如下方式解釋

config

總之, 一旦cr3被設置, 就可能尋址高達4GB RAM, 如果我們期望堆更多的RAM進行尋址, 就必須在cr3中放置一個新值, 或改變PDPT的內容.

但是PAE的主要問題是線性地址仍然是32位長, 這就需要內核黑客用同一線性地址映射不同的RAM區. 很顯然, PAE並沒有擴大進程的線性地址空間, 因爲它只處理物理地址. 此外, 只有內核能夠修改進程的頁表, 所以在用戶態下運行的程序不可能使用大於4GB的物理地址空間. 另一方面, PAE允許內核使用容量高達64GB的RAM, 從而顯著的增加系統中的進程數目。

正常來說, 對於32位的系統兩級頁表已經足夠了, 但是對於64位系統的計算機, 這遠遠不夠.

首先假設一個大小爲4KB的標準頁.因爲1KB覆蓋210個地址的範圍,4KB覆蓋212個地址,所以offset字段需要12位.這樣線性地址空間就剩下64-12=52位分配給頁中間表Table和頁目錄表Directory.如果我們現在決定僅僅使用64位中的48位來尋址(這個限制其實已經足夠了,2^48=256TB,即可達到256TB的尋址空間).剩下的48-12=36位被分配給Table和Directory字段.即使我們現在決定位兩個字段各預留18位,那麼每個進程的頁目錄和頁表都包含218個項, 即超過256000個項.

基於這個原因, 所有64位處理器的硬件分頁系統都使用了額外的分頁級別.使用的級別取決於處理器的類型

config

注:ia64是intel的一門高端技術,不與x86_64系統兼容;IA-32e Paging機制下線性地址映射到4KB的頁

當然,如果沒有開啓分頁,線性地址就是物理地址。

不同架構的分頁機制

對於不同的體系結構,Linux採用的四級頁表目錄的大小有所不同:對於i386而言,僅採用二級頁表,即頁上層目錄和頁中層目錄長度爲0;對於啓用PAE的i386,採用了三級頁表,即頁上層目錄長度爲0;對於64位體系結構,可以採用三級或四級頁表,具體選擇由硬件決定。

對於沒有啓用物理地址擴展的32位系統,兩級頁表已經足夠了。從本質上說Linux通過使「頁上級目錄」位和「頁中間目錄」位全爲0,徹底取消了頁上級目錄和頁中間目錄字段。不過,頁上級目錄和頁中間目錄在指針序列中的位置被保留,以便同樣的代碼在32位系統和64位系統下都能使用。內核爲頁上級目錄和頁中間目錄保留了一個位置,這是通過把它們的頁目錄項數設置爲1,並把這兩個目錄項映射到頁全局目錄的一個合適的目錄項而實現的。

啓用了物理地址擴展的32 位系統使用了三級頁表。Linux 的頁全局目錄對應80x86 的頁目錄指針表(PDPT),取消了頁上級目錄,頁中間目錄對應80x86的頁目錄,Linux的頁表對應80x86的頁表。

最終,64位系統使用三級還是四級分頁取決於硬件對線性地址的位的劃分。

線性地址轉換成物理地址

地址轉換過程有了上述的基本知識,就很好理解四級頁表模式下如何將虛擬地址轉化爲邏輯地址了。基本過程如下:

  1. 從CR3寄存器中讀取頁目錄所在物理頁面的基址(即所謂的頁目錄基址),從線性地址的第一部分獲取頁目錄項的索引,兩者相加得到頁目錄項的物理地址。

  2. 第一次讀取內存得到pgd_t結構的目錄項,從中取出物理頁基址取出(具體位數與平臺相關,如果是32系統,則爲20位),即頁上級頁目錄的物理基地址。

  3. 從線性地址的第二部分中取出頁上級目錄項的索引,與頁上級目錄基地址相加得到頁上級目錄項的物理地址。

  4. 第二次讀取內存得到pud_t結構的目錄項,從中取出頁中間目錄的物理基地址。

  5. 從線性地址的第三部分中取出頁中間目錄項的索引,與頁中間目錄基址相加得到頁中間目錄項的物理地址。

  6. 第三次讀取內存得到pmd_t結構的目錄項,從中取出頁表的物理基地址。

  7. 從線性地址的第四部分中取出頁表項的索引,與頁表基址相加得到頁表項的物理地址。

  8. 第四次讀取內存得到pte_t結構的目錄項,從中取出物理頁的基地址。

  9. 從線性地址的第五部分中取出物理頁內偏移量,與物理頁基址相加得到最終的物理地址。

  10. 第五次讀取內存得到最終要訪問的數據。

整個過程是比較機械的,每次轉換先獲取物理頁基地址,再從線性地址中獲取索引,合成物理地址後再訪問內存。不管是頁表還是要訪問的數據都是以頁爲單 位存放在主存中的,因此每次訪問內存時都要先獲得基址,再通過索引(或偏移)在頁內訪問數據,因此可以將線性地址看作是若干個索引的集合。

參照:http://blog.csdn.net/gatieme/article/details/52402967