JIURL文檔-Linux的虛擬內存與分頁機制(x86-64位)(一)


作者:JIURL

日期:2015年10月30日

 

分頁機制


    Linux(x64CPU)使用基於分頁機制的虛擬內存。每個進程有256TB(48位)的虛擬地址空間。基於分頁機制,這256TB地址空間的一些部分 被映射了物理內存,一些部分什么也沒有映射。程序中使用的都是256TB地址空間中的虛擬地址。而訪問物理內存,需要使用物理地址。

   物 理地址(physical address):放在尋址總線上的地址。放在尋址總線上,如果是讀,電路根據這個地址每位的值就將相應地址的物理內存中的數據放到數據總線中傳輸。如果 是寫,電路根據這個地址每位的值就將相應地址的物理內存中放入數據總線上的內容。物理內存是以字節(8位)為單位編址與尋址的。

    虛擬地址(virtual address): 256TB虛擬地址空間中的地址,程序中使用的都是虛擬地址。

   如 果CPU相關寄存器中的分頁標志位被設置,那么執行內存操作的機器指令時,CPU會自動根據相應轉換結構(PML4,PDPT,PD,PT)中的信息,把 虛擬地址轉換成物理地址,完成該指令。比如"mov eax,dword ptr[13FF3904Ch]",就是把地址13FF3904Ch處的值賦給寄存器的匯編代碼,13FF3904Ch這個地址就是虛擬地址。CPU在執 行這行代碼時,發現寄存器中的分頁標志位已經被設定,就自動完成虛擬地址到物理地址的轉換,使用物理地址取出值,完成指令。對於x86-64CPU 來說,寄存器CR0的第31位是分頁標志位,為1表示使用分頁,為0表示不使用分頁。對於初始化之后的 Linux 我們通過qemu monitor 觀察 CR0,發現第31位的值為1。表明Linux是使用分頁的。有多個寄存器中的控制位與分頁有關,具體細節可以參考Intel軟件開發手冊。

    x86-64 CPU的實際虛擬地址大小為48位(64位中的低48位,高16位不用於地址轉換),可尋址256TB地址空間。x86-64 CPU的實際物理地址大小,不同的CPU不相同,但最大不超過52位。可以通過機器指令cpuid來查詢該CPU的實際虛擬地址長度和實際物理地址長度。 例如,我查詢了兩台計算機,虛擬地址的大小兩台計算機都為0x30(16進制30就是十進制48),物理地址的大小一台計算機為0x24(16進制24就 是十進制36,36位可尋址64GB),另一台計算機為0x27(16進制27就是十進制39,39位可尋址512GB)。為了后面的敘述方便,我們把 CPU實際物理地址的位數叫做M,比如,對於物理地址大小為36位的CPU,M就是36。

   使用了分頁機制之后,256TB的地址空 間被分成了固定大小的頁(有三種大小,4KB,2MB,1GB),每一頁或者被映射到物理內存,或者沒有映射任何東西。對於一般程序來說,256TB的地 址空間,只有一小部分(滄海一粟)映射了物理內存,大片大片的部分是沒有映射任何東西。物理內存也被分頁,來映射地址空間。對於x86-64,頁的大小有 三種,分別是4KB,2MB,1GB。CPU用來把虛擬地址轉換成物理地址的信息存放在叫做"page map level 4"," page directory pointer","pagedirectory"(頁目錄),"pagetable"(頁表)的結構里。每個進程都有自己的一套 PML4,PDPT,PD,PT結構。一個進程中的虛擬地址,最多需要四級轉換,來得到對應的物理地址。

   物理內存分頁,一個物理頁 的大小為4KB,第0個物理頁從物理地址 0x0000000000000000處開始,大小為4KB(0x1000B),第1個物理頁從物理地址 0x0000000000001000 處開始。第2頁從物理地址0x0000000000002000處開始。由於頁的大小是4KB,所以只需要64位的地址中的M-12bit(低12bit 之后)來尋址物理頁。

    "pagetable"(頁表),一個頁表的大小為4KB,放在一個物理頁中。由512個8字節的PTE(頁表項)組成。頁表項的大小為8個字節(64 位),所以一個頁表中有512個頁表項。頁表中的每一項的內容(每項8個字節,64位)低12位之后的M-12位用來放一個物理頁的物理地址,低 12bit放着一些標志。

    "pagedirectory"(頁目錄),一個頁目錄大小為4KB,放在一個物理頁中。由512個8字節的PDE(頁目錄項)組成。頁目錄項的大小為8 個字節(64位),所以一個頁目錄中有512個頁目錄項。頁目錄中的每一項的內容(每項8個字節,64位)低12位之后的M-12位用來放一個頁表(頁表 放在一個物理頁中)的物理地址,低12bit放着一些標志。

    "pagedirectory pointer"表,一個page directorypointer表大小為4KB,放在一個物理頁中。由512個8字節的PDPTE項組成。PDPTE項的大小為8個字節(64位),所 以一個pagedirectory pointer表中有512個PDPTE。page directorypointer表中的每一項的內容(每項8個字節,64位)低12位之后的M-12位用來放一個頁目錄(頁目錄放在一個物理頁中)的物 理地址,低12bit放着一些標志。

    "page maplevel 4"表,一個page map level4表大小為4KB,放在一個物理頁中。由512個8字節的PML4E項組成。PML4E項的大小為8個字節(64位),所以一個pagemap level 4表中有512個PML4E。page map level4表中的每一項的內容(每項8個字節,64位)低12位之后的M-12位用來放一個page directory pointer表(pagedirectory pointer表放在一個物理頁中)的物理地址,低12bit放着一些標志。

   對於x86-64系統,"page map level 4"表的物理地址放在CPU的CR3寄存器中。

   CPU把虛擬地址轉換成物理地址:
   一 個虛擬地址,大小8個字節(64位,實際只使用低48位),包含着找到物理地址的信息,分為5個部分:第39位到第47位這9位(最高9位) 是"pagemap level 4"表中的索引,第30位到第38位這9位是"page directorypointer"表中的索引,第21位到第29位這9位是頁目錄中的索引,第12位到第20位這9位是頁表中的索引,第0位到第11位 這12位(低12位)是頁內偏移。對於一個要轉換成物理地址的虛擬地址,CPU首先根據CR3中的值,找到"pagemap level4"表所在的物理頁,然后根據虛擬地址的第39位到第47位這9位(最高9位)的值作為索引,找到相應的PML4E項,PML4E項中有這個虛 擬地址所對應的"pagedirectory pointer"表的物理地址。有了"page directorypointer"表的物理地址,根據虛擬地址的第30位到第38位這9位的值作為索引,找到該"page directorypointer"表中相應的PDPTE項,PDPTE項中有這個虛擬地址所對應的頁目錄的物理地址。有了頁目錄的物理地址,根據虛擬地 址的第21位到第29位這9位的值作為索引,找到該頁目錄中相應的頁目錄項,頁目錄項中有這個虛擬地址所對應的頁表的物理地址。有了頁表的物理地址,根據 虛擬地址的第12位到第20位這9位的值作為索引,找到該頁表中相應的頁表項,頁表項中有這個虛擬地址所對應的物理頁的物理地址。最后用虛擬地址的最低 12位,也就是頁內偏移,加上這個物理頁的物理地址,就得到了該虛擬地址所對應的物理地址。

    一個"page maplevel 4"表有512項,虛擬地址從48位向低走的9位剛好可以索引512項(2的9次方等於512),一個"pagedirectorypointer"表有 512項,虛擬地址接下來的9位剛好索引512項。一個頁目錄有512項,虛擬地址接下來的9位剛好索引512項。一個頁表有512項,虛擬地址接下來的 9位剛好索引512項。虛擬地址最低的12位(2的12次方等於4096),作為頁內偏移,剛好可以索引4KB,也就是一個物理頁中的每個字節。

   一 個虛擬地址轉換成物理地址的計算過程就是,處理器通過CR3找到當前"page map level4"表所在物理頁,取虛擬地址從48位向低走的9位,然后把這9位右移3位(因為每個PML4E項8個字節長,右移3位相當於乘8)得到在該頁 中的地址,取出該地址處的PML4E(8個字節),就找到了該虛擬地址對應"pagedirectorypointer"表所在物理頁,然后同樣方法依次 找出該虛擬地址對應的頁目錄所在物理頁,該虛擬地址對應的頁表所在物理頁,該虛擬地址對應的物理頁的物理地址,最后將虛擬地址對應的物理頁的物理地址加上 12位的頁內偏移得到了物理地址。

   48位的一個指針,可以尋址范圍0x000000000000-0xFFFFFFFFFFFF,256TB大小。也就是說一個48位的指針可以尋址整個256TB地址空間的每一個字節。
一個頁表項負責4KB的地址空間和物理內存的映射,一個頁表512項,也就是負責512*4KB=2MB的地址空間的映射。
一個頁目錄項,對應一個頁表。一個頁目錄有512項,也就對應着512個頁表,每個頁表負責2MB地址空間的映射,512個頁表負責512*2MB=1GB的地址空間映射。
一個PDPTE項,對應一個頁目錄。一個"page directorypointer"表有512項,也就對應着512個頁目錄,每個頁目錄負責1GB地址空間的映射。512個頁目錄負責512*1GB=512GB的地址空間映射。
一 個"page map level 4"表項,對應一個"page directory pointer"表。一個"page maplevel 4"表有512項,也就對應着512個"page directory pointer"表,每個"page directorypointer"表負責512GB地址空間的映射。512個"page directorypointer"表負責512*512GB=256TB的地址空間映射。
一個進程有一個"page map level4"表。所以以頁為單位,一套PML4,PDPT,PD,PT結構可以保證256TB的地址空間中的每頁和物理內存的映射。

   一 個虛擬地址在轉換過程中,如果發現對應的PDPTE項的PS位為0則繼續之后的轉換步驟,如果發現對應的PDPTE項的PS位為1,則本PDPTE項中的 物理地址,就是該虛擬地址對應的一個大小為1GB物理頁的地址,該虛擬地址之后的30位為這個1GB物理頁的頁內偏移,就可以得到該虛擬地址對應的物理地 址。

   一個虛擬地址在轉換過程中,如果發現對應的頁目錄項的PS位為0則繼續之后的轉換步驟,如果發現對應的頁目錄項的PS位為1, 則本頁目錄項中的物理地址,就是該虛擬地址對應的一個大小為2MB物理頁的地址,該虛擬地址之后的21位為這個2MB物理頁的頁內偏移,就可以得到該虛擬 地址對應的物理地址。

   虛擬地址48位,尋址256TB。48位地址:9bit+9bit+9bit+9bit+12bit。
每一級表的大小都為4KB。表項大小8B(64位),所以每個表512項。
4級轉換:CR3-> "page map level 4"表-> "page directorypointer"表-> 頁目錄-> 頁表-> 得到物理地址。
一個PTE項對應4KB地址范圍。一張PT表對應512*4KB=2MB地址范圍。
一個PDE項對應2MB地址范圍。一張PD表對應512*2MB=1GB地址范圍。
一個PDPTE項對應1GB地址范圍。一張PDPT表對應512*1GB=512GB地址范圍。
一個PML4E項對應512GB地址范圍。一張PML4表對應512*512GB=256TB地址范圍。
頁大小有3種,4KB,2MB,1GB。

   每 個進程都有自己的256TB地址空間,"0000000000000000 - 00007fffffffffff" 和"ffff800000000000 - ffffffffffffffff" 。因為CPU會忽略高16位,所以相當於"000000000000 - 7fffffffffff" 和 "800000000000 -ffffffffffff"。
因為CPU有特殊規定,被忽略的高16位的每一 位必須等於第47位的值(並會做檢查,不符合規定將引發異常)。"000000000000 -7fffffffffff"的第47位是0,所以高16位也必須都為0。"800000000000 -ffffffffffff"的第47位是1,所以高16位也必須都為1。
每個進程都有自己的256TB地址空間,通過每個進程自己的一套 PML4,PDPT,PD,PT結構來實現。由於每個進程有自己的一套PML4,PDPT,PD,PT結構,所以每個進程的地址空間映射的物理內存是不一 樣的。兩個進程的同一個虛擬地址處(如果都有物理內存映射)的值一般是不同的,因為他們往往對應不同的物理頁。

   256TB地址空間 中低128TB,0x000000000000-0x7fffffffffff是用戶地址空間,256TB地址空間中高 128TB,0x800000000000-0xffffffffffff是系統地址空間。訪問系統地址空間需要程序有ring0的權限。

未完待續...

微博: http://weibo.com/ddqqppb
郵箱:thejiurl@163.com
QQ:6291898

歡迎交流。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM