vivi開發(fā)筆記(十二):MMU分析 (2007-08-16 21:31)
分類: Vivi
這幾天一直在看MMU部分,,現(xiàn)在有了基本的認(rèn)識,,還不深入,解決了初級問題,,并且仿照vivi完成了一個測試實(shí)例,,對深入理解和驗(yàn)證推論的結(jié)果很有幫助。在學(xué)習(xí)的過程中,,體會到幾種方法還是比較實(shí)用的:
· 從歷史的角度去了解技術(shù),,梳理清楚發(fā)展主線,效率更高,。
· 采用軟硬件結(jié)合的方法分析,,理解更為深入。
· 與同一愛好的朋友交流,可以發(fā)現(xiàn)認(rèn)識的盲區(qū),,認(rèn)識更為全面,。
· 應(yīng)該閱讀英文的Datasheet,中文翻譯往往有錯誤,,有時候是致命的,,以前在c8051F020的SPI的設(shè)計(jì)中就因?yàn)檫@個問題研究了一周,最后才發(fā)現(xiàn)中文翻譯有問題,,這也足以說明還是原版更具有可信度,。但是呢,,不要絕對化,,原版也可能有錯誤。在閱讀學(xué)習(xí)的過程中,,如果理解到設(shè)計(jì)的巧妙,,那么很好,拿來使用,。如果暫時不能理解,,或者認(rèn)為原版有錯誤,那么不妨持懷疑的態(tài)度進(jìn)行學(xué)習(xí),,即使錯了,,也能學(xué)到很多東西,甚至從錯誤中學(xué)到的東西更多,。
· 充分利用網(wǎng)絡(luò)資源,。站在巨人的肩上可以更高更遠(yuǎn)!但是,,你必須訓(xùn)練讓自己具備找到巨人的能力,!
下面開始MMU的探討。因?yàn)檫€只是處于初級階段,,本文僅就MMU的基礎(chǔ)方面和應(yīng)用作一下探討,,其中還有沒有明確的地方,待解決,。
一,、MMU是什么?
MMU,,英文名稱為Memory Manage Unit,, 中文可以為“內(nèi)存管理單元”,或者“存儲器管理單元”,。MMU是硬件設(shè)備,,它與virtual memory是緊密聯(lián)系在一起的。
看一下s3c2410 datasheet Appendix 1中關(guān)于ARM920T的介紹(因?yàn)閟3c2410采用的是ARM920T的處理器),。對ARM9系列處理器有如下幾種:
可見ARM920T具備了MMU功能部件,。而且還有cache,。它采用了一種變形的Harvard架構(gòu),擁有16KB的Instruction cache和16KB的Data cache,,MMU和cache有密切的聯(lián)系,,后面會談到。
總之,,由于s3c2410這款SoC采用了ARM920T的處理器(處理器內(nèi)核為ARM9TDMI,,關(guān)于這些命名的區(qū)分在前面已經(jīng)討論過了),所以擁有了MMU和cache,。有了這個硬件基礎(chǔ),,軟件上才可能使用這個功能。那么,,現(xiàn)在的問題是,,s3c2410擁有MMU,那么MMU到底有什么用呢,?還是從歷史發(fā)展的角度看一下,。
二、從歷史發(fā)展的角度看MMU的作用
這一部分可結(jié)合蔡于清的講解【網(wǎng)址:http://www./viewthread.php?tid=28&extra=page%3D1】來看,,下面的大部分內(nèi)容轉(zhuǎn)載此處,,針對自己的理解做了一些擴(kuò)充性說明。只是需要注意的是,,在蔡于清此部分的講解中,,有幾處小的錯誤,完成此部分的講解后可以進(jìn)行更正,。
MMU功能部件是與虛擬內(nèi)存技術(shù)(virtual memory)緊密聯(lián)系在一起的,。
第一階段:最初,計(jì)算機(jī)內(nèi)存很小,,而且非常昂貴,,大多數(shù)都是以KB為單位的。相應(yīng)的,,當(dāng)時程序規(guī)模很小,,不復(fù)雜,所以內(nèi)存還是能夠滿足需求的,。在看《Linkers and Loaders》的時候,,也是從這個階段講解,不過此書的核心視角是從Linkers和Loaders的發(fā)展來看的,。也就是,,計(jì)算機(jī)剛剛出現(xiàn)時,還是比較簡陋的,各種復(fù)雜的技術(shù)是伴隨著人們需求的提高而出現(xiàn)的,。把握住這一點(diǎn),,就可以從需求的角度入手探討技術(shù),可以分析它如何滿足了這樣的需求,。通過這種分析,,理解上就比較簡單一些了。
第二階段:程序規(guī)模擴(kuò)大,,考慮到成本問題,,出現(xiàn)了overlay技術(shù),也就是內(nèi)存覆蓋策略,?;镜脑砭褪前殉绦蚍指畛稍S多稱為“覆蓋塊”的片斷。覆蓋塊0首先加載運(yùn)行,,結(jié)束時調(diào)用另一個覆蓋塊,。覆蓋塊的調(diào)度是由OS來完成的,但是事先需要分割,,這部分工作是程序員借助Linkers來完成的。但是畢竟枯燥,,由此帶來的開銷也比較大,。于是進(jìn)入第三個階段。
第三階段:出現(xiàn)virtual memory,。虛擬存儲器的基本思想是程序,,數(shù)據(jù),堆棧的總的大小可以超過物理存儲器的大小,,操作系統(tǒng)把當(dāng)前使用的部分保留在內(nèi)存中,,而把其他未被使用的部分保存在磁盤上。比如對一個16MB的程序和一個內(nèi)存只有4MB的機(jī)器,,OS通過選擇,,可以決定各個時刻將哪4M的內(nèi)容保留在內(nèi)存中,并在需要時在內(nèi)存和磁盤間交換程序片段,,這樣就可以把這個16M的程序運(yùn)行在一個只具有4M內(nèi)存機(jī)器上了,。而這個16M的程序在運(yùn)行前不必由程序員進(jìn)行分割。
伴隨著這種技術(shù)的出現(xiàn),,“virtual address,,即VA”和“physical address, 即PA”也就出現(xiàn)了,。一般來說,,CPU看到的地址是VA,VA是有地址線來決定的。比如,,s3c2410是32位的SoC,,那么它的尋址空間為2^32=4GB,那么VA空間也就是4GB,。但是在嵌入式系統(tǒng)中,,物理存儲器是不會有這么大的。現(xiàn)在這塊s3c2410的實(shí)際內(nèi)存SDRAM也就64MB,,遠(yuǎn)遠(yuǎn)小于4GB,。也就是說,VA是4GB,,PA是64MB,,PA的地址空間是VA地址空間的子集。既然PA沒有VA那么大,,而且CPU只能看到VA,,那么CPU如何找到PA呢?這也正是MMU的基本作用之一,,就是提供VA到PA的轉(zhuǎn)換機(jī)制,,除了硬件的支持外,軟件上實(shí)際就是維護(hù)一張表,,表中的內(nèi)容是VA到PA的轉(zhuǎn)換法則,。由于有了MMU,那么就可以實(shí)現(xiàn)利用VA找到實(shí)際物理內(nèi)存區(qū)域,。 現(xiàn)在討論為什么要實(shí)現(xiàn)VA到PA的映射,。就ARM而言,系統(tǒng)上電后,,CPU的PC指向0x00000000或者0xffff0000,,這是由CPU的設(shè)計(jì)者決定的。在這個位置,,一般安排非易失性存儲器地址空間,,比如rom,flash等,。但是flash等響應(yīng)速度慢,,這就稱為提高系統(tǒng)性能的一個瓶頸。而sdram則具有很高的響應(yīng)速度,,為了提高系統(tǒng)運(yùn)行速度,,可以把flash中的應(yīng)用程序下載到sdram中執(zhí)行,也就是一個簡單的loader的功能實(shí)現(xiàn),。這樣就出現(xiàn)一個問題,,ARM響應(yīng)exception時,,程序指針指向固定的VA,比如,,假設(shè)發(fā)生了IRQ中斷,,那么PC執(zhí)行0x00000018(如果是高端啟動,則指向0xffff0018處,。)但是此處仍然為非易失性存儲器,,也就是說,程序的一部分仍然在flash或者rom中執(zhí)行,。這時可以利用MMU,,把sdram的地址映射到0x00000000起始的一片連續(xù)地址空間,而把原來flash映射到其他不相沖突的存儲空間位置,。例如,,flash的地址范圍0x00000000-0x00ffffff,sdram的地址范圍0x30000000-0x31ffffff,。那么可以把sdram映射到0x00000000-0x1fffffff(此處地址空間未被占用),。映射完成后,如果處理器異常,,假設(shè)依然為IRQ中斷,,pc指向0x00000018,但是pc實(shí)際上是從物理地址0x30000018處讀取指令,。通過mmu的映射,,可以實(shí)現(xiàn)系統(tǒng)運(yùn)行的加速。這個地方也可以說明bootloader中常見的中斷向量表的設(shè)置,,為什么有些使用b,有些使用ldr了,?!綽的跳轉(zhuǎn)空間只能是+-32M,而ldr可以大的多了,?!?/div>
在實(shí)際的應(yīng)用過程中,還可能會把兩片不連續(xù)的物理地址空間分配給sdram,,而在os中,,習(xí)慣上把sdram的空間連續(xù)起來,方便實(shí)現(xiàn)動態(tài)內(nèi)存管理,。通過mmu可以實(shí)現(xiàn)不連續(xù)的物理地址空間映射為虛擬地址空間,。
另外一個需求就是,實(shí)現(xiàn)不同的運(yùn)行級別,,那么一些關(guān)鍵的代碼可以設(shè)定不被普通應(yīng)用程序訪問,。這也是通過mmu控制訪問權(quán)限來實(shí)現(xiàn)的,。
綜上三個階段所述,可見MMU的作用主要就是兩個:
· 實(shí)現(xiàn)VA到PA的映射(可以因此實(shí)現(xiàn)方便的動態(tài)內(nèi)存管理)
· 實(shí)現(xiàn)不同的訪問權(quán)限,。
三,、結(jié)合s3c2410來分析MMU的幾處硬件特點(diǎn)
首先看看ARM920T的框圖:
可以驗(yàn)證前面的幾個概念:
·位于中心的ARM9TDMI Processor Core發(fā)出的地址有兩種,IVA和DVA,,都是VA,。其中I代表Instruction, D代表Data,。也就是說,,CPU核心看到的都是32bits的VA。
·Dcache,、Icache,、Dmmu、Immu看到的都是對應(yīng)的MVA(modified virtual address),,這個是比較復(fù)雜的地方,,下面專門拿出這個來講解。
·MMU處理后的輸出地址都是對應(yīng)的PA,,通過AMBA Bus Interface連接到ASB總線上面,。
這樣,從硬件上對地址的概念就比較清晰了,。也可以很明顯的看出MMU的功能:將VA轉(zhuǎn)換成PA,。但是現(xiàn)在存在的一個問題是,MVA是什么,,為什么要用到MVA,?
可以看CP15協(xié)處理器的register 13。這個寄存器是進(jìn)程識別寄存器,,主要的操作如下:
寄存器的字格式為:
很清晰,,ProcID為7bits,剩下的25bits should be zero,,也就是可以實(shí)現(xiàn)2^25=32M的地址對齊,。從這個道理上講,每個進(jìn)程擁有32M的MVA地址空間,,而最多支持的進(jìn)程數(shù)為2^7=128個,。這樣,128*32M=4GB,,正是全部的虛擬地址空間,。但是,英文的datasheet上卻并非如此,,寫的記錄數(shù)字為64個進(jìn)程,,同樣每個進(jìn)程32M,,怎么可能達(dá)到4GB?參看下圖:
我覺得上圖中的63應(yīng)該改為127,。因?yàn)檫@個63處不可能對應(yīng)4GB,,而應(yīng)該對應(yīng)2GB。判斷此處屬于datasheet的錯誤,。
還有,,這個procID是何時,有誰寫入的,?有誰來維護(hù),?根據(jù)推斷,在bootloader階段,,只需要一個進(jìn)程就可以了,,所以,procID一直都是復(fù)位后默認(rèn)的0,,不需要改變,。但是后面有了OS后,要想實(shí)現(xiàn)多進(jìn)程,,那么就需要對此維護(hù)了,。所以procID的維護(hù)者是系統(tǒng)軟件OS。在創(chuàng)建一個新進(jìn)程的時候,,要把進(jìn)程號寫入procID,。
另外,關(guān)于MVA部分的轉(zhuǎn)換公式,,實(shí)際上還是有疑問的,。
寫成偽代碼,可以參考《s3c2410完全開發(fā)》,。
thisway.diy說利用PID來生成MVA的目的是為了減少切換進(jìn)程時的代價:如果兩個進(jìn)程占用的VA有重疊,,不進(jìn)行上述處理的話,當(dāng)進(jìn)行進(jìn)程切換時必須進(jìn)行VA到PA的重新映射,,這就需要重新建立頁表,使無效cache和TLB等等,,代價很大,。但是如果進(jìn)行上述處理的話,進(jìn)程切換就省事多了:假設(shè)兩個進(jìn)程1,、2運(yùn)行時的VA都是0-32M,,則它們的MVA分別是(0x02000000-0x03ffffff)、(0x04000000-0x05ffffff),,前面看到的MMU,、cache使用MVA而不是使用VA,,這樣就不必進(jìn)行重建頁表等工作了。
但是這里帶來的一個問題是,,如果進(jìn)程運(yùn)行時的VA小于32M,,那么根據(jù)PID的不同,可以達(dá)到4GB空間的任意部分,,也就是,,雖然可以避免運(yùn)行VA小于32M時的不同進(jìn)程的“撞車”,但是同時帶來的是VA小于32M可能與VA大于32M的進(jìn)程產(chǎn)生了“撞車”,。這樣不是更為普遍嗎,?現(xiàn)在從原理上還不能理解。翻看《ARM Architecture Reference Manual》,,發(fā)現(xiàn)對于ARM核,,如果采用MVA,那么進(jìn)程切換實(shí)際上對應(yīng)著Fast context switch extension,,不知道原理是什么,。對于研究bootloader來說,現(xiàn)在不設(shè)計(jì)到多進(jìn)程,,整個系統(tǒng)就是一個獨(dú)立的單進(jìn)程,,PID就是默認(rèn)的0x0。這個問題可能要后推了,。
四,、提出幾個問題
1、在vivi中為什么使用了MMU,?是否可以不用,?
這個問題已經(jīng)解決。實(shí)際上,,在nand flash啟動的情況下,,vivi中可以不使用MMU。因?yàn)橐皇侵袛嘞蛄勘硎欠旁趕ram里,,響應(yīng)速度比sdram還要快,。另外,在bootloader階段,,只有一個進(jìn)程,,不存在多進(jìn)程的內(nèi)存空間重疊的問題。也因?yàn)橐粋€進(jìn)程,,所以單純的PA就滿足需求,,沒有必要用VA。開始時,,也不需要區(qū)分訪問權(quán)限,。大量的工作,,比如進(jìn)程切換、權(quán)限訪問等等,,都是在EOS中處理的,。所以,這種情況下,,可以不使用MMU,。我把vivi中關(guān)于MMU的部分去除,編譯下載,,可以正常引導(dǎo)內(nèi)核啟動,,沒有問題。
那么,,vivi為什么要開啟MMU呢,?原因也是比較簡單的,就是追求系統(tǒng)運(yùn)行的高效,。因?yàn)閟3c2410的Icache不受MMU的影響,,而Dcache和write buffer則必須開啟了MMU功能之后,才能使用,。而使用Dcache和write buffer后,,對系統(tǒng)運(yùn)行速度的提高是非常明顯的,后面還將通過實(shí)驗(yàn)來驗(yàn)證這一點(diǎn),。也就是說,,在nand flash啟動時,vivi使用了MMU,,主要是為了獲得Dcache和write buffer的使用權(quán),,借此提高系統(tǒng)運(yùn)行的性能。
2,、使用了MMU,,那么軟硬件是如何分工協(xié)作的?
這個基本搞清楚了,,但是還有一個遺留問題,。針對于s3c2410,可以分為如下幾個階段:
· 第一階段 軟件準(zhǔn)備
MMU在軟件上的實(shí)現(xiàn)過程,,實(shí)際上就是一個查表映射的過程,。建立頁表(translation table)是MMU功能的重要的一步。頁表就是內(nèi)存的一塊區(qū)域,,由一個個固定格式的entry組成。其中每個entry對應(yīng)一個VA到PA的轉(zhuǎn)換,,每一項(xiàng)的長度是一個word,,還可以完成訪問權(quán)限和緩沖特性的限定,。在軟件上,就是要把這個表填好,。重映射就是修改相應(yīng)的entry,,改變了原來的映射規(guī)則,很簡單,。
這步工作是要軟件提前準(zhǔn)備的,。需要注意的是,明確如何找到這個頁表,。對于表的查找,,需要知道表的基地址和偏移地址,在cp15的register 2用于保存頁表的基地址,,這樣就可以查找到相應(yīng)的PA了,。
· 第二階段 硬件完成VA-MVA
硬件根據(jù)ARM9TDMI發(fā)出的VA和CP15的register 13來自動生成MVA。
· 第三個階段
硬件自動實(shí)現(xiàn)cache查詢,,如果沒有,,則根據(jù)cp15的register 2和MVA找到translation table中的entry,實(shí)現(xiàn)相應(yīng)的PA轉(zhuǎn)換,,讀取內(nèi)存,,然后根據(jù)cache算法更新cache。也就是說,,這個階段也是硬件實(shí)現(xiàn)的,。不過軟件上對cache要進(jìn)行相應(yīng)的管理,這個地方的算法相對還是比較復(fù)雜的,。
綜上,,對單進(jìn)程而言,軟件操作上就是維護(hù)translation table,,并且處理好cache相關(guān)操作,。
五、實(shí)驗(yàn)
實(shí)驗(yàn)內(nèi)容比較簡單,,綜合了前面的串口實(shí)驗(yàn),,燈循環(huán)點(diǎn)亮實(shí)驗(yàn),中斷實(shí)驗(yàn),,nand flash實(shí)驗(yàn),,另外,加入了MMU功能,。利用MMU功能的開啟,,觀察燈循環(huán)點(diǎn)亮實(shí)驗(yàn),如果開啟了Dcache和write buffer,燈閃的速度明顯快的多,,幾乎看不出間隔,,而把其關(guān)閉,則還能夠看出間隔,。這還是在12MHz的前提下,,還沒有把PLL功能開啟。如果把PLL功能開啟,,還需要進(jìn)行相應(yīng)的調(diào)整,。
源代碼如下,完全仿照vivi的架構(gòu),,另外,,mmu部分基本是采用vivi的源代碼,具體的分析留待vivi源代碼分析時解決,。其實(shí),,如果開啟了mmu,cache和write buffer是否能夠合理有效的使用還是一個問題,。如果使用不當(dāng),,帶來的問題可能會比較奇怪,而且難以解決,。在這個過程中,,需要對照現(xiàn)有的較好的代碼進(jìn)行分析,總結(jié)規(guī)律,,然后應(yīng)用到自己的設(shè)計(jì)中去,。
|
|
來自: 向往~ > 《vivi源碼分析》