翻閱《深入理解linux內核》之內存尋址章節,寫此文章,作爲總結。
X86架構,關於地址類型有3個重要概念:
邏輯地址(logical address)
每個邏輯地址由一個段地址和偏移量組成,偏移量指實際地址相對於段首的偏移。即logical addr = segment addr + offset
線性地址(linear address)
也稱虛擬地址,無符號整數,值範圍是0x00000000~0xFFFFFFFF
物理地址(pyhsical address)
物理內存單元的地址,通過電信號能訪問到的地址
後續相關重點涉及線性地址和物理地址。
硬件中的分頁
CPU芯片有一個內存控制單元(MMU),其一重要的功能是將線性地址轉換爲物理地址。
首先介紹涉及到得重要概念:
1. 頁:爲了效率起見,線性地址被分爲以固定長度爲單位的組,稱爲頁。頁連續的線性地址映射到連續的物理地址中;
2. 頁框:分頁單元把所有的RAM分成固定長度的頁框(page frame),也可稱物理頁;頁框的長度等於頁的長度;
3. 頁表:線性地址映射到物理地址的數據結構稱爲頁表(page table);
據書中記載,常規分頁,從80386起,Intel處理器的分頁單元處理4KB的頁,那頁的大小是怎麼計算出來的呢?
X86架構處理器32位線性地址劃分爲3個域:
域名 | Bit Size | space size |
Directory(目錄) | 21~31 | 1024K目錄項 |
Table(頁表) | 12~21 | 1024K頁表項 |
offset | 0~11 | 4K |
每個進程必須獨佔一個分配給他的頁目錄,這樣每個進程可以有相同的地址空間。但不必立刻爲進程的所有頁表分配RAM,當進程實際需要一個頁時才分配RAM。
正在使用的頁目錄的物理地址存在在控制寄存器CR3中, 通過解析線性地址->Directory字段找到頁目錄中的目錄項->找到與目錄項與之對應的頁表->Table字段找到頁表中的表項->找到與表項對應的頁框的物理地址->offset字段找到頁框中某字節的物理地址。
硬件分頁一個重要的環節是根據表示地址空間大小,將線性地址分爲多個域,在域之間進行逐級查找,最後找到對應的物理地址。這點從常規分頁線性地址到物理地址的轉換可以看出。書中還涉及擴展分頁,物理地址擴展分頁機制(PAE),64位系統分頁,不再詳述,原理都是一樣的,只是線性地址每個域的劃分方法不同。
Linux中的分頁
內核2.6.11版本開始,採用四級分級模型:
頁全局目錄(page global directory)
頁上級目錄(page upper directory)
頁中級目錄 (page middle directory)
頁表(page table)
每一部分的大小與具體的計算機體系架構有關。X86和ARM是怎麼劃分的呢?
沒有啓動PAE的32位系統,頁上級目錄和頁中級目錄位置爲0,但頁上級目錄和頁中級目錄在指針序列中的位置被保留; 啓動了PAE的32位系統,取消了頁上級目錄,使用3級目錄結構; 64位系統,根據硬件對位的劃分,決定使用三級結構(取消頁上級目錄)或者四級目錄結構
Linux中頁的權限訪問
頁與頁表特權級別有2個,由user/Supervisor標誌所控制;頁得存取權限位有兩種:讀與寫
進程頁表地址空間
進程的線性地址空間分爲兩部分:
0x00000000~0xBFFFFFFF的線性地址,進程空間和內核空間都可以訪問;
0xC0000000~0xFFFFFFFF的線性地址,只有內核空間可以訪問;
進程運行於用戶態時,它產生的地址空間小於0xc0000000, 當進程運行於內核態時,它產生的地址空間大於0xc0000000。即是0~3G爲用戶空間,3G~4G爲內核空間。