第五章 虛擬內(nèi)存及緩沖區(qū)管理
在剛開始接觸TQ2440并測(cè)試TEST程序時(shí),當(dāng)時(shí)就產(chǎn)生了一個(gè)疑惑,把程序下載到NAND和SDRAM中,其中斷均能正確執(zhí)行,當(dāng)時(shí)以為,程序有可能采用了動(dòng)態(tài)添加中斷向量技術(shù),即在SDRAM中運(yùn)行時(shí)在向量0x18處添加跳轉(zhuǎn)指令的二進(jìn)制編碼。雖然能夠?qū)崿F(xiàn),但在實(shí)際編程時(shí)會(huì)非常麻煩。
ARM采用了虛擬內(nèi)存映射技術(shù)即MMU,負(fù)責(zé)虛擬地址到物理地址的映射,并提供硬件機(jī)制的內(nèi)存訪問權(quán)限檢查,通過使用CACHE及WRITE BUFFER技術(shù)縮小處理器和存儲(chǔ)系統(tǒng)的差別,從而提高系統(tǒng)的整體性能。
在系統(tǒng)加電時(shí),將ROM/FLASH映射為地址0,進(jìn)行一些初始化工作并將程序加載到SDRAM中去,然后啟用MMU,將虛擬地址0映射到SDRAM地址(0x30000000),這樣當(dāng)中斷產(chǎn)生時(shí)讀取0x18處的指令時(shí)實(shí)際讀取的是0x30000018處的指令,這樣中斷就就可以正確執(zhí)行。
S3c2440內(nèi)存管理單元有如下特征:
4種映射長(zhǎng)度,段1M、大頁64k、小頁4k,極小頁1k
指令TLB(含64個(gè)條目)、數(shù)據(jù)TLB(含64個(gè)條目)
硬件訪問頁表地址映射、權(quán)限檢查由硬件自動(dòng)完成
第一節(jié)CP15寄存器的功能及讀寫
ARM的虛擬地址管理主要通過CP15相關(guān)寄存器來實(shí)現(xiàn)的,CP15包括了16個(gè)32位寄存器,編號(hào)為0~15,實(shí)際上對(duì)于某些編號(hào)的寄存器可能對(duì)應(yīng)有多個(gè)物理寄存器,在指令編碼時(shí)指定標(biāo)志位來區(qū)分。
CP15寄存器功能
編號(hào)
MMU功能
C0
ID編碼(只讀)
C1
開啟/禁止MMU/CACHE/WRITE等功能
C2
地址轉(zhuǎn)換表基地址
C3
域訪問控制
C4
保留
C5
內(nèi)存失效狀態(tài)
C6
內(nèi)存失效狀態(tài)
C7
CACHE及WRITE控制
C8
TLB控制
C9
CACHE鎖定
C10
TLB鎖定
C11
保留
C12
保留
C13
進(jìn)程PID
C14
保留
C15
CP15寄存器的讀寫
MCR ARM寄存器到協(xié)處理器寄存器數(shù)據(jù)傳送
MRC 協(xié)處理器寄存器到ARM寄存器數(shù)據(jù)傳送
格式:
MCR/MRC P15,0,<RD>,<CRN>,<CRM>,{,<OPCODE_2>}
其中RD為ARM寄存器
CRN為協(xié)處理器寄存器
CRM附加的目標(biāo)寄存器或源操作數(shù)寄存器,用于區(qū)分一個(gè)編號(hào)的不同物理寄存器,當(dāng)指令不需要提供附加信息時(shí),將CRMC0指定為,OPCODE_2指定為0
MCR P15,0,R4,C1,C0,0 R4->C1
MRC P15,0,R4,C1,C0,0 R4<-C1
C1寄存器位相關(guān)功能
M[0]:0禁止|1啟用MMU
A[1]:0禁止地址對(duì)齊檢查|1使能地址對(duì)齊檢查
C[2]:0禁止數(shù)據(jù)CACHE|1使能數(shù)據(jù)CACHE
W[3]:0禁止寫緩沖|1使能寫緩沖
I[12]:0禁止代碼CACHE|1使能代碼CACHE
第二節(jié) 地址轉(zhuǎn)換過程
MMU地址轉(zhuǎn)換過程及描述符定義
描述符定義:
第一級(jí)段、粗頁和細(xì)頁描述符
類型
31 20
19 12
11
10
9
8 5
4
3
2
1
0
粗頁
二級(jí)頁表基地址[31:10]
Domain
1
0
1
段
物理地址基地址[31:20]
AP
Domain
1
C
B
1
0
細(xì)頁
二級(jí)頁表基地址[31:12]
Domain
1
1
1
第二級(jí)極大頁、小頁和極小頁描述符
31 16
15 12
11
10
9 8
7 6
5 4
3
2
1
0
極大
物理地址基地址[31:16]64k
Ap3
Ap2
Ap1
Ap0
C
B
0
1
小頁
物理地址基地址[31:12]4k
Ap3
Ap2
Ap1
Ap0
C
B
1
0
極小
物理地址基地址[31:10]1k
ap
C
B
1
1
虛擬地址空間到物理地址空間映射是以內(nèi)存塊為單位進(jìn)行的,即虛擬存儲(chǔ)空間中一塊連續(xù)的存儲(chǔ)空間被映射成物理存儲(chǔ)空間中同樣大小的一塊連續(xù)存儲(chǔ)空間,每一個(gè)描述符實(shí)際記錄了一個(gè)虛擬地址與物理地址之間的對(duì)應(yīng)關(guān)系,ARM支持多種地址變換。
通常,以段為單位的地址變換過程只需要一級(jí)頁表,而以頁為單位的地址變換過程還需要二級(jí)頁表。
地址轉(zhuǎn)換過程
1. 從CP15寄存器C2得到一級(jí)頁表的基地址
2. 將虛擬地址[31:20]作為頁表的索引,得到頁表中該虛擬地址的描述符。
3. 判斷該描述符是否為段描述符,如為段描述符,將該描述符[31:20]和虛擬地址[19:0]作為偏移量組成一個(gè)32位的物理地址進(jìn)行訪問。
4. 如為粗頁表描述符,則將該粗頁表描述符[31:10]作為二級(jí)頁表的基地址,并將虛擬地址[19:12]位作為索引得到在二級(jí)頁表中該虛擬地址的描述符。
判斷二級(jí)頁表符的類型
① 為極大頁描述符表將該描述符[31:16]作為基地和虛擬地址[15:0]作為偏移量得到該虛擬地址的32位物理地址進(jìn)行訪問。
② 為小頁描述符表將描述符[31:12]作為基地和虛擬地址[11:0]作為偏移量得到該虛擬地址的32位物理地址進(jìn)行訪問。
5. 如為細(xì)頁表描述符,將該組頁表描述符[31:12]作為二級(jí)頁表的基地址,并將虛擬地址[19:10]位作為索引得到在二級(jí)頁表中該虛擬地址的描述符。
判斷二級(jí)頁表符的類型
① 為大頁描述符表將該描述符[31:16]作為基地和虛擬地址[15:0]作為偏移量得到該虛擬地址的32位物理地址進(jìn)行訪問。
②為小頁描述符表將該描述符[31:12]作為基地和虛擬地址[11:0]作為偏移量得到該虛擬地址的32位物理地址進(jìn)行訪問。
③為小極頁描述符表將描述符[31:10]作為基地和虛擬地址[9:0]作為偏移量得到該虛擬地址的32位物理地址進(jìn)行訪問。
其轉(zhuǎn)換過程如下圖如示:
當(dāng)采用段描述符時(shí),虛地址[19:0]共20位作為偏移量可尋址空間為1M
當(dāng)采用二級(jí)描述符時(shí):
第一級(jí)為粗頁時(shí),虛地址[19:12]共8位作為第二級(jí)的索引量,可尋址256個(gè)第二級(jí)頁表。
1.當(dāng)?shù)诙?jí)為小頁描述符時(shí),虛地址[11:0]作為偏移量,可尋址空間2^12=4k,一個(gè)粗頁表總可尋址4k*256=1M。
2.當(dāng)?shù)诙?jí)為大頁描述符時(shí),虛地址[15:0]作為偏移量,可尋址空間2^16=64k 但是,虛地址[19:15:12]是作為第二級(jí)大頁描述符的索引,虛地址[15:0]作為偏移量,也就是說虛地址[15:12]被重復(fù)使用。我們考慮一下從0x0~0xffff(64K)空間地址的轉(zhuǎn)換問題,顯然虛地址[15:12]將從0~f,也就是說二級(jí)頁表開始的16個(gè)描述符都將被訪問,如果每個(gè)描述符定義的頁物理基地址不一致,如第二級(jí)第一個(gè)頁表定義物理基地址為0x300000000;第2個(gè)頁表為0x30001000,第16個(gè)頁表定義的物理基地址為0x300f000時(shí),0~ffff(64K)空間將被映射到0~fffff(1M)地址空間,顯然這是不正確的。為了得到正確的結(jié)果,我們可以將這粗頁表中16個(gè)連續(xù)的大頁描述符定義為同一大頁描述符,其物理基地址一致。
結(jié)論:當(dāng)采用二級(jí)頁表時(shí),索引第二級(jí)頁表虛地址和作為偏移量的虛地址有重復(fù)時(shí),其重復(fù)為n位,則第二級(jí)頁表中連續(xù)的2^n個(gè)頁表描述符必須定義為一致。如上所示[15:12]位重復(fù),n=4,則連續(xù)16個(gè)描述符必須相同。
第一級(jí)為細(xì)頁表時(shí),其情況類似,不再分析。
地址映射具體實(shí)例:
我們將以下圖所示的過程對(duì)虛擬地址0x00000018和0x30605600的轉(zhuǎn)換過程進(jìn)行詳細(xì)的說明:
TLB寄存器值0x33ffc000是整個(gè)頁表的基地址
0x00000018地址轉(zhuǎn)換:將虛地址[31:20]位0x0作為索引*4(每個(gè)描述符占4個(gè)字節(jié))再與頁表基地址相加得0x33ffc000,即頁表中第一個(gè)描述符,因?yàn)樵撁枋龇麨槎蚊枋龇?,將其[31:20]位0x300左移20位充0為0x30000000作為該段物理基地址,并將虛地址[19:0]位0x18作為偏移地址與該段物理基地相加得0x30000018。該地址就為虛地址0x18對(duì)應(yīng)的物理地址。
0x30605600地址轉(zhuǎn)換:將虛地址[31:20]位0x306作為索引*4(每個(gè)描述符占4個(gè)字節(jié))再與頁表基地址相加得0x33ffcc18,即頁表中第775個(gè)描述符,因?yàn)樵撁枋龇麨榇猪撁枋龇瑢⑵鋄31:10]位0xcffc0左移10位為0x33ff0000作為第二級(jí)頁表的基地址。再將虛地址[19:12]位0x05作為索引*4(每個(gè)描述符占4個(gè)字節(jié))與0x33ff0000相加得到該虛擬地址的第二級(jí)頁描述符地址0x33ff0014。因?yàn)樵撁枋龇麨榈诙?jí)小頁描述符,將其[31:12]位0x30605左移12位得0x30605000作為該粗頁的物理基地址,并與虛地址[11:0]位0x600作為偏移量相加得0x30605600作為該虛地址轉(zhuǎn)換后的物理地址。
描述符表的計(jì)算及添加
設(shè)定:
因?yàn)槎蚊枋龇梢杂成?M的空間,需要映射多少M(fèi)就需要多少個(gè)連續(xù)的段描述符
1. 將虛擬結(jié)束地址和起始地址右移20位(除1M)相減,得段描述符數(shù)量用來控制需要循環(huán)的次數(shù)
2. 根據(jù)TLB和虛擬起始地址得到在頁表描述符的起始地址
3. 將需要映射的物理地址右移20位(除1M)
4. 將移位后的物理地址填入起始位置頁表描述符的[31:20]位,并將描述符屬性加入描述符相應(yīng)位置[11:0]AP、Domain、CB、10(段描述符標(biāo)志)
5. 將描述符起始地址加4(描述符為4個(gè)字節(jié))指向下一個(gè)描述符
6. 將移位后的物理地址加1(實(shí)際上在基地址的位[20]加1)指向下一M物理空間。
7. 循環(huán)至第4步,至到所有描述符被賦值。
第三節(jié)Cache和寫緩沖
ARM920T有16K的數(shù)據(jù)Cache和16K的指令Cache,這兩個(gè)Cache是基本相同的,數(shù)據(jù)Cache多了一些寫回內(nèi)存的機(jī)制,后面我們以數(shù)據(jù)Cache為例來介紹Cache的基本原理。我們已經(jīng)知道,Cache中的存儲(chǔ)單位是Cache Line,ARM920T的一個(gè)Cache Line是32字節(jié),因此16K的Cache由512條Cache Line組成。要了解Cache的基本原理,我們從如何設(shè)計(jì)Cache這個(gè)問題入手。
設(shè)計(jì)Cache的一種最樸素的想法是,把VA分成以32字節(jié)為單位,從任何一個(gè)對(duì)齊到32字節(jié)地址邊界的VA開始連續(xù)的32個(gè)字節(jié)(比如0x00-0x1f,0x20-0x3f,0x40-0x5f等等)都可以緩存到512條Cache Line中的任何一條。那么一條Cache Line中的32個(gè)字節(jié)怎么知道是來自哪個(gè)VA的呢?這就需要把VA也保存在Cache中,由于這32字節(jié)的起始地址是對(duì)齊到32字節(jié)地址邊界的,末5位全為0,因此只需要保存VA[31:5]即可,這稱為VA Tag[4],Tag是VA的一部分,是Cache Line中數(shù)據(jù)的標(biāo)識(shí),表明這32字節(jié)數(shù)據(jù)來自哪個(gè)VA。這樣設(shè)計(jì)的Cache稱為全相聯(lián)Cache(Fully Associative Cache),圖示如下:
圖 17. 全相聯(lián)Cache
給定一個(gè)VA,如何在Cache中查找對(duì)應(yīng)的數(shù)據(jù)呢?首先到Cache中比較查找哪一行的Tag等于VA[31:5],找到對(duì)應(yīng)的Cache Line后,再根據(jù)VA[4:0]決定要訪問的是該Cache Line緩存的32個(gè)字節(jié)中的哪一個(gè)字節(jié)。由于有512條Cache Line,如果這個(gè)VA沒有緩存在Cache中則需要比較512次才知道,這是最壞的情況,也是最常見的情況,下面我們要改進(jìn)Cache的設(shè)計(jì)來解決這個(gè)問題。
全相聯(lián)Cache的特點(diǎn)是任何VA都可以緩存到任何一條Cache Line,給定一個(gè)VA做查找時(shí),由于它有可能緩存在512條Cache Line中的任何一條,就只好全部都找一遍了。如果限定某一個(gè)VA只允許緩存在某一條Cache Line中,那么查找的過程就快多了:檢查一下應(yīng)該緩存這個(gè)VA的那條Cache Line,看Tag一致不一致,如果一致就是Cache Hit,如果不一致就是Cache Miss,可以直接訪問物理內(nèi)存而不必再找其它Cache Line了。這種設(shè)計(jì)稱為直接映射Cache(Direct Mapped Cache),如下圖所示:
圖 18. 直接映射Cache
地址0~31應(yīng)該緩存在第1條Cache Line中,地址32~63應(yīng)該緩存在第2條Cache Line中,依此類推,地址16352~16383應(yīng)該緩存在第512條Cache Line中,下一個(gè)地址應(yīng)該是16384(16K)了,我們又回到開頭,地址16K~16K+31應(yīng)該緩存在第1條Cache Line中,地址16K+32~16K+63應(yīng)該緩存在第2條Cache Line中,依此類推,再次回到開頭的地址應(yīng)該是32K,32K~32K+31應(yīng)該緩存在第1條Cache Line中,32K+32~32K+63應(yīng)該緩存在第2條Cache Line中,依此類推。讀者應(yīng)該可以總結(jié)出規(guī)律了:給定一個(gè)VA,將它除以16K得的余數(shù)決定了它應(yīng)該緩存在哪一條Cache Line中,那么除以16K的商數(shù)部分就應(yīng)該是VA Tag,用以區(qū)別Cache Line中緩存的到底是0還是16K還是32K地址上的數(shù)據(jù)。那么除以16K的商數(shù)和余數(shù)怎么表示呢?VA[31:14]就是除以16K的商數(shù),VA[13:0]就是余數(shù),所以上圖的Tag處標(biāo)著VA[31:14]。余數(shù)VA[13:0]是16K Cache里的一個(gè)字節(jié)偏移量,而Cache是按32字節(jié)一個(gè)Cache Line組織的,所以余數(shù)中的高位VA[13:5]決定了是第幾條Cache Line,余數(shù)中的低位VA[4:0]決定了Cache Line內(nèi)的字節(jié)偏移量。驗(yàn)算一下,VA[13:5]一共是9位,作為Cache Line的編號(hào)可以表示的Cache Line數(shù)目正是512條。
直接映射Cache雖然查找速度很快,但也有缺點(diǎn)。比如,地址0~31、16K~16K+31、32K~32K+31都應(yīng)該緩存到第1條Cache Line中,假如我們程序第一次訪問地址30,地址0~31的數(shù)據(jù)就從內(nèi)存加載到第1條Cache Line,以便下次訪問能更快一些,但是我們程序第二次訪問的卻是地址32770,地址32K~32K+31的數(shù)據(jù)就要從內(nèi)存加載到第1條Cache Line,把Cache Line里原來存的地址0~31的數(shù)據(jù)替換掉,以便下次訪問能更快一些,但是我們程序第三次訪問的卻是地址16392……這樣下去,Cache起不到任何加速作用,形同虛設(shè),這種問題稱為Cache抖動(dòng)(Cache Thrash)。全相聯(lián)Cache就不會(huì)有這種問題,因?yàn)槿魏蜼A都可以緩存到任何一條Cache Line,可以把先后幾次訪問的VA緩存到不同的Cache Line,就不會(huì)相互沖突。
全相聯(lián)Cache和直接映射Cache各有優(yōu)缺點(diǎn),全相聯(lián)Cache查找很慢,但沒有抖動(dòng)問題,直接映射Cache則正相反。為了得到更好的性能,實(shí)際CPU的Cache設(shè)計(jì)是取兩者的折衷,把所有Cache Line分成若干個(gè)組,每一組有n條Cache Line,稱為n路組相聯(lián)Cache(n-way Set Associative Cache)。ARM920T采用64路組相聯(lián)Cache,如下圖所示:
圖 19. 64路組相聯(lián)Cache
有了前面兩種Cache概念的基礎(chǔ),這種Cache應(yīng)該很好理解,512條Cache Line分成8組,每組64條,地址0-31、256-587、512-543等等可以緩存到第1組64條Cache Line中的任何一條,地址32-63、288-319、544-575等等可以緩存到第2組64條Cache Line中的任何一條,依此類推。為什么說組相聯(lián)Cache是全相聯(lián)和直接映射Cache的一個(gè)折衷呢?如果把組分得很大,把全部Cache Line都分到一個(gè)組里面去,就變成了全相聯(lián)Cache;如果把組分得很小,每組只有一個(gè)Cache Line,就變成了直接映射Cache。作為練習(xí),請(qǐng)讀者自己計(jì)算一下為什么VA Tag是VA[31:8],為什么組的編號(hào)用VA[7:5]表示。
那么,為什么組相聯(lián)Cache的性能比直接映射Cache要好呢?一方面,組相聯(lián)Cache把一條Cache Line上的沖突分散到了64條Cache Line上,起到了64倍的積極作用。而另一方面,應(yīng)該緩存到同一個(gè)組的VA更多了:對(duì)于直接映射Cache,在同一個(gè)組(也就是同一條Cache Line)互相沖突的VA有4G/512個(gè);對(duì)于組相聯(lián)Cache,在同一個(gè)組(64條Cache Line)互相沖突的VA有4G/8個(gè)。從這個(gè)數(shù)量關(guān)系來看,組相聯(lián)Cache又起到了64倍的消極作用。難道這兩種作用不會(huì)完全抵銷嗎?我不打算從數(shù)學(xué)上嚴(yán)格證明,這不是本節(jié)的重點(diǎn),讀者可以通過一個(gè)生活常識(shí)的例子來理解:層數(shù)一樣多的兩棟樓,其中一棟樓是一部電梯,每層三戶,而另一棟樓是兩部電梯,每層六戶,每戶的平均人數(shù)一樣多,你認(rèn)為在哪個(gè)樓里等電梯的時(shí)間較短呢?
接下來解釋一下有關(guān)Cache寫回內(nèi)存的問題。Cache寫回內(nèi)存有兩種模式:
Write Back:Cache Line中的數(shù)據(jù)被CPU核修改時(shí)并不立刻寫回內(nèi)存,Cache Line和內(nèi)存中的數(shù)據(jù)會(huì)暫時(shí)不一致,在Cache Line中有一個(gè)Dirty位標(biāo)記這一情況。當(dāng)一條Cache Line要被其它VA的數(shù)據(jù)替換時(shí),如果不是Dirty的就直接替換掉,如果是Dirty的就先寫回內(nèi)存再替換。
Write Through:每當(dāng)CPU核修改Cache Line中的數(shù)據(jù)時(shí)就立刻寫回內(nèi)存,Cache Line和內(nèi)存中的數(shù)據(jù)總是一致的。如果有多個(gè)CPU或設(shè)備同時(shí)訪問內(nèi)存,例如采用雙口RAM,那么Cache中的數(shù)據(jù)和內(nèi)存保持一致就非常重要了,這時(shí)相關(guān)的內(nèi)存頁面通常配置為Write Through模式。
通過讀寫CP15的相關(guān)寄存器,可以對(duì)Cache做以下操作:
Clean:將Cache Line中的數(shù)據(jù)寫回內(nèi)存,清除Dirty位。在程序中的某些同步點(diǎn)上用于確保Cache Line和內(nèi)存中的數(shù)據(jù)一致。
Invalidate:在Cache Line中有一個(gè)Invalid位表示無效,將這個(gè)位置1,下次要訪問時(shí)即使VA Tag匹配也重新從內(nèi)存讀取數(shù)據(jù)。例如進(jìn)程切換時(shí)需要聲明前一個(gè)進(jìn)程緩存在Cache中的數(shù)據(jù)無效。
Lock:將某個(gè)地址的數(shù)據(jù)鎖定在Cache中,確保不被替換掉。在實(shí)時(shí)系統(tǒng)中,這樣做可以保證某個(gè)地址的數(shù)據(jù)能在一個(gè)確定的時(shí)間內(nèi)訪問到。
從Cache中查找要訪問的數(shù)據(jù)時(shí)用的是VA,但是Cache寫回內(nèi)存要用PA,如果寫回內(nèi)存時(shí)還需要查一遍頁表就太沒有效率了,所以實(shí)際上每條Cache Line中還保存了PA[31:5](PA Tag),完整的Cache構(gòu)造如下圖所示:
圖 20. PA Tag
最后解決我們前面遺留的一個(gè)問題:頁描述符中的C、B位具體是什么意思?
表 2. 頁描述符中C、B位的含義
C位為1表示允許Cache,這種情況下用B位來表示W(wǎng)rite Through還是Write Back。有些頁面不允許Cache,置C位為0,這種情況下可以用B位來選擇是否允許使用Write Buffer。Write Buffer也是一種簡(jiǎn)單的Cache,CPU核執(zhí)行寫指令時(shí)可以把數(shù)據(jù)交給Write Buffer,然后由Write Buffer負(fù)責(zé)寫回內(nèi)存,這時(shí)CPU可以執(zhí)行后續(xù)指令而不必等待寫回內(nèi)存這個(gè)較慢的操作結(jié)束。想一下,既然有Write Buffer,為什么沒有Read Buffer?
啟用MMU后地址訪問過程
當(dāng)CPU請(qǐng)求存儲(chǔ)器訪問時(shí),首先在TLB中查找虛擬地址,如果該虛擬地址對(duì)應(yīng)的地址描述符不在TLB中時(shí),讀取內(nèi)存中頁表查詢,并將該描述符添加到TLB中,如果TLB已滿,根據(jù)一定算法進(jìn)行替換。
在得到該地址描述符后,進(jìn)行如下操作:
1從描述符表中得到對(duì)應(yīng)的物理地址
2根據(jù)域訪問控制和描述符中AP位確定是否允許對(duì)該內(nèi)存進(jìn)行操作。如不,則產(chǎn)生存儲(chǔ)訪問中止中斷
3如訪問被允許,根據(jù)描述符表中CB位決定是否緩存該內(nèi)存的訪問結(jié)果,如不,則根據(jù)得到的物理地址直接訪問內(nèi)存,如允許,則首先在CACHE中查找,命中則直接讀取,如未命中,則根據(jù)物理地址直接訪問內(nèi)存,并將該數(shù)據(jù)讀取到CACHE中。
第四節(jié) 具體編程實(shí)現(xiàn)
好了,通過對(duì)以上知識(shí)的學(xué)習(xí),我們已經(jīng)對(duì)ARM地址轉(zhuǎn)換及CACHE的讀寫有了深刻的認(rèn)識(shí),因此啟動(dòng)MMU及CACHE,需要如下步驟:
1. 禁止數(shù)據(jù)CACHE,將C15中寄存器的c1寄存器C[2]清零
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(0x1<<2)
mcr p15,0,r0,c1,c0,0
2. 禁止代碼CACHE,將C15中寄存器的c1寄存器I[12]清零
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(0x1<<12)
mcr p15,0,r0,c1,c0,0
3. 禁止MMU,將C15中寄存器的c1寄存器M[0]清零
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0x1
mcr p15,0,r0,c1,c0,0
4. 使數(shù)據(jù)及代碼段CACHE無效
mcr p15,0,r0,c7,c7,0
5. 清空寫緩沖區(qū)
mcr p15,0,r0,c7,c10,4
6. 使TLB整個(gè)頁表無效
mcr p15,0,r0,c8,c7,0
7. 設(shè)置控制域
mcr p15,0,r0,c3,c0,0 R0->C3;
8. 設(shè)置進(jìn)程PID號(hào)
mcr p15,0,r0,c13,c0,0
9. 設(shè)置頁表基地址
mcr p15,0,r0,c2,c0,0 R0->C2
10. 計(jì)算描述符表并添加到TLB指定的內(nèi)存單元中
由于一級(jí)頁表由虛地址[31:20]進(jìn)行索引,共計(jì)4096個(gè)為16k,由于TQ2440開發(fā)板為64M內(nèi)存,故我們將其放在0x33ffc000處,即64M內(nèi)存的最未端的16K內(nèi)存中。
11. 在設(shè)置好頁表描述符的基礎(chǔ)上, 我們啟用地址對(duì)齊功能,將C1寄存器A[1]賦值為1
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(0x1<<1)
mcr p15,0,r0,c1,c0,0
12. 開啟MMU功能,將C1寄存器M[0]賦值為1
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0x1
mcr p15,0,r0,c1,c0,0
13. 開啟代碼及數(shù)據(jù)CACHE,將C1寄存器C[2]位,I[12]位賦值為1
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(0x1<<12+0x1<<2)
mcr p15,0,r0,c1,c0,0
經(jīng)過以上步驟,我們成功開啟了MMU及CACHE功能。在本程序中,為了能使用中斷功能,我們將0~0x20000000(32M)的地址空間映射到了0x30000000~0x32000000處,這樣當(dāng)中斷發(fā)生時(shí),CPU到0x18處執(zhí)行時(shí),實(shí)際到物理地址0x30000018處執(zhí)行,中斷就能正常運(yùn)行了。
雖然我們成功對(duì)0x0開始的地址進(jìn)行了映射,但還有一個(gè)關(guān)鍵問題未解決,當(dāng)CPU執(zhí)行mcr p15,0,r0,c1,c0,0這條指令后,MMU功能開啟,而這條指令的下一條指令已經(jīng)開始譯碼并執(zhí)行,而這條指令的地址已經(jīng)通過MMU進(jìn)行轉(zhuǎn)換,那么此時(shí)程序如何保證能得到正確的物理地址而正確執(zhí)行呢?如果我們將0x30000000映射到0x30000000,即虛擬地址與物理地址一致,顯然程序能夠正確執(zhí)行。這也是ARM推薦使用這種方法。
TQ2440-TEST程序映射關(guān)系:
通過以上分析,我們確保了程序的正確運(yùn)行,但又產(chǎn)生了新的問題,也就是說我們的程序必須保證在0x0和0x30000000均能正確運(yùn)行,對(duì)于這個(gè)問題,我在前幾章已經(jīng)做過分析。一句話,確保程序是基于PC+8+偏移量的尋址方式。
我們完全可以將0x0處的地址映射到0x30000000處,其它地址映射保持不變,即虛擬地址與物理地址一致。這樣地址映射對(duì)我們來說完全是透明的,在開發(fā)程序時(shí),我們完全可以不用考慮它,最后調(diào)用它就行。