MMU(Memory Management Unit)主要用來管理虛擬存儲器、物理存儲器的控制線路,同時也負責虛擬地址映射爲物理地址,以及提供硬件機制的內存訪問受權、多任務多進程操做系統。(來自百度百科,對其幾個點不熟悉,所以能夠只考慮加粗部分)linux
注意:學習一個知識點,很重要的一步是瞭解其爲何而存在?它的存在是爲了解決什麼問題?而後,在學習的過程當中帶着這些問題去理解、去思考。程序員
在許多年之前,仍是使用DOS或一些古老的操做系統時,內存很小,同時,應用程序也很小,將程序存儲在內存中基本可以知足須要。隨着科技的發展,圖形界面及一些其餘更復雜的應用出現,內存已經沒法存儲這些應用程序了,一般的解決辦法是將程序分割成不少個覆蓋塊,覆蓋塊0最早運行,運行結束以後,就調用另外一個覆蓋塊,雖然這些操做由OS來完成,可是,須要程序員對程序進行分割,這很是不高效;所以,人們想出了一個虛擬存儲器(virtual memory)的方法。虛擬存儲器的基本思想是:程序、數據、堆棧的總大小能夠超過內存空間的大小,操做系統將當前運行的部分保存在內存中,未使用的部分保存在磁盤中。好比一個16MB的程序和一個內存只有4MB的機器,操做系統經過選擇能夠決定哪部分4MB的程序內容保存在內存中,並在須要時,在內存與磁盤中交換程序代碼,這樣16MB的代碼就能夠運行在4MB的機器中了。注意:這裏麪包含了虛擬地址和物理地址的概念算法
地址範圍、虛擬地址映射成物理地址以及分頁機制緩存
若是處理器沒有MMU,或者有MMU但沒有啓用,CPU執行單元發出的內存地址將直接傳到芯片引腳上,被內存芯片(如下稱爲物理內存,以便與虛擬內存區分)接收,這稱爲物理地址(Physical Address,如下簡稱PA),以下圖3-1-1所示;
安全
大多數使用MMU的機器都採用分頁機制。虛擬地址空間以頁爲單位進行劃分,而相應的物理地址空間也被劃分,其使用的單位稱爲頁幀,頁幀和頁必須保持相同,由於內存與外部存儲器之間的傳輸是以頁爲單位進行傳輸的。例如,MMU能夠經過一個映射項將VA的一頁0xb70010000xb7001fff映射到PA的一頁0x20000x2fff,若是CPU執行單元要訪問虛擬地址0xb7001008,則實際訪問到的物理地址是0x2008。bash
虛擬內存的哪一個頁面映射到物理內存的哪一個頁幀是經過頁表(Page Table)來描述的,頁表保存在物理內存中,MMU會查找頁表來肯定一個VA應該映射到什麼PA。ide
操做系統和MMU是這樣配合的:函數
操做系統在初始化或分配、釋放內存時會執行一些指令在物理內存中填寫頁表,而後用指令設置MMU,告訴MMU頁表在物理內存中的什麼位置。post
設置好以後,CPU每次執行訪問內存的指令都會自動引起MMU作查表和地址轉換操做,地址轉換操做由硬件自動完成,不須要用指令控制MMU去作。性能
重要:咱們在程序中使用的變量和函數都有各自的地址,在程序被編譯後,這些地址就成了指令中的地址,指令中的地址就成了CPU執行單元發出的內存地址,因此在啓用MMU的狀況下, 程序中使用的地址均是虛擬內存地址,都會引起MMU進行查表和地址轉換操做。(注意理解這句話)
處理器通常有用戶模式(User Mode)和特權模式(privileged Mode)之分。操做系統能夠在頁表中設置每一個頁表訪問權限,有些頁表不能夠訪問,有些頁表只能在特權模式下訪問,有些頁表在用戶模式和特權模式下均可以訪問,同時,訪問權限又分爲可讀、可寫和可執行三種。這樣設定以後,當CPU要訪問一個VA(Virtual Address)時,MMU會檢查CPU當前處於用戶模式仍是特權模式,訪問內存的目的是讀數據、寫數據仍是取指令執行,若是與操做系統設定的權限相符,則容許訪問,把VA轉換成PA,不然不容許執行,產生異常(Exception)。
異常與中斷:異常與中斷的處理機制相似,不一樣的是中斷由外部設備產生,而 異常由CPU內部產生的;中斷產生與CPU當前執行的指令無關,而異常是因爲當前執行的指令出現問題致使的
一般操做系統會將虛擬地址空間劃分爲用戶空間和內核空間。例如x86平臺的linux系統的虛擬地址空間範圍是0x0000 0000 ~ 0xffff ffff,前3G的空間爲用戶空間,後1G的空間爲內核空間。用戶程序加載到用戶空間,內核程序加載到內核空間,用戶程序不能訪問內核中的數據,也不能跳轉到內核空間執行。這樣能夠保護內核,若是一個進程訪問了非法地址,頂多就是這個進程崩潰,而不會影響到內核和系統的穩定性。在系統發生中斷或異常時,不只會跳轉到中斷或異常服務函數中執行,並且還會從用戶模式切換到特權模式,從中斷或異常服務程序跳轉到內核代碼中執行。總結一下:在正常狀況下處理器在用戶模式執行用戶程序,在中斷或異常狀況下處理器切換到特權模式執行內核程序,處理完中斷或異常以後再返回用戶模式繼續執行用戶程序。
段錯誤咱們已經遇到過不少次了,它是這樣產生的:
S3C2440的MMU使用頁表來實現虛擬地址到物理地址的轉換;頁表存儲在內存中,頁表中的每一行對應於虛擬存儲空間的一個頁,該行包含了該虛擬內存頁對應的物理內存頁的地址、該頁的方位權限和該頁的緩衝特性等。這裏頁表中的每一行稱爲一個地址變換條目(entry)也稱爲「描述符」。描述符有:段描述符、大頁描述符、小頁描述符、極小頁描述符——他們保存段、大頁、小頁或極小頁的起始物理地址;粗頁表描述符、細頁表描述符——它們保存二級頁表的物理地址。
頁表的存儲:頁表存放在內存中,系統一般有一個寄存器來保存頁表的基地址。在ARM中系統控制協處理器CP15的寄存器C2用來保存頁表的基地址。
TLB:由於從虛擬地址到物理地址的變換過程是經過查詢頁表完成的,而頁表又存儲在內存中,若是每次程序執行時去讀取內存中的數據獲取物理地址,代價很大。而程序在執行過程當中可能只對頁表中的少數幾個單元進行訪問,根據這一特色,採用一個容量更小(一般爲8~16個字)、訪問速度和CPU中通用寄存器至關的存儲器件來存放當前訪問須要的地址變換條目。這個小容量的頁表稱爲TLB(Translation Lookaside buffer)。
S3C2440/S3C2410中的頁表
在S32440/S3C2410中最多會使用兩級頁表:以段(Section 1MB)的方式進行轉換時只用到一級頁表,以頁(Page)的方式進行轉換時用到二級頁表。
CPU訪問內存的過程:
a . 當CPU須要訪問內存時,先在TLB中查詢須要的地址變換條目。若是該條目不存在,CPU從位於內存中的頁表中查詢,並把相應的結果添加到TLB中。這樣,當CPU下一次又須要該地址變換條目時,能夠從TLB中直接獲得,從而使地址變換的速度大大加快。
b. 當內存中的頁表內容改變,或者經過修改系統控制協處理器CP15的寄存器C2使用新的頁表時,TLB中的內容須要所有清除。系統控制協處理器CP15的寄存器C8用來控制清除TLB內容的相關操做。
c. MMU能夠將某些地址變換條目鎖定在TLB中,從而使得獲取該地址變換條目的速度保持很快。在CP15中的C10用於控制TLB內容的鎖定。
d. MMU 能夠將整個存儲空間分爲最多16個域,每一個域對應必定的內存區域,該區域具備相同的訪問控制屬性。MMU中寄存器C3用於控制與域相關的屬性的配置。
e. 當存儲訪問失效時,MMU提供了相應的機制用於處理這種狀況。在MMU中寄存器C5和寄存器C6用於支持這些機制。
應注意以下幾點:
ARM CPU上的地址轉換過程涉及3個概念:虛擬地址(VA)、變換後的虛擬地址(MVA, modified virtrual address)、物理地址(PA)。
沒啓動MMU時,CPU核、cache、MMU、外設等全部部件使用的都是物理地址。
啓動MMU後,CPU覈對外發出虛擬地址VA;VA被轉換爲MVA供cache、MMU使用,在這裏MVA被轉換爲PA,最後使用PA讀寫實際設備。
ARM支持的存儲塊大小有如下幾種:
MMU中的域指的是一些段、大頁或者小頁的集合。ARM支持最多16個域,每一個域的訪問控制特性由CP15中的寄存器C3中的兩位來控制,CP15中的寄存器C3的格式以下所示:
其中每兩位控制一個域的訪問控制特性,其編碼及對應的含義以下所示:
本篇文章簡要闡述MMU的概念,以及以段地址的轉換過程爲例,簡單說明MMU將虛擬地址轉換成物理地址的過程。更多詳細內容請查看《ARM-MMU(中文手冊).pdf》。
在ARM存儲系統中,使用MMU實現虛擬地址到實際物理地址的映射。爲什麼要實現這種映射?
首先就要從一個嵌入式系統的基本構成和運行方式着手。系統上電時,處理器的程序指針從0x0(或者是由0Xffff_0000處高端啓動)處啓動,順序執行程序,在程序指針(PC)啓動地址,屬於非易失性存儲器空間範圍,如ROM、FLASH等。然而與上百兆的嵌入式處理器相比,FLASH、ROM等存儲器響應速度慢,已成爲提升系統性能的一個瓶頸。而SDRAM具備很高的響應速度,爲什麼不使用SDRAM來執行程序呢?爲了提升系統總體速度,能夠這樣設想,利用FLASH、ROM對系統進行配置,把真正的應用程序下載到SDRAM中運行,這樣就能夠提升系統的性能。然而這種想法又遇到了另一個問題,當ARM處理器響應異常事件時,程序指針將要跳轉到一個肯定的位置,假設發生了IRQ中斷,PC將指向0x18(若是爲高端啓動,則相應指向0vxffff_0018處),而此時0x18處仍爲非易失性存儲器所佔據的位置,則程序的執行仍是有一部分要在FLASH或者ROM中來執行的。那麼咱們可不可使程序徹底都SDRAM中運行那?答案是確定的,這就引入了MMU,利用MMU,可把SDRAM的地址徹底映射到0x0起始的一片連續地址空間,而把原來佔據這片空間的FLASH或者ROM映射到其它不相沖突的存儲空間位置。例如,FLASH的地址從0x0000_0000-0x00ff_ffff,而SDRAM的地址範圍是0x3000_0000-0x31ff_ffff,則可把SDRAM地址映射爲0x0000_0000-0x1fff_ffff而FLASH的地址能夠映射到0x9000_0000-0x90ff_ffff(此處地址空間爲空閒,未被佔用)。映射完成後,若是處理器發生異常,假設依然爲IRQ中斷,PC指針指向0x18處的地址,而這個時候PC其實是從位於物理地址的0x3000_0018處讀取指令。經過MMU的映射,則可實現程序徹底運行在SDRAM之中。
在實際的應用中,可能會把兩片不連續的物理地址空間分配給SDRAM。而在操做系統中,習慣於把SDRAM的空間連續起來,方便內存管理,且應用程序申請大塊的內存時,操做系統內核也可方便地分配。經過MMU可實現不連續的物理地址空間映射爲連續的虛擬地址空間。
操做系統內核或者一些比較關鍵的代碼,通常是不但願被用戶應用程序所訪問的。經過MMU能夠控制地址空間的訪問權限,從而保護這些代碼不被破壞。
MMU的實現過程,實際上就是一個查表映射的過程。創建頁表(translate table)是實現MMU功能不可缺乏的一步。頁表是位於系統的內存中,頁表的每一項對應於一個虛擬地址到物理地址的映射。每一項的長度便是一個字的長度(在ARM中,一個字的長度被定義爲4字節)。頁表項除完成虛擬地址到物理地址的映射功能以外,還定義了訪問權限和緩衝特性等。
MMU 支持基於節或頁的存儲器訪問, MMU 能夠用下面四種大小進行映射:
節 ( Section ) 構成 1MB 的存儲器塊。
微頁 ( Tiny page ) 構成 1KB 的存儲器塊。
小頁 ( Small page ) 構成 4KB 的存儲器塊。
大頁 ( Large page ) 構成 64KB 的存儲器塊。
其中對於節映射使用一級轉換表就能夠了,而對於微頁、小頁、大頁則須要使用兩級轉換表。
要知道虛擬內存機制必須瞭解ARM9中的3種地址:VA(虛地址),MVA(修正後虛地址),PA(物理地址)
1)VA,是程序中的邏輯地址,0x00000000~0xFFFFFFFF。
2)MVA,是修改後的虛擬地址。在ARM9裏面,若是VA<32M,利用進程標識號PID轉換獲得MVA。過程以下:
if(VA < 32M) MVA = VA | ( PID<<25 ) else MVA = VA
只是上面的過程是由硬件實現的。這樣爲VA進行了一級映射,爲何呢?在linux系統裏,每一個進程的地址空間0-4G,0-3G是進程獨有的,稱爲用戶空間,3G-4G是系統的,稱爲內核空間,全部進程共享。若是兩個進程所用的VA有重疊,在切換進程時,爲了把重疊的VA映射到不一樣的PA上,須要重建頁表、使無效caches和TLBS。使用了MVA,使進程在VA相同的狀況下,使用不一樣的MVA,進而PA也不一樣。這就是在VA與PA之間加上一次到MVA的映射的意義。
3)PA,物理地址,MVA經過MMU轉換後的地址。
一級頁表使用 4096 個描述符來表示 4GB 空間,每一個描述符對應 1MB 的虛擬地址,存儲它對應的 1MB 物理空間的起始地址,或者存儲下一級頁表的地址。每一個描述符佔 4 個字節,格式以下:
使用 MVA[31:20]來索引一級頁表(20-31 一共 12 位,2^12=4096,因此是4096 個描述符)。其中段地址的轉換流程以下圖所示:
①頁表基址寄存器位[31:14]和 MVA[31:20]組成一個低兩位爲 0 的 32 位地址, MMU 利用這個地址找到段描述符。
②取出段描述符的位[31:20](段基址,section base address),它和 MVA[19:0]組成一個 32 位的物理地址(這就是 MVA 對應的 PA)
從MVA 到 PA 的轉換須要訪問屢次內存,大大下降了 CPU 的性能,有沒有辦法改進呢?
程序執行過程當中,用到的指令和數據的地址每每集中在一個很小的範圍內,其中的地址、數據常用,這是程序訪問的局部性。由此,經過使用一個高速、容量相對較小的存儲器來存儲近期用到的頁表條目(段、大頁、小頁、極小頁描述符),避免每次地址轉換都到主存中查找,這樣就大幅提升性能。這個存儲器用來幫助快速地進行地址轉換,成爲轉譯查找緩存(Translation Lookaside Buffers, TLB)。
當 CPU 發出一個虛擬地址時,MMU 首先訪問 TLB。若是 TLB 中含有能轉換這個虛擬地址的描述符,則直接利用此描述符進行地址轉換和權限檢查,不然 MMU 訪問頁表找到描述符後再進行地址轉換和權限檢查,並將這個描述符填入TLB 中,下次再使用這個虛擬地址時就直接使用 TLB 用的描述符。
若轉換成功,則稱爲」命中」。Linux 系統中,目前的」命中」率高達 90%以上,使分頁機制帶來的性能損失下降到了可接收的程度。若在 TLB 中進行查錶轉換失敗,則退縮爲通常的地址變換,機率小於 10%。
現代操做系統及CPU硬件中,都會提供內存管理單元(memory management unit,MMU)來進行內存的有效管理。內存管理算法有許多,從簡單的裸機方法到分頁和分段策略。各類算法都有其優缺點,爲特定系統選擇內存管理算法依賴於不少因素,特別是系統的硬件設計。
內存管理的目的是爲了更好的使用內存(彷佛是廢話-,-)。 內存是現代操做系統運行的中心。操做系統中任何一個進程的運行都須要內存,可是,操做系統中的內存是有限的;另外一方面,從安全的角度出發,進程都須要有自 己的內存空間,其餘的進程都不能訪問這個私有的空間;同時,內存的分配會致使內存碎片問題,嚴重影響計算機的性能。以上這三個問題就是通常內存管理算法所 須要處理的目標。
進程須要在內存中執行,但進程能夠暫時從內存中交換(swap)出去到備份存儲上,當須要時再調回到內存中去。
在基於優先級的交換調度算法中,若是一個更高優先級的進程來了且須要服務,內存管理能夠交換出低優先級的進程,以便裝入和執行更高優先級的進程。當高優先級的進程執行完畢以後,低優先級的進程能夠交換回內存繼續執行。這種交換有時被稱之爲滾出(roll out)、滾進(roll in)。
一般一個交換出的進程須要交換回它原來的內存空間。這一限制是由地址捆綁方式決定的。若是捆綁是在彙編時或加載時決定的,那麼就不能夠移動到不一樣的位置。若是捆綁是在運行時決定,因爲物理地址是在運行時才肯定,那麼進程能夠移到不一樣的地址空間。
交換的代價:交換時間
交換時間主要是指轉移時間,總的轉移時間和所交換的內存空間成正比。交換不須要或只須要不多的磁頭移動,簡單的說,交換空間一般做爲磁盤的一整塊,且獨立於文件系統(如Linux的swap空間),所以使用就有可能很快。
交換須要花不少時間,並且進程執行時間卻不多,故交換一般不執行,但只有在許多進程運行且內存吃緊時,交換纔開始啓動。
內存保護是指操做系統進程不受用戶進程的影響,保護用戶進程不受其餘用戶進程的影響。內存保護最基本的思路是進程使用邏輯地址空間,而內存管理單元所看的是物理地址。操做系統將邏輯地址分配給進程,MMU負責邏輯地址到物理地址的映射(轉換,捆綁)。
值得注意的是對於指令(程序)和數據映射到內存地址能夠在如下步驟地任意一步執行:
內存碎片是操做系統內存分配的產物。最初操做系統的內存是連續分配的,即進程A須要某一大小的內存空間,如200KB,操做系統就須要找出一塊至少200KB的連續內存空間給進程A。隨着系統的運行,進程終止時它將釋放內存,該內存能夠被操做系統分配給輸入隊列裏的其餘等待內存資源的進程。
能夠想象,隨着進程內存的分配和釋放,最初的一大塊連續內存空間被分紅許多小片斷,即便總的可用空間足夠,但再也不連續,所以產生的內存碎片。
一 個辦法是再也不對內存空間進行連續分配。這樣只要有物理內存就能夠爲進程進行分配。而實際上,不進行連續分配只是相對的,由於徹底這樣作的代價太大。現實 中,每每定出一個最小的內存單元,內存分配是這最小單元的組合,單元內的地址是連續的,但各個單元不必定連續。這樣的內存小單元有頁和段。
固然,分段和分頁也會產生碎片,但理論上每一個碎片的大小不超過內存單元的大小。
分頁時一種內存管理方案,同時也提供了內存保護機制。它容許分配的物理內存地址能夠是非連續的。
邏輯內存分爲大小相等塊的組合,這個塊稱之爲頁;物理內存則分爲固定大小的幀(frame)。頁大小應和幀大小相同,這是由硬件決定的。一般是2的冪,這樣能夠方便地將邏輯地址映射到物理地址。
基於分頁的邏輯地址到物理地址的映射
考慮32位地址。若是頁大小是4KB,則須要12位來表示每一頁中的某個具體地址,所以32位的邏輯地址中須要12位來對某一頁中的具體地址尋址。這12位叫作頁偏移。剩下的20位能夠做爲頁碼,能夠有1M的頁。邏輯地址能夠表示爲:
尋址時,根據頁碼P查頁表,找到該頁對應的幀,將幀號與頁偏移(也是幀偏移)組合即獲得物理地址。這樣也說明了爲何頁大小要等於幀大小,由於頁數要等於幀數。
例如,頁大小爲4K,頁碼11對應的幀碼是10,即表示是第10塊物理幀,也偏移爲5,則邏輯地址0X0000b 005對應的物理地址是0X0000a 005。
基於分頁的操做系統在分配內存時分給進程所須要的頁數,其對應物理內存的幀號同時裝入該MMU的頁表。同時頁表上有一個標記爲,指明該頁是屬於哪一個進程的。甚至能夠定義該頁對於某個進程的讀寫權限。非法的讀寫操做會產生硬件陷阱(或內存保護衝突)。
由上一節可知分頁是基於查找表的,而在內存中存儲這個1M個項目的頁表自己就帶來了內存消耗和查找速度問題。因而,頁表一般須要硬件的支持,即將頁表寫在硬件MMU的寄存器中。
若是頁表比較小,那麼頁表寫在寄存器中能夠加快查找速度。但絕大多數當代的計算機頁表都很是大。對於這些頁表,採用快速寄存器來實現頁表就不太合理了。
一種辦法是使用 TLB(translation look-aside buffer)。TLB是關聯的寄存器,TLB條目由兩部分組成:頁號和幀號。TLB只包含頁表中的一小部分條目,整個頁表仍是保存在內存中。當CPU產生邏輯地址後,其頁號提交給TLB。若是找到了頁號,那同時也就找到了幀號,就能夠訪問物理內存;若是頁號不在TLB中(稱爲TLB失效),那就須要訪問頁表。在頁表中找到幀號後,把頁號和幀號增長到TLB中,這樣下次再用時能夠很快找到。若是TLB中條目已滿,則操做系統會根據一個替換策略來替換條目。替換策略有不少,從最近最小使用替換到隨機替換等。另外,有的TLB容許某些條目不被替換,如內核代碼的條目。
有的TLB還在條目中保存地址空間保護標誌符,用來惟一標誌進程,以提供進程內存保護。
對於32位以及64位邏輯地址的計算機來講,其頁表實在太過龐大。爲了壓縮頁表,一個簡單的方法是使用層次化分頁算法,就是將頁表再分頁。(這其實是一種索引的方法)
即將2^20個頁表項分爲2^10個組,每一個組裏面有2^10項。這樣只須要2K*4=8K的頁表空間,且查找速度也有很大提高。例如原先最壞狀況下要查2^20次,如今最壞只要2*2^10次
內存管理單元MMU(memory management unit)
內存管理單元MMU(memory management unit)的主要功能是虛擬地址(virtual memory addresses)到物理地址(physical addresses)的轉換。除此以外,它還能夠實現內存保護(memory protection)、緩存控制(cache control)、總線仲裁(bus arbitration)以及存儲體切換(bank switching)。
CPU將要請求的虛擬地址傳給MMU,而後MMU先在高速緩存TLB(Translation Lookaside Buffer)查找轉換關係,若是找到了相應的物理地址則直接訪問;若是找不到則在地址轉換表(Translation Table)裏查找計算。
現代的內存管理單元是以頁的方式來分區虛擬地址空間(the range of addresses used by the processor)的。頁的大小是2的n次方,一般爲幾KB。因此虛擬地址就被分爲了兩個部分:virtual page number和offset。
上面從虛擬頁號在頁表裏找到的存放物理頁表號的條目就是頁表項(PTE)。PTE通常佔1個字長,裏面不只包含了physical page number,還包含了重寫標誌位(dirty bit)、訪問控制位(accessed bit)、容許讀寫的進程類型(user/supervisor mode)、是否能夠被cached以及映射類型(PTE最後兩位)。
映射方式
映射方式有兩種,段映射和頁映射。段映射只用到一級頁表,頁映射用到一級頁表和二級頁表。
映射粒度
段映射的映射粒度有兩種,1M section和16M supersection;頁映射的映射粒度有4K small page、64K large page和過期的1K tiny page。