由于很多童鞋大學的時候學《微機原理》都是打醬油,當老師是蒼蠅在講臺上發噪音,導致MMU這些基本知識都沒有搞清楚,所以對計算機的認識一塌糊涂,Linux也無法學通。然后我經常被問到各種奇葩到讓人吐血的內存管理問題,這些問題顯示出這些童鞋對最基本的MMU和頁表工作機制不清楚。我覺得我不得不寫點什么東西,讓這些打醬油的童鞋,把基本的馬步扎穩,當然這不是為了別人,也不是為了無私奉獻,純粹是為了避免無數次被問到吐血,遲早有一天吐血而亡。為了能夠活地久一點,特作此文。
假設頁表只有一級
對于一個有MMU的CPU而言,MMU開啟后,CPU是這樣尋址的:CPU任何時候,一切時候,發出的地址都是虛擬地址,這個虛擬地址發給MMU后,MMU通過頁表來在頁表里面查出來這個虛擬地址對應的物理地址是什么,從而去訪問外面的內存條。MMU里面的頁表地址寄存器,記錄了頁表本身的存放位置。
現在我們假設每一頁的大小是4KB,而且假設頁表只有一級,這個頁表長成下面這個樣子,頁表的每一行是32個bit。
當CPU訪問虛擬地址0的時候,MMU會去查上面頁表的第0行,發現第0行沒有命中,于是無論以何種形式(R讀,W寫,X執行)訪問,MMU都會給CPU發出page fault,CPU自動跳到fault的代碼去處理fault。
當CPU訪問虛擬地址4KB的時候,MMU會去查上面頁表的第1行(4KB/4KB=1),發現第1行命中,如果這個時候
用戶是執行讀或者執行,則MMU去訪問內存條的6MB這個地址,因為頁表里面記錄該頁的權限是RX;
用戶是去寫4KB,由于頁表里面第1行記錄的權限是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的代碼去處理fault;
CPU在執行內核態程序的時候,去訪問3GB,由于頁表里面記錄的U+K權限只有K,所以K是有權限的,MMU不會給CPU發出page fault,程序正常執行。
由此可以得知,如果頁表只有1級,每4KB的虛擬地址空間就需要頁表里面的一行(32bit),那么CPU要覆蓋到整個4GB的內存,就需要這個頁表的大小是:
4GB/4KB *4 = 4MB。
注意頁表是無縫全覆蓋!!!你頁表不覆蓋全,CPU訪問虛擬地址的時候,MMU都不知道查哪里了....
所以,這個頁表的大小是4MB,覆蓋了整個0-4GB的虛擬地址空間,任何一個虛擬地址,都可以用地址的高20位(由于一頁是4KB,低12位就是葉內偏移了),作為頁表這個表的行號去讀對應的頁表項。
這個查水表的過程,由MMU硬件自動完成。
現在我們假設在Linux里面有2個進程,一個是QQ,一個是Firefox,他們的頁表分別如下:
當CPU在執行QQ的時候,Linux會把QQ的頁表的物理地址255MB,填入MMU的頁表地址寄存器,于是這個時候,QQ的頁表生效。根據頁表內容,CPU如果訪問4KB這個虛擬地址的話,MMU訪問內存條的6MB物理地址;CPU如果訪問8KB這個虛擬地址的話,MMU訪問內存條的8MB物理地址;CPU如果訪問3GB這個虛擬地址的話,MMU訪問內存條的0MB物理地址;
當CPU在執行Firefox的時候,Linux會把Firefox的頁表的物理地址280MB,填入MMU的頁表地址寄存器,于是這個時候,Firefox的頁表生效,QQ的頁表淡出江湖。根據頁表內容,CPU如果訪問4KB這個虛擬地址的話,MMU訪問內存條的100MB物理地址;CPU如果訪問8KB這個虛擬地址的話,MMU訪問內存條的200MB物理地址;CPU如果訪問3GB這個虛擬地址的話,MMU訪問內存條的0MB物理地址。
上面我們發現一個共同點,QQ和Firefox去訪問3GB虛擬地址的時候,最終MMU訪問的都是0MB這個物理地址,具體原因非常簡單,QQ和Firefox,這2張頁表里面,3GB/4KB這一行,里面填的是完全一樣的東東。
多級頁表:真實的存在在
上面我們發現,如果采用一級頁表的話,每個進程都需要1個4MB的頁表,這個空間浪費還是很大,于是我們可以采用二級或者三級頁表。舉例如下,假設我們用地址的高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,把新的進程的頁表激活即可。
-
cpu
+關注
關注
68文章
11001瀏覽量
214977 -
Linux
+關注
關注
87文章
11411瀏覽量
212246 -
MMU
+關注
關注
0文章
92瀏覽量
18564
原文標題:宋寶華: CPU是如何訪問到內存的?--MMU最基本原理
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
關于頁表和MMU的問題
ARM MMU 理解(基于ARM 920T)
MMU的產生及MMU工作過程詳解
裸機加強版MMU章節頁表創建,地址映射相同
如何配置MMU page table walk的訪問屬性
嵌入式Linux運行一定需要MMU嗎?為什么需要MMU?
MMU原理:CPU是如何訪問到內存的?

MMU包含兩個模塊是什么

MMU中的頁命中、缺頁介紹

MMU多級頁表映射過程

評論