由于很多童鞋大學(xué)的時(shí)候?qū)W《微機(jī)原理》都是打醬油,當(dāng)老師是蒼蠅在講臺(tái)上發(fā)噪音,導(dǎo)致MMU這些基本知識(shí)都沒有搞清楚,所以對(duì)計(jì)算機(jī)的認(rèn)識(shí)一塌糊涂,Linux也無法學(xué)通。然后我經(jīng)常被問到各種奇葩到讓人吐血的內(nèi)存管理問題,這些問題顯示出這些童鞋對(duì)最基本的MMU和頁表工作機(jī)制不清楚。我覺得我不得不寫點(diǎn)什么東西,讓這些打醬油的童鞋,把基本的馬步扎穩(wěn),當(dāng)然這不是為了別人,也不是為了無私奉獻(xiàn),純粹是為了避免無數(shù)次被問到吐血,遲早有一天吐血而亡。為了能夠活地久一點(diǎn),特作此文。
假設(shè)頁表只有一級(jí)
對(duì)于一個(gè)有MMU的CPU而言,MMU開啟后,CPU是這樣尋址的:CPU任何時(shí)候,一切時(shí)候,發(fā)出的地址都是虛擬地址,這個(gè)虛擬地址發(fā)給MMU后,MMU通過頁表來在頁表里面查出來這個(gè)虛擬地址對(duì)應(yīng)的物理地址是什么,從而去訪問外面的內(nèi)存條。MMU里面的頁表地址寄存器,記錄了頁表本身的存放位置。
現(xiàn)在我們假設(shè)每一頁的大小是4KB,而且假設(shè)頁表只有一級(jí),這個(gè)頁表長(zhǎng)成下面這個(gè)樣子,頁表的每一行是32個(gè)bit。
當(dāng)CPU訪問虛擬地址0的時(shí)候,MMU會(huì)去查上面頁表的第0行,發(fā)現(xiàn)第0行沒有命中,于是無論以何種形式(R讀,W寫,X執(zhí)行)訪問,MMU都會(huì)給CPU發(fā)出page fault,CPU自動(dòng)跳到fault的代碼去處理fault。
當(dāng)CPU訪問虛擬地址4KB的時(shí)候,MMU會(huì)去查上面頁表的第1行(4KB/4KB=1),發(fā)現(xiàn)第1行命中,如果這個(gè)時(shí)候
用戶是執(zhí)行讀或者執(zhí)行,則MMU去訪問內(nèi)存條的6MB這個(gè)地址,因?yàn)轫摫砝锩嬗涗浽擁摰臋?quán)限是RX;
用戶是去寫4KB,由于頁表里面第1行記錄的權(quán)限是RX,沒有記錄你有寫的權(quán)限,MMU會(huì)給CPU發(fā)出page fault,CPU自動(dòng)跳到fault的代碼去處理fault。
當(dāng)CPU訪問虛擬地址8KB+16的時(shí)候,MMU會(huì)去查上面頁表的第2行(8KB/4KB=2),發(fā)現(xiàn)第2行命中了物理地址8M,這個(gè)時(shí)候,MMU會(huì)訪問內(nèi)存條的8MB+16這個(gè)物理地址。當(dāng)然,權(quán)限檢查也是需要的。
…
當(dāng)CPU訪問虛擬地址3GB的時(shí)候,MMU會(huì)去查上面頁表的第3GB/4KB行,表中記錄命中了,查到虛擬地址3GB對(duì)應(yīng)的物理地址是0,于是MMU去訪問內(nèi)存條上的地址0。但是,這個(gè)訪問分成2種情況:
CPU在執(zhí)行用戶態(tài)程序的時(shí)候,去訪問3GB,由于頁表里面記錄的U+K權(quán)限只有K,所以U是沒權(quán)限的,MMU會(huì)給CPU發(fā)出page fault,CPU自動(dòng)跳到fault的代碼去處理fault;
CPU在執(zhí)行內(nèi)核態(tài)程序的時(shí)候,去訪問3GB,由于頁表里面記錄的U+K權(quán)限只有K,所以K是有權(quán)限的,MMU不會(huì)給CPU發(fā)出page fault,程序正常執(zhí)行。
由此可以得知,如果頁表只有1級(jí),每4KB的虛擬地址空間就需要頁表里面的一行(32bit),那么CPU要覆蓋到整個(gè)4GB的內(nèi)存,就需要這個(gè)頁表的大小是:
4GB/4KB *4 = 4MB。
注意頁表是無縫全覆蓋?。?!你頁表不覆蓋全,CPU訪問虛擬地址的時(shí)候,MMU都不知道查哪里了....
所以,這個(gè)頁表的大小是4MB,覆蓋了整個(gè)0-4GB的虛擬地址空間,任何一個(gè)虛擬地址,都可以用地址的高20位(由于一頁是4KB,低12位就是葉內(nèi)偏移了),作為頁表這個(gè)表的行號(hào)去讀對(duì)應(yīng)的頁表項(xiàng)。
這個(gè)查水表的過程,由MMU硬件自動(dòng)完成。
現(xiàn)在我們假設(shè)在Linux里面有2個(gè)進(jìn)程,一個(gè)是QQ,一個(gè)是Firefox,他們的頁表分別如下:
當(dāng)CPU在執(zhí)行QQ的時(shí)候,Linux會(huì)把QQ的頁表的物理地址255MB,填入MMU的頁表地址寄存器,于是這個(gè)時(shí)候,QQ的頁表生效。根據(jù)頁表內(nèi)容,CPU如果訪問4KB這個(gè)虛擬地址的話,MMU訪問內(nèi)存條的6MB物理地址;CPU如果訪問8KB這個(gè)虛擬地址的話,MMU訪問內(nèi)存條的8MB物理地址;CPU如果訪問3GB這個(gè)虛擬地址的話,MMU訪問內(nèi)存條的0MB物理地址;
當(dāng)CPU在執(zhí)行Firefox的時(shí)候,Linux會(huì)把Firefox的頁表的物理地址280MB,填入MMU的頁表地址寄存器,于是這個(gè)時(shí)候,F(xiàn)irefox的頁表生效,QQ的頁表淡出江湖。根據(jù)頁表內(nèi)容,CPU如果訪問4KB這個(gè)虛擬地址的話,MMU訪問內(nèi)存條的100MB物理地址;CPU如果訪問8KB這個(gè)虛擬地址的話,MMU訪問內(nèi)存條的200MB物理地址;CPU如果訪問3GB這個(gè)虛擬地址的話,MMU訪問內(nèi)存條的0MB物理地址。
上面我們發(fā)現(xiàn)一個(gè)共同點(diǎn),QQ和Firefox去訪問3GB虛擬地址的時(shí)候,最終MMU訪問的都是0MB這個(gè)物理地址,具體原因非常簡(jiǎn)單,QQ和Firefox,這2張頁表里面,3GB/4KB這一行,里面填的是完全一樣的東東。
多級(jí)頁表:真實(shí)的存在在
上面我們發(fā)現(xiàn),如果采用一級(jí)頁表的話,每個(gè)進(jìn)程都需要1個(gè)4MB的頁表,這個(gè)空間浪費(fèi)還是很大,于是我們可以采用二級(jí)或者三級(jí)頁表。舉例如下,假設(shè)我們用地址的高10位作為一級(jí)頁表的索引,中間10位作為2級(jí)頁表的索引。CPU訪問虛擬地址16,這個(gè)地址如果分解為10/10/12位的話,就是這個(gè)樣子:
那么MMU會(huì)用0這個(gè)下標(biāo)去訪問一級(jí)頁表(一級(jí)頁表的地址填入MMU的頁表地址寄存器)的第0行,第0行的內(nèi)容寫的是2MB(此處不再是最終的物理地址,而是二級(jí)頁表的物理地址),證明二級(jí)頁表的地址在2MB,于是MMU自動(dòng)去以中間的10位作為下標(biāo),去查詢位置在2MB的二級(jí)頁表,在2級(jí)頁表里面,最終查到第0頁(地址范圍0x00000000~0x00000FFF)這個(gè)虛擬地址的物理地址是1GB,于是MMU去訪問內(nèi)存條的1GB+16這個(gè)物理地址。
據(jù)以上分析,1級(jí)頁表占據(jù)的內(nèi)存是2的10次方,再乘以4,即4KB。而每個(gè)二級(jí)頁表,也是2的10次方,再乘以4,即4KB。分級(jí)機(jī)制的主要好處是,二級(jí)頁表不是一定存在了,比如一級(jí)頁表的第2行不命中,也即如下地址都無效的話:
那么這一行對(duì)應(yīng)的二級(jí)頁表,就整個(gè)都不需要了,于是就省掉了這段區(qū)間4KB二級(jí)頁表的內(nèi)存占用。頁表當(dāng)然還有是三級(jí)甚至更多。
至于有多級(jí)頁表的時(shí)候,其實(shí)MMU也只需要知道一級(jí)頁表的基地址即可。每次切換進(jìn)程的時(shí)候,把一級(jí)頁表的地址重新填入MMU,把新的進(jìn)程的頁表激活即可。
-
cpu
+關(guān)注
關(guān)注
68文章
11082瀏覽量
217168 -
Linux
+關(guān)注
關(guān)注
87文章
11511瀏覽量
213894 -
MMU
+關(guān)注
關(guān)注
0文章
92瀏覽量
18759
原文標(biāo)題:宋寶華: CPU是如何訪問到內(nèi)存的?--MMU最基本原理
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
關(guān)于MMU的一級(jí)頁表為什么必須是16K對(duì)齊
關(guān)于頁表和MMU的問題
ARM MMU 理解(基于ARM 920T)
MMU的產(chǎn)生及MMU工作過程詳解
裸機(jī)加強(qiáng)版MMU章節(jié)頁表創(chuàng)建,地址映射相同
如何配置MMU page table walk的訪問屬性
MMU的工作原理梳理

MMU如何知道頁表在內(nèi)存中的具體地址

嵌入式Linux運(yùn)行一定需要MMU嗎?為什么需要MMU?
MMU原理:CPU是如何訪問到內(nèi)存的?

MMU包含兩個(gè)模塊是什么

MMU中的頁命中、缺頁介紹

MMU多級(jí)頁表映射過程

評(píng)論