Linux_MMU

MMU是Memory Management Unit的縮寫,中文名是內存管理單元,它是中央處理器(CPU)中用來管理虛擬存儲器、物理存儲器的控制線路,同時也負責虛擬地址映射爲物理地址,以及提供硬件機制的內存訪問授權。

編輯本段歷史

許多年以前,當人們還在使用DOS或是更古老的操作系統的時候,計算機的內存還非常小,一般都是以K爲單位進行計算,相應的,當時的程序規模也不大,所以內存容量雖然小,但還是可以容納當時的程序。但隨着圖形界面的興起還有用戶需求的不斷增大,應用程序的規模也隨之膨脹起來,終於一個難題出現在程序員的面前,那就是應用程序太大以至於內存容納不下該程序,通常解決的辦法是把程序分割成許多稱爲覆蓋塊(overlay)的片段。覆蓋塊0首先運行,結束時他將調用另一個覆蓋塊。雖然覆蓋塊的交換是由OS完成的,但是必須先由程序員把程序先進行分割,這是一個費時費力的工作,而且相當枯燥。人們必須找到更好的辦法從根本上解決這個問題。不久人們找到了一個辦法,這就是虛擬存儲器(virtual memory).虛擬存儲器的基本思想是程序,數據,堆棧的總的大小可以超過物理存儲器的大小,操作系統把當前使用的部分保留在內存中,而把其他未被使用的部分保存在磁盤上。比如對一個16MB的程序和一個內存只有4MB的機器,操作系統通過選擇,可以決定各個時刻將哪4M的內容保留在內存中,並在需要時在內存和磁盤間交換程序片段,這樣就可以把這個16M的程序運行在一個只具有4M內存機器上了。而這個16M的程序在運行前不必由程序員進行分割。

編輯本段相關概念

——地址範圍、虛擬地址映射爲物理地址 以及分頁機制
任何時候,計算機上都存在一個程序能夠產生的地址集合,我們稱之爲地址範圍。這個範圍的大小由CPU的位數決定,例如一個32位的CPU,它的地址範圍是0~0xFFFFFFFF (4G),而對於一個64位的CPU,它的地址範圍爲0~0xFFFFFFFFFFFFFFFF (16E).這個範圍就是我們的程序能夠產生的地址範圍,我們把這個地址範圍稱爲虛擬地址空間,該空間中的某一個地址我們稱之爲虛擬地址。與虛擬地址空間和虛擬地址相對應的則是物理地址空間和物理地址,大多數時候我們的系統所具備的物理地址空間只是虛擬地址空間的一個子集。這裏舉一個最簡單的例子直觀地說明這兩者,對於一臺內存爲256M的32bit x86主機來說,它的虛擬地址空間範圍是0~0xFFFFFFFF(4G),而物理地址空間範圍是0x000000000~0x0FFFFFFF(256M)。
在沒有使用虛擬存儲器的機器上,虛擬地址被直接送到內存總線上,使具有相同地址的物理存儲器被讀寫;而在使用了虛擬存儲器的情況下,虛擬地址不是被直接送到內存地址總線上,而是送到存儲器管理單元MMU,把虛擬地址映射爲物理地址。
大多數使用虛擬存儲器的系統都使用一種稱爲分頁(paging)機制。虛擬地址空間劃分成稱爲頁(page)的單位,而相應的物理地址空間也被進行劃分,單位是頁幀(frame).頁和頁幀的大小必須相同。在這個例子中我們有一臺可以生成32位地址的機器,它的虛擬地址範圍從0~0xFFFFFFFF(4G),而這臺機器只有256M的物理地址,因此他可以運行4G的程序,但該程序不能一次性調入內存運行。這臺機器必須有一個達到可以存放4G程序的外部存儲器(例如磁盤或是FLASH),以保證程序片段在需要時可以被調用。在這個例子中,頁的大小爲4K,頁幀大小與頁相同——這點是必須保證的,因爲內存和外圍存儲器之間的傳輸總是以頁爲單位的。對應4G的虛擬地址和256M的物理存儲器,他們分別包含了1M個頁和64K個頁幀。

編輯本段功能

1、將虛擬地址映射爲物理地址

現代的多用戶多進程操作系統,需要MMU,才能達到每個用戶進程都擁有自己獨立的地址空間的目標。使用MMU,操作系統劃分出一段地址區域,在這塊地址區域中,每個進程看到的內容都不一定一樣。例如MICROSOFTWINDOWS操作系統將地址範圍4M-2G劃分爲用戶地址空間,進程A在地址0X400000(4M)映射了可執行文件,進程B同樣在地址0X400000(4M)映射了可執行文件,如果A進程讀地址0X400000,讀到的是A的可執行文件映射到RAM的內容,而進程B讀取地址0X400000時,則讀到的是B的可執行文件映射到RAM的內容。
這就是MMU在當中進行地址轉換所起的作用。

2、提供硬件機制的內存訪問授權

多年以來,微處理器一直帶有片上存儲器管理單元(MMU),MMU能使單個軟件線程工作於硬件保護地址空間。但是在許多商用實時操作系統中,即使系統中含有這些硬件也沒采用MMU。
應用程序的所有線程共享同一存儲器空間時,任何一個線程將有意或無意地破壞其它線程的代碼、數據或堆棧。異常線程甚至可能破壞內核代碼或內部數據結構。例如線程中的指針錯誤就能輕易使整個系統崩潰,或至少導致系統工作異常。
就安全性和可靠性而言,基於進程的實時操作系統(RTOS)的性能更爲優越。爲生成具有單獨地址空間的進程,RTOS只需要生成一些基於RAM的數據結構並使MMU加強對這些數據結構的保護。基本思路是在每個關聯轉換中“接入”一組新的邏輯地址。MMU利用當前映射,將在指令調用或數據讀寫過程中使用的邏輯地址映射爲存儲器物理地址。MMU還標記對非法邏輯地址進行的訪問,這些非法邏輯地址並沒有映射到任何物理地址
這些進程雖然增加了利用查詢表訪問存儲器所固有的系統開銷,但其實現的效益很高。在進程邊界處,疏忽或錯誤操作將不會出現,用戶接口線程中的缺陷並不會導致其它更關鍵線程的代碼或數據遭到破壞。目前在可靠性和安全性要求很高的複雜嵌入式系統中,仍然存在採無存儲器保護的操作系統的情況,這實在有些不可思議。
採用MMU還有利於選擇性地將頁面映射或解映射到邏輯地址空間。物理存儲器頁面映射至邏輯空間,以保持當前進程的代碼,其餘頁面則用於數據映射。類似地,物理存儲器頁面通過映射可保持進程的線程堆棧。RTOS可以在每個線程堆棧解映射之後,很容易地保留邏輯地址所對應的頁面內容。這樣,如果任何線程分配的堆棧發生溢出,將產生硬件存儲器保護故障,內核將掛起該線程,而不使其破壞位於該地址空間中的其它重要存儲器區,如另一線程堆棧。這不僅在線程之間,還在同一地址空間之間增加了存儲器保護。
存儲器保護(包括這類堆棧溢出檢測)在應用程序開發中通常非常有效。採用了存儲器保護,程序錯誤將產生異常並能被立即檢測,它由源代碼進行跟蹤。如果沒有存儲器保護,程序錯誤將導致一些細微的難以跟蹤的故障。實際上,由於在扁平存儲器模型中,RAM通常位於物理地址的零頁面,因此甚至NULL指針引用的解除都無法檢測到。

編輯本段MMU和CPU

1、X86系列的MMU

INTEL出品的80386CPU或者更新的CPU中都集成有MMU. 可以提供32BIT共4G的地址空間.
X86 MMU提供的尋址模式有4K/2M/4M的PAGE模式(根據不同的CPU,提供不同的能力),此處提供的是目前大部分操作系統使用的4K分頁機制的描述,並且不提供ACCESS CHECK的部分。
涉及的寄存器
a) GDT
b) LDT
c) CR0
d) CR3
e) SEGMENT REGISTER
虛擬地址到物理地址的轉換步驟
a) SEGMENT REGISTER作爲GDT或者LDT的INDEX,取出對應的GDT/LDT ENTRY.
注意: SEGMENT是無法取消的,即使是FLAT模式下也是如此. 說FLAT模式下不使用SEGMENT REGISTER是錯誤的. 任意的RAM尋址指令中均有DEFAULT的SEGMENT假定. 除非使用SEGMENT OVERRIDE PREFⅨ來改變當前尋址指令的SEGMENT,否則使用的就是DEFAULT SEGMENT.
ENTRY格式
typedef struct
{
UINT16 limit_0_15;
UINT16 base_0_15;
UINT8 base_16_23;
UINT8 accessed : 1;
UINT8 readable : 1;
UINT8 conforming : 1;
UINT8 code_data : 1;
UINT8 app_system : 1;
UINT8 dpl : 2;
UINT8 present : 1;
UINT8 limit_16_19 : 4;
UINT8 unused : 1;
UINT8 always_0 : 1;
UINT8 seg_16_32 : 1;
UINT8 granularity : 1;
UINT8 base_24_31;
} CODE_SEG_DESCRIPTOR,*PCODE_SEG_DESCRIPTOR;
typedef struct
{
UINT16 limit_0_15;
UINT16 base_0_15;
UINT8 base_16_23;
UINT8 accessed : 1;
UINT8 writeable : 1;
UINT8 expanddown : 1;
UINT8 code_data : 1;
UINT8 app_system : 1;
UINT8 dpl : 2;
UINT8 present : 1;
UINT8 limit_16_19 : 4;
UINT8 unused : 1;
UINT8 always_0 : 1;
UINT8 seg_16_32 : 1;
UINT8 granularity : 1;
UINT8 base_24_31;
} DATA_SEG_DESCRIPTOR,*PDATA_SEG_DESCRIPTOR;
共有4種ENTRY格式,此處提供的是CODE SEGMENT和DATA SEGMENT的ENTRY格式. FLAT模式下的ENTRY在base_0_15,base_16_23處爲0,而limit_0_15,limit_16_19處爲0xfffff. granularity處爲1. 表名SEGMENT地址空間是從0到0XFFFFFFFF的4G的地址空間.
b) 從SEGMENT處取出BASE ADDRESS 和LIMIT. 將要訪問的ADDRESS首先進行ACCESS CHECK,是否超出SEGMENT的限制.
c) 將要訪問的ADDRESS+BASE ADDRESS,形成需要32BIT訪問的虛擬地址. 該地址被解釋成如下格式:
typedef struct
{
UINT32 offset :12;
UINT32 page_index :10;
UINT32 pdbr_index :10;
} VA,*LPVA;
d) pdbr_index作爲CR3的INDEX,獲得到一個如下定義的數據結構
typedef struct
{
UINT8 present :1;
UINT8 writable :1;
UINT8 supervisor :1;
UINT8 writethrough:1;
UINT8 cachedisable:1;
UINT8 accessed :1;
UINT8 reserved1 :1;
UINT8 pagesize :1;
UINT8 ignoreed :1;
UINT8 avl :3;
UINT8 ptadr_12_15 :4;
UINT16 ptadr_16_31;
}PDE,*LPPDE;
e) 從中取出PAGE TABLE的地址. 並且使用page_index作爲INDEX,得到如下數據結構
typedef struct
{
UINT8 present :1;
UINT8 writable :1;
UINT8 supervisor :1;
UINT8 writethrough:1;
UINT8 cachedisable:1;
UINT8 accessed :1;
UINT8 dirty :1;
UINT8 pta :1;
UINT8 global :1;
UINT8 avl :3;
UINT8 ptadr_12_15 :4;
UINT16 ptadr_16_31;
}PTE,*LPPTE;
f) 從PTE中獲得PAGE的真正物理地址的BASE ADDRESS. 此BASE ADDRESS表名了物理地址的.高20位. 加上虛擬地址的offset就是物理地址所在了.

2、ARM系列的MMU

ARM出品的CPU,MMU作爲一個協處理器存在。根據不同的系列有不同搭配。需要查詢DATASHEET纔可知道是否有MMU。如果有的話,一定是編號爲15的協處理器。可以提供32BIT共4G的地址空間。
ARM MMU提供的分頁機制有1K/4K/64K 3種模式. 本文介紹的是目前操作系統通常使用的4K模式。
涉及的寄存器,全部位於協處理器15.
ARM cpu地址轉換涉及三種地址:虛擬地址(VA,Virtual Address),變換後的虛擬地址(MVA,Modified Virtual Address),物理地址(PA,Physical Address)。沒有啓動MMU時,CPU核心、cache、MMU、外設等所有部件使用的都是物理地址。啓動MMU後,CPU核心對外發出的是虛擬地址VA,VA被轉換爲MVA供cache、MMU使用,並再次被轉換爲PA,最後使用PA讀取實際設備。
ARM沒有SEGMENT的寄存器,是真正的FLAT模式的CPU。給定一個ADDRESS,該地址可以被理解爲如下數據結構:
typedef struct
{
UINT32 offset :12;
UINT32 page_index :8;
UINT32 pdbr_index :12;
} VA,*LPVA;
從MMU寄存器2中取出BIT14-31,pdbr_index就是這個表的索引,每個入口爲4BYTE大小,結構爲
typedef struct
{
UINT32 type :2; //always set to 01b
UINT32 writebackcacheable:1;
UINT32 writethroughcacheable:1;
UINT32 ignore :1; //set to 1b always
UINT32 domain :4;
UINT32 reserved :1; //set 0
UINT32 base_addr:22;
} PDE,*LPPDE;
獲得的PDE地址,獲得如下結構的ARRAY,用page_index作爲索引,取出內容。
typedef struct
{
UINT32 type :2; //always set to 11b
UINT32 ignore :3; //set to 100b always
UINT32 domain :4;
UINT32 reserved :3; //set 0
UINT32 base_addr:20;
} PTE,*LPPTE;
從PTE中獲得的基地址和上offset,組成了物理地址.
PDE/PTE中其他的BIT,用於訪問控制。這邊講述的是一切正常,物理地址被正常組合出來的狀況。
ARM/X86 MMU使用上的差異
⒈X86始終是有SEGMENT的概念存在. 而ARM則沒有此概念(沒有SEGMENT REGISTER.).
⒉ARM有個DOMAIN的概念. 用於訪問授權. 這是X86所沒有的概念. 當通用OS嘗試同時適用於此2者的CPU上,一般會拋棄DOMAIN的使用.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章