S3C2440的MMU

  MMU:memory management unit 存儲管理單元。主要的做用有2個:權限管理 和 地址映射。算法

1、功能編程

  (1) 權限管理架構

  簡單說就是,進程之間不能訪問對方的地址空間,如強制訪問則報錯,程序崩潰但不會影響到其它進程。出現的提示是「訪問非法地址0xxxxxx」。dom

  (2)地址映射spa

  即完成虛擬地址到物理地址的轉換工做。操作系統

2、MMU的地址映射原理code

  首先,觀察一個CPU<--->MMU<--->存儲管理器<--->外接存儲器(以SDRAM爲例)框圖。blog

   

  鏈接1處,即CPU發出的地址。站在CPU角度分析,不會區分虛擬地址和物理地址。若是MMU沒有使能的話,那麼CPU發出的地址就直接到達存儲管理器,是物理地址。而若是MMU使能的狀況,CPU發出地址爲虛擬地址,通過MMU轉換爲物理地址。並送到存儲管理器。進程

  鏈接2處,即MMU轉換完成(若是MMU使能)的物理地址,或者存儲管理器接收的物理地址。所以,存儲管理器操做的都是物理地址。內存

  鏈接3處,即通過操做選擇不一樣的Bank經過器件的選通功能完成的。

3、MMU的地址轉換過程

  注意本文講解的都是基於裸跑純硬件的,並無複雜操做系統(如Linux)的支持,網上搜到的不少博客都是對有操做系統的討論。

     MIPS架構中很是簡單,其MMU對轉換過程知足下述公式:虛擬地址 = 0xA000 0000 + 物理地址

     ARM架構的CPU中較爲複雜。分爲兩種段和頁。其中頁方式又能夠細分爲大頁、小頁、極小頁。本文主要講的是段方式的轉換。

     所謂段映射就是創建一個表項,一般一個段的大小規定爲1M。

     例如CPU的地址總線是32位的,那麼就意味着,訪問的地址空間能夠達到2的32次方,也就是4G空間。根據段的大小規定1M,因此應該創建的表項就是4G/1M=4096項。具體解釋可參見下圖

     

  若是創建如圖所示的表項,那麼,若是CPU須要訪問的地址在0~1M,那麼MMU就會在第1個表項中,取出實際物理地址。而後交給存儲管理器。固然,若是訪問形成衝突的狀況下,須要必定的算法來處理。

  那麼最後能夠講解一個簡單的MMU段方式的映射的流程:

  第1步,創建段表項。

  在哪建?能夠在任意能尋址到的位置(固然是內存了),因爲咱們一般是在SDRAM中運行程序,因此建議在SDRAM前4K完成此項任務。

  須要注意,在創建表項以前,請勿使能MMU。這樣,此時咱們使用的CPU發出的都是物理地址。

  創建哪些表項,這與應用需求相關,但都應該包括SDRAM的物理地址到虛擬地址的映射過程。由於最後程序都是要在SDRAM上運行。而後,若是你應用程序中須要使用到哪些寄存器,那麼就須要創建寄存器實際物理地址到虛擬地址的映射。

  注意上述的虛擬地址,能夠自行指定,如寄存器的虛擬地址的均可以自行定義。而SDRAM的虛擬地址,則須要與連接腳本保持一致。由於連接腳本上的地址不就是程序應該運行在的地址麼,是CPU發出的地址,此時它是虛擬地址,因此咱們須要利用此虛擬地址與實際的物理地址創建映射關係。

  第2步,將創建表項的首地址,通知給MMU。具體代碼,可參見下述

unsigned long ttb = 0x30000000;//表項地址,即爲SDRAM的起始地址
// ARM休系架構與編程
// 嵌入彙編:LINUX內核徹底註釋
__asm__(
    "mov    r0, #0\n"
    "mcr    p15, 0, r0, c7, c7, 0\n"    /* 使無效ICaches和DCaches */   
    "mcr    p15, 0, r0, c7, c10, 4\n"   /* drain write buffer on v4 */
    "mcr    p15, 0, r0, c8, c7, 0\n"    /* 使無效指令、數據TLB */   
    "mov    r4, %0\n"                   /* r4 = 頁表基址 */
    "mcr    p15, 0, r4, c2, c0, 0\n"    /* 設置頁表基址寄存器 */
    "mvn    r0, #0\n"                  
    "mcr    p15, 0, r0, c3, c0, 0\n"    /* 域訪問控制寄存器設爲0xFFFFFFFF,
                                         * 不進行權限檢查
                                         */   
    /*
     * 對於控制寄存器,先讀出其值,在這基礎上修改感興趣的位,
     * 而後再寫入
     */
    "mrc    p15, 0, r0, c1, c0, 0\n"    /* 讀出控制寄存器的值 */   
    /* 控制寄存器的低16位含義爲:.RVI ..RS B... .CAM
     * R : 表示換出Cache中的條目時使用的算法,
* 0 = Random replacement;1 = Round robin replacement * V : 表示異常向量表所在的位置, * 0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000 * I : 0 = 關閉ICaches;1 = 開啓ICaches * R、S : 用來與頁表中的描述符一塊兒肯定內存的訪問權限 * B : 0 = CPU爲小字節序;1 = CPU爲大字節序 * C : 0 = 關閉DCaches;1 = 開啓DCaches * A : 0 = 數據訪問時不進行地址對齊檢查;1 = 數據訪問時進行地址對齊檢查 * M : 0 = 關閉MMU;1 = 開啓MMU
*/ /* * 先清除不須要的位,往下若須要則從新設置它們 */ /* .RVI ..RS B... .CAM */ "bic r0, r0, #0x3000\n" /* ..11 .... .... .... 清除V、I位 */ "bic r0, r0, #0x0300\n" /* .... ..11 .... .... 清除R、S位 */ "bic r0, r0, #0x0087\n" /* .... .... 1... .111 清除B/C/A/M */ /* * 設置須要的位 */ "orr r0, r0, #0x0002\n" /* .... .... .... ..1. 開啓對齊檢查 */ "orr r0, r0, #0x0004\n" /* .... .... .... .1.. 開啓DCaches */ "orr r0, r0, #0x1000\n" /* ...1 .... .... .... 開啓ICaches */ "orr r0, r0, #0x0001\n" /* .... .... .... ...1 使能MMU */ "mcr p15, 0, r0, c1, c0, 0\n" /* 將修改的值寫入控制寄存器 */ : /* 無輸出 */ : "r" (ttb) );

  第3步,使能MMU.

 

總結:

整個過程應該是這樣的:

1 上電後,CPU自動將nandflash前4K拷貝到SRAM中。

2 從地址0開始執行代碼,完成的內容應該包括了硬件初始化(關看門狗、初始化SDRAM等)。

3 創建表項(關於如何創建表項能夠參見上述),由於咱們須要使用MMU。

4 使能MMU

5 而後LDR PC XXX跳轉到SDRAM中執行。注意此時,XXX應該是虛擬地址了,由於已經使能MMU。至於XXX的具體值 ,應該參照連接腳本指定的所謂的程序應該位於的地址運行。因此在寫連接腳本指定地址時,也應該是個虛擬地址,而不要寫實際的物理地址(0x3xxxxx)。

 

附:

運行一個點燈程序你會發現比不用MMU直接在SDRAM上運行快,這是由於在MMU中有ICache和DCache兩個存儲器

相關文章
相關標籤/搜索