承接前文分段機制,本文深入分析 80386 保護模式下的分頁機制。分頁是實現虛擬記憶體的關鍵,將 4GB 線性位址空間劃分為 4KB 頁框,透過兩級頁表將線性位址轉換為實體位址,並由 TLB (Translation Lookaside Buffer) 加速轉換過程。
CR0 控制暫存器關鍵位元:
PE (Protection Enable, bit 0):1 = 保護模式,0 = 實模式。PG (Paging, bit 31):1 = 啟用分頁,0 = 停用分頁 (線性位址 = 實體位址)。啟用分頁需先載入 CR3 (頁目錄基址),再置 PG=1。CR2 儲存導致頁錯誤的線性位址,供處理程式使用。
32 位元線性位址空間 = 4GB。若採用單級頁表,每頁 4KB,共 1M 頁。每個頁表項 (PTE) 4 字節 → 頁表大小 4MB,且需連續實體記憶體,極不實用。
Linux 採用 兩級頁表:
總頁表項數 = 1K × 1K = 1M,覆蓋 4GB 空間,但只需為實際使用的區域分配頁表,極大節省記憶體。
32 位元線性位址劃分為三段:
31 22 21 12 11 0
+--------------+--------------+--------------+
| 目錄索引(10) | 頁表索引(10) | 頁內偏移(12) |
+--------------+--------------+--------------+
Present (P, bit 0):1 = 頁面在實存,0 = 頁面不在實存 (觸發頁錯誤)。Read/Write (R/W, bit 1):1 = 可讀寫,0 = 唯讀。User/Supervisor (U/S, bit 2):1 = 用戶態可存取,0 = 僅核心態。Accessed (A, bit 5):CPU 存取時自動置 1。Dirty (D, bit 6, 僅 PTE):寫入時自動置 1,供換出判斷。Page Size (PS, bit 7, 僅 PDE):1 = 4MB 大頁 (Pentium+),0 = 4KB 標準頁。TLB 是 CPU 內部的全相聯/組相聯快取,儲存近期使用的「線性頁號 → 實體頁框」映射。命中時直接獲得實體頁框,省去兩級頁表查詢。Context Switch 時需刷新 TLB (載入新 CR3 自動刷新),或使用 invlpg 指令刷新單一條目。
pgd_t、pmd_t、pte_t:核心定義的頁目錄項、頁中間目錄項 (三級/四級架構)、頁表項類型,封裝架構差異。pgd_offset(mm, addr)、pmd_offset()、pte_offset():三級/四級通用查找巨集。mk_pte(page, prot)、pte_mkwrite()、pte_mkclean():PTE 屬性構建與修改。__get_free_pages()、alloc_page():頁框分配器 (Buddy System)。兩級分頁機制以 4KB 頁框為基本單位,透過頁目錄 + 頁表層級間接映射,實現稀疏位址空間的高效管理。TLB 硬體快取消除查表開銷,使虛擬記憶體效能接近實體記憶體。理解位址拆分、PDE/PTE 旗標、頁錯誤處理流程,是掌握 Linux 記憶體管理、除錯頁錯誤、開發核心模組的基石。