虛擬地址如何對映到實體地址
虛擬地址***被不同的程序對映到的實體地址是不同的,那麼大家知道嗎?下面跟著小編來一起了解下虛擬地址對映到實體地址吧。
虛擬地址對映到實體地址方法
這裡只談分頁管理的機制,也是目前最重要的記憶體管理機制。
最初的設計想法:
結構圖如下:
頁的尺寸是4KB,虛擬地址的前20位用於指定一個物理頁,後12位用於訪問頁內偏移。
頁表項的結構:
各個位的含義:
P--位0是存在***Present***標誌,用於指明表項對地址轉換是否有效。P=1表示有效;P=0表示無效。在頁轉換過程中,如果說涉及的頁目錄或頁表的表項無效,則會導致一個異常。如果P=0,那麼除表示表項無效外,其餘位可供程式自由使用,如圖4-18b所示。例如,作業系統可以使用這些位來儲存已儲存在磁碟上的頁面的序號。
R/W--位1是讀/寫***Read/Write***標誌。如果等於1,表示頁面可以被讀、寫或執行。如果為0,表示頁面只讀或可執行。當處理器執行在超級使用者特權級***級別0、1或2***時,則R/W位不起作用。頁目錄項中的R/W位對其所對映的所有頁面起作用。
U/S--位2是使用者/超級使用者***User/Supervisor***標誌。如果為1,那麼執行在任何特權級上的程式都可以訪問該頁面。如果為0,那麼頁面只能被執行在超級使用者特權級***0、1或2***上的程式訪問。頁目錄項中的U/S位對其所對映的所有頁面起作用。
A--位5是已訪問***Accessed***標誌。當處理器訪問頁表項對映的頁面時,頁表表項的這個標誌就會被置為1。當處理器訪問頁目錄表項對映的任何頁面時,頁目錄表項的這個標誌就會被置為1。處理器只負責設定該標誌,作業系統可通過定期地復位該標誌來統計頁面的使用情況。
D--位6是頁面已被修改***Dirty***標誌。當處理器對一個頁面執行寫操作時,就會設定對應頁表表項的D標誌。處理器並不會修改頁目錄項中的D標誌。
AVL--該欄位保留專供程式使用。處理器不會修改這幾位,以後的升級處理器也不會。
由於頁表佔用記憶體空間太大***1M個元素*4B大小=4MB,也可以這麼看:每個程序的虛擬地址空間=4G,頁面大小=4K,所以共有1M個頁,需要1M個頁表項,又因為每個頁表項=4B,所以頁表大小=4M***,為了減少記憶體佔用量,因此設計了層次化的分頁結構:頁目錄表+頁表。
層次化的設計想法:
因為4GB的虛擬記憶體共有1M=220=1048576個4K大小的頁面。
我們將這些頁面分成210=1024份,即從頁表1到頁表1024,由頁目錄表管理;
每一份***每一頁表***有210=1024個頁,由每一個頁表管理,頁在頁表中是隨機的,哪個頁位於哪個頁表中是沒有規律的;
結構圖如下:
每個任務都有這樣的層次化的分頁結構,即每個任務都有自己的頁目錄表和頁表。
從硬體角度來分析:
在處理器中有個控制暫存器CR3,存放著當前任務頁目錄的實體地址,故又叫做頁目錄基址暫存器***Page Directory Base Register,PDBR***,每個任務都存放了自己的頁目錄實體地址,當任務切換時,處理器切換到新任務開始執行,更新CR3暫存器的內容,以指向新任務的頁目錄位置;
相應的,頁目錄又指向了一個個的頁表,每個頁表又根據任務的頁表項指向了相應的頁。其中注意的是,頁目錄和頁表也是普通的頁,混跡於全部的物理頁中,它們和普通頁的不同之處僅僅在於功能不一樣,當任務撤銷之後, 它們和任務所佔用的普通頁一樣會被回收, 並分配給其他任務***如下圖所示***。
下面內容轉自《分頁機制》,寫的很清楚。
地址變換的具體過程
對於Intel處理器來說, 有關分頁, 最簡單和最基本的機制就是這些; CR3暫存器給出了頁目錄的實體地址; 頁目錄給出了所有頁表的實體地址, 而每個頁表給出了它所包含的頁的實體地址. 好了, 該清楚的都清楚了, 唯一還不明白的, 應該是如何用這種層次性的分頁結構把線性地址轉換成實體地址? 這裡舉個例子, 某任務載入後, 在4GB虛擬地址空間建立了一個段, 起始地址為0x00800000, 段界限為0x5000, 位元組粒度. 當前任務執行時, 段暫存器DS指向該段. 又假設執行了下面一條指令
mov edx, [0x1050]
此時, 段部件會輸出線性地址0x00801050. 在沒有開啟分頁機制時, 這就是要訪問的實體地址. 但現在開啟了分頁機制, 所以這是一個下虛擬地址, 要經過頁部件轉換, 才能得到實體地址.
如下圖所示, 處理器的頁部件專門負責線性地址到實體地址的轉換工作. 它首先將段部件送來的32位線性地址分為3段, 分別是高10位, 中間10位, 低12位. 高10位是頁目錄的索引, 中間10位是頁表的索引, 低12位則作為頁內偏移量來用.
當前任務頁目錄的實體地址在處理器的CR3暫存器中, 假設它的內容為0x00005000. 段管理部件輸出的線性地址是0x00801050, 其二進位制的形式如圖中給出. 高10位是十六進位制的0x002, 它是頁目錄表內的索引,處理器將它乘以4***因為每個目錄項4位元組***, 作為偏移量訪問頁目錄. 最終處理器從實體地址00005008處取得頁表的實體地址0x08001000.
線性地址的中間10位為0x001, 處理器用它作為頁表索引取得頁的實體地址. 將該值乘以4, 作為偏移量訪問頁表. 最終, 處理器又從實體地址08001004處取得頁的實體地址, 這就是我們一直努力尋找的那個頁.
頁的實體地址是0x0000c000, 而線性地址的低12位是資料所在的頁內偏移量. 故處理器將它們相加, 得到實體地址0x0000C050, 這就是線性地址0x00801050所對應的實體地址, 要訪問的資料就在這裡.
注意, 這種變換不是無緣無故的, 而是事先安排好的. 當任務載入時, 作業系統先建立虛擬的段, 並根據段地址的高20位決定它要用到哪些頁目錄項和頁表項. 然後, 尋找空閒的頁, 將原本應該寫入段中的資料寫到一個或者多個頁中, 並將頁的實體地址填寫到相對應的頁表項中. 只有這樣做了, 當程式執行的時候, 才能以相反的順序進行地址變換, 並找到正確的資料.
頁目錄項, 頁表項, CR3和開啟分頁
頁目錄項和頁表項
頁目錄和頁表中分別存放為頁目錄項和頁表項, 它們的格式如下:
可以看出, 在頁目錄和頁表中, 只儲存了頁表或者頁實體地址的高20位. 原因很簡單, 頁表或者頁的實體地址, 都要求必須是4KB對齊的, 以便於放在一個頁內, 故其低12位全是0. 在這種情況下, 可以只關心其高20位, 低12位安排其他用途.
P 是存在位, 為1時, 表示頁表或者頁位於記憶體中. 否則, 表示頁表或者頁不在記憶體中, 必須先予以建立, 或者從磁碟調入記憶體後方可使用.
RW 是讀/寫位. 為0時表示這樣的頁只能讀取, 為1時可讀可寫
US 是使用者/管理位. 為1時, 允許所有特權級別的程式訪問; 為0時, 只允許特權級別為0, 1和2的程式訪問.
PWT***Page-level Write-Through*** 是頁級通寫位, 和快取記憶體有關. "通寫"是處理器快取記憶體的一種工作方式, 這一位用來間接決定是否採用此種方式來改善頁面的訪問效率.
PCD***Page-level Cache Disable***是頁級快取記憶體禁止位, 用來間接決定該表項所指向的那個頁是否使用快取記憶體策略.
A 是訪問位. 該位由處理器韌體設定, 用來指示此表項所指向的頁是否被訪問過.
D***Dirty*** 是髒位. 該位由處理器韌體設定, 用來指示此表項所指向的頁是否寫過資料