cpu如何通過MMU訪問到物理地址

cpu的MMU開啓後,cpu的尋址過程如下:CPU任何時候發出的地址都是虛擬地址,這個虛擬地址發給MMU後,MMU通過頁表在頁表裏面查出這個虛擬地址對應的物理地址是什麼,從而去訪問外面的內存條。MMU裏面的頁表地址寄存器,記錄了頁表本身存放的位置。

現在我們假設每一頁的大小是4KB,而且假設頁表只有一級。這個頁表長成下面這個樣子,頁表的每一行是32bit。

當CPU訪問虛擬地址0的時候,MMU會去查上面頁表的第0行,發現第0行沒有命中,於是無論以何種形式(R讀,W寫,X執行)訪問,MMU都會給CPU發出page fault,CPU會自動跳到fault的代碼去處理fault。

當CPU訪問虛擬地址4KB的時候,MMU會去查上面的頁表的第1行(4KB/4KB),發現第一行命中,如果這個時候

用戶是執行讀或者執行,則MMU去訪問內存條的6MB的這個地址,因爲頁表裏面記錄該頁的權限是RX;

用戶是去寫4KB,由於頁表裏面的第一行記錄的權限是RX,沒有記錄你有的寫權限,MMU會給CPU發出page fault,CPU自動跳轉到fault代碼去處理fault。

當CPU訪問虛擬地址8KB+16的時候,MMU會去查上面頁表的第2行(8KB/4KB=2),發現第2行命中了物理地址8M,這個時候,MMU會去訪問內存條的8MB+16的這個物理地址。當然,權限檢查也是需要的。

當CPU訪問虛擬地址3GB的時候,MMU會去查詢上面頁表的第3GB/4KB行,頁表命中了,查到虛擬地址3GB對應的物理地址是0,於是MMU去訪問內存條上的地址0.但是,這個訪問分成2種情況。

cpu在執行用戶態程序的時候,去訪問3GB,由於頁表裏面記錄的U+K權限只有K,所以U沒有權限的,MMU會給CPU發出page fault,CPU自動跳轉到fault

cpu在執行內核態程序的時候,去訪問3GB,由於頁表裏面記錄的U+K的權限只有K,所以K是有權限的,MMU不會給CPU發出page fault,程序正常執行。

由此可以得知,如果頁表只有1級,每4KB的虛擬地址空間就需要頁表裏面的一行(32bit),那麼CPU要覆蓋到整個4GB的內存,就需要這個頁表的大小是:

4GB/4KB*4=4MB.

注意頁表是無縫全覆蓋,你頁表不覆蓋,CPU訪問虛擬地址的時候,MMU都不知道查哪裏了…

所以,這個頁表的大小是4MB,覆蓋了整個0-4G的虛擬地址空間,任何一個虛擬地址,都可以用這個地址的高20位(由於一頁是4KB,低12位就是頁內偏移了),作爲頁表這個表的行號去讀對應的頁表項。

這個查表的過程,由MMU硬件自動完成。

現在我們假設在linux系統裏面有2個進程,一個是微信,一個chorm,他們的頁表分別如下:

當CPU在執行微信的時候,LINUX會把微信頁表的物理地址255MB,填入MMU的頁表地址寄存器,於是這個時候,微信的頁表生效。根據頁表內容,CPU如果訪問4KB這個虛擬地址的話,MMU訪問內存條的6MB的物理地址;CPU如果訪問8KB這個虛擬地址的話,MMU訪問內存條的8MB物理地址;CPU如果訪問3GB這個虛擬地址的話,MMU訪問內存條的0MB物理地址;

當CPU在執行chorm的時候,linux會把chorm的頁表的物理地址280,填入MMU的頁表地址寄存器,於是這個時候,chorm的頁表生效,微信的頁表淡出。根據頁表內容,CPU如果訪問4KB這個虛擬地址的話,MMU訪問內存條的100MB物理地址;CPU如果訪問8KB這個虛擬地址的話,MMU訪問內存條的200MB的物理地址;CPU如果訪問3GB這個虛擬地址的話,MMU訪問內存條的0MB的物理地址。

上面我們發現一個共同點,微信和chorm去訪問3GB虛擬地址的時候,最終MMU訪問的都是0MB這個物理地址,具體的原因很簡單,微信和chorm,這兩個頁表裏面,3GB/4KB這一行,裏面填的是完全一樣的東東。

多級頁表:真實的存在

上面我們發現,如果採用一級頁表的話,每個進程都需要1個4MB的頁表,這個空間浪費很大,於是我們可以採用2,3級頁表的。舉例如下,假設我們用地址的高10位作爲一級頁表的索引,中間10位作爲2級頁表的索引。CPU訪問虛擬地址16,這個地址如果分解爲10/10/12位的話,就是這個樣子。

那麼MMU會用0這個下標去訪問一級頁表(一級頁表的地址填入MMU的頁表地址寄存器)的第0行,第0行的內容寫的是2MB(此處不再是最終的物理地址,而是二級頁表的物理地址),證明二級頁表的地址在2MB,於是MMU自動去以中間的10位作爲下標,去查詢位置在2MB的二級頁表,在2級頁表裏面,最終查到第0頁(地址範圍0x00000000~0x00000FFF)這個虛擬地址的物理地址是1GB,於是MMU去訪問內存條的1GB+16這個物理地址。

據以上分析,1級頁表佔據的內存是2的10次方,再乘以4,即4KB。而每個二級頁表,也是2的10次方,再乘以4,即4KB。分級機制的主要好處是,二級頁表不是一定存在了,比如一級頁表的第2行不命中,也即如下地址都無效的話:

那麼這一行對應的二級頁表,就整個都不需要了,於是就省掉了這段區間4KB二級頁表的內存佔用。頁表當然還有是三級甚至更多。

至於有多級頁表的時候,其實MMU也只需要知道一級頁表的基地址即可。每次切換進程的時候,把一級頁表的地址重新填入MMU,把新的進程的頁表激活即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章