內核知識第八講,PDE,PTE,頁目錄表,頁表的內存管理
一丶查看GDT表.
我們通過WinDbg + 虛擬機可以進行雙機調試.調試一下看下GDT表
我們知道,GDT表中.存儲的是存儲段信息. 保存了一系列的段和內存的屬性.
但是微軟並沒有使用.
我們可以通過ring3的段寄存器. 當作GDT表的下標.進行查表. 查詢GDT表.
例如我們用OD隨便打開一個ring3的exe,然后看下段和虛擬地址.:
虛擬地址: 0040256f 段選擇子: cs:1B
那么此時段選擇字當下表.虛擬地址當作偏移.去查詢GDT表
下圖為選擇子結構
段選擇子結構:
首先先拆分選擇子.
1B = 0000000000011 011
查詢出來下表為3,那么去GDT表的第三項進行查找.
然后我們從中取出段首地址 加上我們的偏移
00000000 + 40256F = 0040256F(線性地址)
那么通過查詢GDT表.那么可以找到線性地址. 而我們GDT表,微軟沒有使用它來進行進程隔離.
PS: 微軟因為不使用GDT表進行進程隔離,所以段選擇子都是一樣的.基地址都是0,我們的虛擬地址就是線性地址.
如果沒有開分頁保護.那么就是物理地址了.但是注意FS寄存器. FS寄存器很特殊.並不能說GDT表沒用.
二丶控制寄存器CR0
我們上面說過.如果沒有開啟分頁保護.那么虛擬地址就是線性地址,線性地址就是物理地址
而微軟是通過分頁進行進程內存的隔離的.
首先說一下什么分頁的歷史,和CR0控制寄存器.
在保護模式下, 寄存器CR0的高位1表示開啟分頁.0表示不開啟.
而這個在操作系統初始化的是否就已經完成了.
如果我們不開啟,那么訪問虛擬內存,就等價於訪問物理內存了.
但是我們的三環是不可以操作的.這個屬於特權指令.如果用匯編進行操作.例如:
__asm mov cr0,8000000
程序會崩潰,提示你權限不夠,並且報告錯誤碼為 C096
但是我們0環可以進行操作的.
看一下CR0的結構:
但是我們0環可以進行操作的.
此圖是從inter手冊上截圖下來的.有興趣的可以查詢CR0查看.
剛才我們說的高位為1的是否就去掉分頁保護,此時訪問虛擬內存 等價於訪問物理內存,其實我們修改的是PG位
關於位怎么說的,inter手冊也說.這里我總結一下重要的,如果不相信我可以查看inter手冊.
PG: PG位表示是否分頁管理機制是否有效. PG = 1,有效, PG = 0 無效.
WP: Wp位 寫保護位, WP為0禁用寫保護,為1則啟動
PS: 通過修改WP位可以進行過保護. 詳情請看 https://www.cnblogs.com/hongfei/archive/2013/06/18/3142162.html 轉載
三丶分頁管理機制
講解分頁管理機制之前,我們要明白以下幾個關鍵詞的意思.
頁碼:
在80386下,一個頁的固定大小是4K個字節,也就是4096,一個頁的辯解地址,不許死4K的倍數.
所以4G大小的內存.就可以划分為1M個節. 而我們的頁的開始一般具有一個特點.
比如我們的虛擬地址:
004010123,而頁的首地址是00401000
后12位都是0.
所以我們把頁的高20位稱為頁碼.
進程內存的保護.
進程內存的保護就通過頁的方式進行保護的.
當我們的線性地址轉化為物理地址的是否,會進行查表. 進而查詢到物理地址是那個.
微軟采用的是這種方式.
線性地址轉物理地址需要注意的頁問題.
這個問題則是頁的映射.
我們知道,頁碼是高20位,那么低12為就是偏移了.
當32位的線性地址轉為32為的物理地址的是否,只需要記錄頁碼就可以了.低12位都是一樣的.所以不用記錄.
比如線性地址:
004010123 映射到物理地址 002010123
那么我只需要記錄前20位即可.
004010 -> 002010 ,然后物理地址加上我們的后12位即可. 002010+123 = 002010123
四丶線性地址到物理地址的轉換.
我們說過,操作系統為了隔離內存.采用了分頁管理.而我們線性地址轉化到物理地址的時候.
則需要查表.
那么我們覺着這個表應該怎么做?
物理地址 |
Xxxx |
內存保護屬性 |
類似於這樣,我們只需要讓虛擬地址當標進行查表即可.
我們每一個進程都提供這樣的一張表.但是在那個時代.資源是匱乏的.我們這樣做.開不了幾個進程內存就會耗光了.
所以微軟提供了自己的表.而硬件上也提供了支持.
我們看下微軟的表.
首先我們的CR3寄存器保存了表的首地址.
這里有一個頁目錄表,還有頁表的關鍵詞.
頁目錄表: 也稱為PDE,而頁表稱之為PTE.
CPU會通過虛擬地址,當作下表.去頁目錄表中查詢.然后查到的結果再去頁表中查詢.這樣就查到對應的物理地址了.
PDE表的大小:
頁目錄表,存儲在一個4K字節的物理頁中,其中每一項是4個字節.保存了頁表的地址.
而最大是1M個頁.
PTE表的大小.
PTE的大小也和PDE一樣的.
微軟為什么這樣設計.有人會問.這樣設計不就資源用的更多了嗎.其實不是的. 雖然我們設計怎么大.
但是通過兩個表查詢.可以映射4G內存.而上面的設計方法不行.
首先前邊20位保存了頁表或者物理地址的基地址.
比如我們的頁目錄表. 查到了第5項.那么從中取出千20位來,加上000就等於頁表了.
然后從頁表中查詢千20位.+虛擬地址的偏移就等價於實際的物理地址了.
AVL 位: 可利用位.
D 位: 表示這個分頁是否寫過.
A 位: 表示這個分頁是否讀過
U/S位: 表示這個分頁是否用戶可以訪問還是ring0可以訪問.
R/W位: 內存保護位. 可讀可寫可執行. 還是可讀可執行.
P 位: 內存是否有效.
R/W位: 注意我這里說的有兩種方式. 可讀可執行,和可讀可寫可執行. 有沒有發現,我們的Ring3程序.不過是那個內存區域也好.都是可以讀的.
而我們Ring3下的修改內存分頁保護屬性,其實就是將這個頁表的這個RW位進行置位.
而我們的虛擬地址當作下表進行查表. 我們的虛擬地址不是分為了20位了嗎. 前10位當作 頁目錄表的下表. 后10位當作頁表的下表
設有物理地址為:
00401 000
那么下表則為:
00401 = 0000000001 0000000001
通過虛擬地址得知,頁目錄表是第一項,而頁表也是第一項.
設頁目錄表第一項為
003f0111, 此時頁表為 取前20位,加上3個0. 003f0 + 000 = 003f0000
設頁表為
00201456, 此時取出前20位加上虛擬地址的后邊20位偏移 物理地址= 00201 + 000 = 00201000,那么物理地址就是201000
圖示:
設虛擬地址為00402567H, 取出前20位. 分為高10位,和低10位做 PDE,和PTE的索引.
然后進行查表.
最后的通過PTE查詢的高20位加上原虛擬地址的低12位, 然后就找到了物理地址.