//接前一篇部落格:
本節主要講述linux中的分頁機制,注意對比linux和80x86下分頁機制的不同。
圖:linux分頁模式(四級頁表)
linux的程序處理很大程度上依賴于分頁,每個程序都有自己的頁全局目錄和自己的頁表集。
下列宏簡化了頁表處理。(80x86)
page_shift:
指定offset字段的位數;當用于80x86處理器時,其值為12。
pmd_shift:
指定線性位址的offset字段和table字段的總位數;即頁中間目錄項可以映射的區域大小的對數。
pud_shift:
确定頁上級目錄項所能映射的區域大小的對數。
pgdir_shift:
确定頁全局目錄項所能映射的區域大小的對數。
ptrs_per_pte、ptrs_per_pmd、ptrs_per_pud、ptrs_per_pgd:
用于計算頁表、頁中間目錄、頁上級目錄和頁全局目錄表中表項的個數。
當pae被禁用時,它們産生的值分别為1024、1、1、1024(32位系統,頁上級目錄(pud)、頁中間目錄(pmd)置0,從根本上取消了頁上級目錄和頁中間目錄字段)。
當pae被激活時,産生的值分别為512、512、1、4(32位系統使用三級頁表,linux的頁全局目錄對應于80x86的頁目錄指針表(pdpt),取消了頁上級目錄,頁中間目錄對應頁目錄,頁表對應80x86的頁表)。
====》注意區分linux的分頁機制和80x86的分頁機制的不同。
#頁表項格式轉化
pte_t、pmd_t、pud_t和pgd_t分别描述頁表項、頁中間目錄項、頁上級目錄項和頁全局目錄項的格式。pgprot_t表示與一個單獨表項相關的保護标志。
#讀頁标志的函數
#設定頁标志的函數
#對頁表項操作的宏
#頁配置設定函數
在初始化階段,核心必須建立一個實體位址映射來指定哪些實體位址範圍對核心可用而哪些實體位址範圍對核心不可用。
核心将下列頁框标記為保留:
#在不可用的實體位址範圍内的頁框;
#含有核心代碼和已初始化的資料結構的頁框。
一般來說,linux核心安裝在ram從實體位址0x00100000開始的地方,即從第二個mb開始。
為什麼核心沒有安裝在ram的第一個mb開始的地方?因為pc的體系結構,有幾個獨特的地方必須考慮到。如:
#頁框0由bios使用,存放加電自檢檢查到的系統硬體配置資訊;
#實體位址從0x000a0000到0x000fffff的範圍通常留給bios例程;
#第一個mb内的頁框可能由特定計算機模型保留。
linux2.6的前768個頁框(3mb):
每一個程序都有它自己的頁全局目錄和頁表集,當發生程序切換時,cr3的内容被儲存在前一個執行程序的task_struct中,(task_struct->mm->pgd)。
将下一個程序的pgd位址裝入cr3寄存器。
程序的線性位址空間分為兩部分:
0-3g 使用者态與核心态都可尋址;
3g-4g 隻有核心态才能尋址。
程序的頁全局目錄的第一部分表項映射的線性位址小于3g。
剩餘的表項對于所有程序都是相同的,等于核心頁表中的相應表項。
核心維持着一組自己使用的頁表,駐留在主核心頁全局目錄中。在系統初始化時建立。
#核心建立一個有限的位址空間,将核心裝入ram中和對其初始化的核心資料結構進行存儲;
#核心充分利用剩餘的ram并适當地建立分頁表。
(1)、臨時核心頁表
臨時頁全局目錄是在核心編譯過程中靜态初始化的,而臨時頁表是由startup_32()彙編語言函數初始化的。
臨時頁全局目錄放在swapper_pg_dir變量中。臨時頁表在pg0變量處開始存放,緊接在核心未初始化的資料段後面。
(2)、當ram小于896mb時的最終核心頁表
swapper_pg_dir頁全局目錄有如下代碼初始化:
pagetable_init()函數====>>>
kernel_physical_mapping_init()函數====>>>關鍵在于中間的for循環實作!
(3)、當ram大小在896mb和4096mb之間時的最終核心頁表
在這種情況下,并不把所有ram全部映射到核心位址空間。linux把一個具有896mb的ram視窗映射到核心線性位址空間。如果一個程式需要對現有ram的其餘部分尋址,必須把某些其他的線性位址間接映射到所需的ram(動态重映射)。
(4)、當ram大于4096mb時的最終核心頁表
使用三級分頁模型。
硬體高速緩存的同步,由處理器自動完成。
tlb的同步,由核心完成,因為線性位址到實體位址的映射是否有效,由核心決定。
獨立于系統的使tlb表項無效的方法:
在一個處理器上運作的函數發送處理器間中斷,給其他cpu,強制它們執行适當的函數重新整理tlb。