1. 程式人生 > >MMU與cache(ARM920)

MMU與cache(ARM920)

1、虛擬地址與實體地址

        CPU通過地址來訪問記憶體中的單元,地址有虛擬地址和實體地址之分,如果CPU沒有MMU(Memory Management Unit,記憶體管理單元),或者有MMU但沒有啟用,CPU核在取指令或訪問記憶體時發出的地址將直接傳到CPU晶片的外部地址引腳上,直接被記憶體晶片(以下稱為實體記憶體,以便與虛擬記憶體區分)接收,這稱為實體地址(Physical Address,以下簡稱PA),如下圖所示。

                                                               

        如果CPU啟用了MMU,CPU核發出的地址將被MMU截獲,從CPU到MMU的地址稱為虛擬地址(Virtual Address,以下簡稱VA),而MMU將這個地址翻譯成另一個地址發到CPU晶片的外部地址引腳上,也就是將虛擬地址對映成實體地址,如下圖所示

       

                                                        

        MMU將虛擬地址對映到實體地址是以頁(Page)為單位的,對於32位CPU通常一頁為4K。例如,虛擬地址0xb700 1000~0xb700 1fff是一個頁,可能被MMU對映到實體地址0x2000~0x2fff,實體記憶體中的一個物理頁面也稱為一個頁框(Page Frame)。

2 ARM920T的CP15協處理器

        ARM920T的MMU和Cache都整合在CP15協處理器中,MMU和Cache的聯絡非常密切,我們來看看協處理器CP15的具體細節。

CP15定義了16個暫存器,暫存器的對映圖如下:

 注:暫存器位置0可以訪問兩個暫存器,通過opcode_2的值來確定。

訪問CP15協處理器的格式為

MCR/MRC{cond} P15,opcode_1,Rd,CRn,CRm,opcode_2

        對於MCR/MRC這兩條指令,其實很好記憶,M代表MOVE,R為主處理器暫存器,C代表是協處理器,方向是從右向左。MCR表示資料從暫存器到協處理器,MRC代表的是資料從協處理器到暫存器。

  1. P15 為固定值
  2. Rd為主暫存器編號
  3. CRn表示協處理器暫存器編號
  4. op_code1,op_code2,CRm與其他引數配合使用

ARM920T存在3個地址。

        MVA(Modified Virtual Address)這個概念,這屬於ARM的快速上下文切換(Fast Context Switch)機制,適用於一些小型的RTOS,每個程序的地址空間不超過32M,Linux並沒有利用快速上下文切換機制,因此在我們的討論當中,VA 和MVA不加區分,認為是相同的。

我們來詳細看看協處理器的這幾個暫存器

register0  ID code

命令格式:

MRC p15,0,Rd,c0,c0,0

暫存器的詳細格式如下

register0  Cache type

命令格式:

MRC p15,0,Rd,c0,c0,1

該暫存器的格式如下:

Isize和Dsize的域是一致的

暫存器的詳細描述如下

Register1,control register 控制暫存器

這個暫存器包含了ARM920T的控制位。

MRC p15,0,Rd,c1,c0,0 ;read control register

MCR p15,0,Rd,c1,c0,0;write control register

暫存器詳細格式如下:0bit是cache的使能位,bit2是dcache使能位,bit12是icache使能位

Register 2,translation table base(TTB)register,頁表基址暫存器。具體作用後面講

指令格式

MRC p15,0,Rd,c2,c0,0;         read TTB register 

MCR p15,0,Rd,c2,c0,0;         write TTB register

 

Register 3,domain access control register讀寫域訪問控制暫存器。

詳細解釋下文會介紹

命令格式:

MRC p15,0,Rd,c3,c0,0;         read domain 15:0 access permissions

MCR p15,0,Rd,c3,c0,0;         write domain 15:0 access permissions

Register 4,reserved

Register 5,fault status registers

Register 6,fault address registers

 

 

Register 7,cache operations register

這是cp15中最常用的暫存器

例如,在讀記憶體時,確保資料從記憶體讀取而不僅僅是從cache中讀,首先使dcache無效invalid

MCR p15 ,0,rd,c7,c6,1               rd暫存器中是要invalid的虛擬記憶體地址。

寫記憶體時,確保資料不僅僅寫入到cache中,也要寫入到記憶體中,首先要clean dcache

MCR p15 ,0,rd,c7,c10,1                   rd暫存器中是要clean的虛擬記憶體地址。

 

Register 8,TLB operations register

用來管理Translation Lookaside Buffers(TLBs),指令TLB和資料TLB

Register 9,cache lockdown register

opcode_2=0x0 訪問的是Dcache

opcode_2=0x1 訪問的是 Icache

Regiter 10,TLB lockdown register

opcode_2=0x0 訪問的是D TLB

opcode_2=0x1 訪問的是 I TLB

Register 11,12,and 14,reserved

Register 13,FCSE PID register

是快速上下文切換擴充套件暫存器。

MRC p15,0,Rd,c13,c0,0;read FCSE_PID

MCR p15,0,Rd,c13,c0,0; write FCSE_PID

3 MMU與CHACHE相關知識

        在第一章節中,我們知道了虛擬地址與實體地址的相關概念。那麼虛擬地址是如何對映成實際的實體地址的呢?這實際上是一個查表的過程。

        虛擬地址VA被分成了三段,[31:20],[19:12],[11:0]。三段都是在一個偏移值,不同的是[31:20],[19:12]用來做兩次查表索引,[11:0]用來做頁內的偏移。一頁的大小通常為4K。(這是其中一種情況,其他情況下面還會有介紹)

 

  1.  在協處理器的暫存器中,C2暫存器儲存的時TTB的值,TTB的意思時Translation Table Base,也就是頁表的基地址。這個基地址是實際的實體地址。通過它就可以找到頁表。我們稱這個頁表是一級頁表
  2. VA[31:20]欄位就是表示的是在一級頁表內的偏移,一級頁表內共4096個表項,每個表項代表的是二級頁表的實體地址。
  3. 通過第二步我們找到了二級頁表的基地址,如圖中的coarse page table(還有其他型別的二級頁表,待會兒我們將看到),VA[19:12]欄位表示的是在二級頁表內的偏移,二級頁表共256個表項,每個表項中儲存的是某一頁的實體地址。
  4. 通過第三步,我們找到了某一頁的實體地址,如圖中的small page,VA[11:0]欄位表示的是相對於頁的基地址的偏移,也就是實際的實體地址了。

        我們再來詳細看看一級頁表中的內容,一級頁表中每一項成為一級頁表描述符,一個表項佔4個位元組。頁表描述符的內容如下

最低兩bit表示的cache的格式

bit1-bit0:00 fault格式,此處的VA沒有對映到PA

bit1-bit0:10 Section格式 ,沒有二級頁表,直接對映到物理頁面。一個section是1M大頁面,[31:20]是這個1M頁面的基地址,[19:0]為0.Domain 和AP控制訪問許可權,B,C兩bit控制快取模式。下面有詳細介紹。

bit1-bit0:01 coarse格式,[31:10]為二級頁表的基地址,再用VA[19:12]作為二級頁表的索引偏移找到二級頁表,二級頁表共計256項

bit1-bit0:11 fine格式,[31:12]為二級頁表的基地址,再用VA[19:10]作為二級頁表的索引偏移找到二級頁表。

找到二級頁表之後,我們會根據二級頁表的內容找到頁的基地址,二級頁表的內容如下:

bit1-bit0:00 fault格式

bit1-bit0:01 large page,large page一頁是64k,bit[31:16]就是頁的基地址。

bit1-bit0:10 small page,small page一頁是4k,bit[31:12]就是頁的基地址

bit1-bit0:11 tiny page,tiny page的頁大小是1k,bit[31:10]就是頁的基地址

ap代表權限位,每2個bit為一組,tiny page只有一組,small page 和 large page 各有四組許可權位,這樣可以為每1/4個物理頁面分別設定不同的許可權,也就是說,Large Page可以為每16K設定不同的許可權,Small Page可以為每1K設定不同的許可權。

arm920提供了多種頁表和頁面規格,linux系統使用其中的一種,一級頁表採用coarse page table,二級頁表採用small page,也就是一頁大小為4k。

再來看一下使用這種方式的詳細過程

從上到下依次解釋如下:

    1 VA被劃分為三段用於地址對映過程,各段的長度取決於頁描述符的格式

    2 TTB暫存器中只有[31:14]位有效,低14位全為0,因此一級頁表的基地址對齊到16K地址邊界,而一級頁表的大小也是16K。

    3 一級頁表的基地址加上VA[31:20]左移兩位組裝成一個實體地址。想一想為什麼VA[31:20]要左移兩位佔據[13:2]的位置,而空出[1:0]兩位呢?型別?,4位元組對齊

   4 用這個組裝的實體地址從實體記憶體中讀取一級頁描述符,這是一個Coarse Page Table格式的描述符。

   5 通過Domain許可權檢查後,Coarse Page Table的基地址再加上VA[19:12]左移兩位組裝成一個實體地址。同樣是因為要四位元組對齊的原因。

   6 用這個組裝的實體地址從實體記憶體中讀取二級頁描述符,這是一個Small Page格式的描述符。

   7 通過AP許可權檢查後,Small Page的基地址再加上VA[11:0]就是最終的實體地址。想一想為什麼這次不左移兩位了呢?這裡要查詢的就是實際的地址了,並不要求四位元組對齊。

 下面解釋一下Domain和AP位。CP15的Domain訪問控制暫存器(見表 1 “CP15協處理器的暫存器列表”暫存器3)表示了16個域(Domain),每兩位表示一個Domain的訪問許可權,以下是該暫存器的格式:

 每個Domain的兩個位可以取值為00、01、10或11

00/10:該domain不可訪問

01:需要進一步檢查AP位

11:改domain可以直接訪問

快速上下文切換、Domain和多種規格的頁表是ARM特有的機制,是針對嵌入式系統軟體的特點而設計的,其它處理器不一定有類似的機制,例如也許沒有Domain和快速上下文切換的概念,也許只有一種規格的頁表。為了能夠在多種不同的平臺上移植,Linux核心程式碼不會利用ARM特有的這些機制。除了這些特例之外,我們在這裡介紹的其它機制都具有普遍性,讀者應重點把握具有普遍意義的基本原理和基本概念

 CP15的控制暫存器(見 “CP15協處理器的暫存器列表”暫存器1)中的S和R位與頁描述符的AP位合在一起決定訪問許可權,如下所示:

  可見,同樣的AP、S、R位對使用者模式和特權模式來說具有不同的意義,特權模式的許可權都不低於使用者模式的許可權。最後將各種由記憶體訪問產生的異常總結如下:

    Alignment Fault——以Word為單位的資料訪問指令地址未對齊到4位元組邊界,或者以Half Word為單位的資料訪問指令地址未對齊到2位元組邊界。

    Translation Fault——頁描述符的[1:0]為00,屬於Fault格式,無效表項。

    Domain Fault——一級頁描述符或Section所屬Domain的許可權位為00或10。

   Permission Fault——根據AP位和CP15暫存器1的S、R位檢查訪問許可權,若所屬Domain的許可權位為11則跳過這一步檢查。

    External Abort——匯流排異常,例如此實體地址上沒有掛RAM晶片,或者其它硬體故障。

例項

我們來看一個簡單的例子,使用最簡單的mmu功能:1M的大頁對映(只有一級頁表),簡單地址平板對映(0地址---0地址,1M地址---1M地址,也就是虛擬地址和實體地址實際上是一致的)

.equ PG_BASE,		0xF00000    /* Page table'offset is at 15MB */
.equ PG_DIR_SIZE,    0x4000

.equ MAX_PHY_SIZE,   0x10000000

.equ CACHE_DLINESIZE, 32

基本資訊設定,頁表起始地址為15M,頁表大小為16k,記憶體最大地址為256M

 

__create_sect_pt:
    mov     r0, #0
    ldr     r1, =PG_BASE
    ldr     r2, =PG_DIR_SIZE
init:
    str     r0, [r1, #0]
    add     r1, r1, #4
    subs    r2, r2, #4
    bne     init
    ldr     r1, =PG_BASE
    ldr     r2, =MAX_PHY_SIZE
    lsr     r2, r2, #20      

開始建立頁表,首先對16k頁表初始化清零,最後兩行是對256M記憶體以1M為單位進行處理,處理過程繼續向下看

 

ddr_config:
    mov     r3, #0xc00
    orr     r3, r3, r0, lsl #20
    orr     r3, r3, #0x1e
    str     r3,[r1, r0, lsl #2]
    add     r0, r0, #1
    subs    r2, r2, #1
    bne     ddr_config

    mov     r0, #0x010
    mov     r2, #0xc00
    orr     r2, r2, r0, lsl #20
    orr     r2, r2, #0x12 /* Non-Cache Non-Buffer */
    str     r2, [r1, r0, lsl #2]

        對於每個1M的空間都或上0xc12標誌,表示read/write都具有cache,write buffer模式。共執行256次,每1M空間都對映到了本身的地址。對於一些特殊地址,如果我們不想使用cache,比如對映到外設的地址空間,或者是專為DMA分配的記憶體空間,我們可以設定不適用cache,例如上面的下半部分,設定16M處的空間,不使用cache,不使用write buffer。

然後,我們就可以使能mmu和cache

__enable_caches:
     push    {r4}
     mrc     p15, 0, r4, c1, c0, 0
     orr     r4, r4, #(0x4)                      /* Enable DCache */
     orr     r4, r4, #(0x1000)           /* Enable ICache */
     mcr     p15, 0, r4, c1, c0, 0
 
     mrc     p15, 0, r4, c0, c0, 0       /* Read id reg */
     mov     r4, r4
     mov     r4, r4
 
     pop     {r4}
     bx      lr
__mmu_enable:
    ldr     r4, =PG_BASE
    mcr     p15, 0, r4, c2, c0, 0 /* Tell the MMU where to find the page table */

    orr     r0, r0, #(0x1)
    mcr     p15, 0, r0, c1, c0, 0

    mrc     p15, 0, r3, c0, c0, 0 /* Read id reg */
    mov     r3, r3
    mov     r3, r3

使能icache,dcache,並頁表的起始地址賦值給協處理器c15的c2暫存器,然後將mmu使能