Linux 內核啟動早期運行在實模式,隨後切換到保護模式並啟用分頁機制。本文基於 arch/i386/kernel/head.S 中的 startup_32 入口點,詳細解析頁表初始化、頁目錄構建、CR0/CR3 寄存器設置及從物理地址跳轉到虛擬地址的關鍵過程。
內核在 0x102000(pg0)和 0x103000(pg1)構建兩個頁表,映射物理內存前 8MB(2048 頁):
movl $pg0-__PAGE_OFFSET, %edi // pg0 物理地址
movl $0x007, %eax // PRESENT | RW | USER
2: stosl
addl $0x1000, %eax // 下一個物理頁
cmpl $empty_zero_page-__PAGE_OFFSET, %edi
jne 2b
0x007(用戶態、可寫、存在)empty_zero_page(零頁),存放啟動參數.org 0x1000
ENTRY(swapper_pg_dir)
.long 0x00102007 // 第 0 項 → pg0
.long 0x00103007 // 第 1 項 → pg1
.fill 766, 4, 0 // 第 2-767 項:用戶空間 3GB,暫不映射
.long 0x00102007 // 第 768 項 → pg0(內核空間映射)
.long 0x00103007 // 第 769 項 → pg1
.fill 254, 4, 0 // 第 770-1023 項:內核空間剩餘 1GB
映射佈局:
movl $swapper_pg_dir-__PAGE_OFFSET, %eax
movl %eax, %cr3 // 載入頁目錄物理地址
movl %cr0, %eax
orl $0x80000000, %eax // 設置 PG 位(第 31 位)
movl %eax, %cr0 // 啟用分頁
jmp 1f // 刷新預取隊列
1: movl $1f, %eax
jmp *%eax // 絕對跳轉到虛擬地址
jmp 1f 是短跳轉,僅刷新流水線,EIP 仍是物理地址movl $1f, %eax; jmp *%eax 將虛擬地址載入 EIP,完成進入內核虛擬空間Linux 通過精心設計的臨時頁表(swapper_pg_dir),實現了從實模式物理地址執行到保護模式虛擬地址執行的平滑過渡。這 8MB 的身份映射是啟動早期內核安全運行的基石,後續 start_kernel 會根據實際內存大小重建完整頁表。