進程地址空間[4]

   雖然應用程序操作的對象是映射到物理內存之上的虛擬內存,但是處理器直接操作的卻是物理內存。所以當用程序訪問一個虛擬地址時,首先必須將虛擬地址轉化成 物理地址,然後處理器才能解析地址訪問請求。地址的轉化工作需要通過查詢也不才能完成,概括地講,地址轉換需要將虛擬地址分段,使每段虛擬地址都作爲一個 索引指向頁表,而頁表則指向下一級別的頁表或者指向最終的物理頁面。
  linux中使用三級頁表完成地址轉換。利用多級頁表能夠節約地址轉換需要佔用的存放空間。如果利用三級頁錶轉換地址,即使是64位機佔用的空間也有限。Linux對所有體系結構,包括那些不支持三級頁表的體系結構都使用三級頁表管理,因爲使用三級頁表結構可以利用“最大公約數”的思想。
  頂級頁表是頁全局目錄(PGD)。PGD包含了一個pgd_t類型數組,多數體系結構中pgd_t類型等同於無符號長整型類型。PGD中的頁表項指向二級頁目錄中的表項:PMD。
  二級頁表是中間頁目錄(PMD)。PMD是個pmd_t類型數組,其中的表項指向PTE中的表項。
  最後一級的頁表稱爲頁表,其中包含pte_t類型的頁表項,該表項指向物理頁面。
  頁表對應的結構體依賴於具體的體系結構,所以定義在asm/page.h中。

  1. 在文件include/asm-i386/page.h中
  2. #ifdef CONFIG_X86_PAE
  3. extern unsigned long long __supported_pte_mask;
  4. typedef struct { unsigned long pte_low, pte_high; } pte_t;
  5. typedef struct { unsigned long long pmd; } pmd_t;
  6. typedef struct { unsigned long long pgd; } pgd_t;
  7. typedef struct { unsigned long long pgprot; } pgprot_t;
  8. #define pmd_val(x)  ((x).pmd)
  9. #define pte_val(x)  ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
  10. #define __pmd(x) ((pmd_t) { (x) } )
  11. #define HPAGE_SHIFT 21
  12. #include <asm-generic/pgtable-nopud.h>
  13. #else
  14. typedef struct { unsigned long pte_low; } pte_t;
  15. typedef struct { unsigned long pgd; } pgd_t;
  16. typedef struct { unsigned long pgprot; } pgprot_t;
  17. #define boot_pte_t pte_t /* or would you rather have a typedef */
  18. #define pte_val(x)  ((x).pte_low)
  19. #define HPAGE_SHIFT 22
  20. #include <asm-generic/pgtable-nopmd.h>
  21. #endif

  多數體系結構中,搜索頁表的工作由硬件完成。雖然通常操作中,很多使用頁表的工作都可以由硬件執行,但是隻有在內核正確設置頁表的前提下,硬件才能方便操作它們。

   Linux總是假定處理器有三級頁表。每個頁表通過所包含的下級頁表的頁面框號來訪問。下圖給出了虛擬地址是如何分割成多個域的,每個域提供了 某個指定頁表的偏移。爲了將虛擬地址轉換成物理地址,處理器必須得到每個域的值。這個過程將持續三次直到對應於虛擬地址的物理頁面框號被找到。最後再使用 虛擬地址中的最後一個域,得到了頁面中數據的地址。

   爲了實現跨平臺運行,Linux提供了一系列轉換宏使得核心可以訪問特定進程的頁表。這樣核心無需知道 頁表入口的結構以及它們的排列方式。

   這種策略相當成功,無論在具有三級頁表結構的Alpha AXP還是兩級頁表的Intel X86處理器中,Linux總是使 用相同的頁表操縱代碼。


Linux的三級頁表結構


  每個進程都有自己的頁表(線程會共享頁表)。內存描述符的pgd域指向的就是進程的頁全局目錄。操作和檢索頁表時必須使用page_table_lock鎖,該鎖在相應的進程的內存描述符中,以防止競爭條件。 
  由於幾乎每次對虛擬內存中的頁面訪問都必須先解析它,然後得到物理內存中對應的地址,所以頁表的操作性能很關鍵。爲了加快搜索,多數體系結構實現了 TLB(translation lookside buffer)。TLB作爲一個將虛擬地址映射到物理地址的硬件緩存,當請求訪問一個虛擬地址時,處理器將首先檢查TLB中十分緩存了該虛擬地址到物理地 址的映射,如果在緩衝中直接命中,物理地址立刻返回;未命中,就需要再通過頁表搜索需要的物理地址。
  2.6內核對頁表管理的主要改進是:從高端內存分配部分頁表。今後可能的改進包括通過在寫時拷貝(copy-on-write) 的方式共享頁表。這種機制似的在fork()操作中可由父子進程共享頁表。因爲只有當子進程或父進程試圖修改特定頁表項時,內核纔去創建該頁表項的新拷 貝,此後父子進程纔不再共享該頁表項。利用共享頁表可以消除fork()操作中頁表拷貝所帶來的消耗。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章