uboot詳解——關閉緩存和mmu
當設置完時鐘分頻以後,uboot就會執行cpu_init_crit匯編函數,這個函數的主要作用就是關閉緩存和mmu,然後調用lowlevel_init函數進行系統總線的初始化。
為什麼啟動的時候,需要關閉緩存和mmu呢?我們先了解一下他們的作用。
緩存是主存(內存)和CPU通用寄存器之間設置的一個高速的、容量相對較小的存儲器,把正在執行的指令地址附近的一部分指令或數據從主存調入這個存儲器,供CPU在一段時間內使用,以提高程序的運行速度。
mmu可以實現虛擬內存和內存保護等功能,完成對內存的操作和管理。
CACHE是高速緩沖存儲器。CPU工作速度是很快的,而外部內存是工作很慢的,所以當CPU對內存訪問的時候,是要等待內存訪問結束的。所以中間CPU就在等待,這就浪費了時間。所以在CPU和內存之間加一個CACHE,當CPU寫數據到內存中的時候,就先寫入到CACHE中,然後CACHE再寫入到內存中。CPU寫CACHE是很快的,所以就提高了寫數據的效率。讀數據的話,CPU先在CACHE中去找數據,沒有找到的話,CACHE將數據從內存中取出來,再給CPU,同時把這個數據存起來。當CPU在CACHE中找到數據的話,就直接使用這個數據,就不用再去內存中取數據了。
Caches是CPU內部的一個2級緩存,它的作用是將常用的數據和指令放在CPU內部。Caches是通過CP15管理的,剛上電的時候,CPU還不能管理Caches。上電的時候指令Cache可關閉,也可不關閉,但數據Cache一定要關閉,否則可能導致剛開始的代碼裡面,去取數據的時候,從Cache裡面取,而這時候RAM中數據還沒有Cache過來,導致數據預取異常 。說到Caches就必須提到一個關鍵字Volatile,它的本質:是告訴編譯器不要對我的代碼進行優化,作用是讓編寫者感覺變量的變化情況。因為在優化時,會將常用的代碼取出來放到Caches中,它沒有從實際的物理地址去取,它直接從CPU的緩存中去取,但常用的代碼就是為了檢測一些常用變量的變化,如果正在取數據的時候發生跳變,那麼就檢測不到變量的變化了,所以在這種情況下要用Volatile關鍵字告訴編譯器不要做優化,讓cpu每次都從實際的物理地址中去取指令。其實這也是為什麼要關閉數據緩存的原因,如果匯編指令讀取的時候緩存中的數據,而實際物理地址的數據發生了變化,將導致cpu讀取不到真實的最新的值。然而在C語言中是不會關閉Caches的,如果編寫者要檢測外界物理數據的變化,或變化太快,從Caches中取數據會有誤差,就加一個關鍵字Volatile。
同樣,在板子啟動的時候是沒有對mmu進行初始化的,而且這個時候也用不到mmu,為了避免他們影響啟動時的初始化,所以需要先關閉mmu和緩存。
2440的協處理器CP15總共有c0~c15這16個協處理器寄存器,各自具有一定的功能定義。但總的來說,cp15主要跟以下功能有關:
1、獲取device id和cache type等一些CPU相關信息。
2、MMU操作。包括MMU的使能和禁止,虛擬地址到物理地址的映射機制建立
3、訪問權限控制。主要用來實現安全機制和linux的寫時復制(copy on write)。
4、設置時鐘模式。init.S中MMU_SetAsyncBusMode和MMU_SetFastBusMode這兩個函數
和MMU有關的p15寄存器為c1(control register)和c2(TTB translation table base register)。其中c2比較簡單,就是用來儲存從虛擬地址到物理地址的地址轉換表的基地址的(轉換表存放在內存中,譬如可以放在0x30000000地址),因此我們在初始化mmu的時候,只要將規劃的轉換表基地址用mcr指令傳送到該c2寄存器即可。而c1寄存器為控制寄存器,詳細定義如下:
Register 1 - Control (read/write)
All values set to 0 at power-up.
o Bit 0 - On-chip MMU turned off (0) or on (1) 用來關閉或使能MMU
o Bit 1 - Address alignment fault disabled (0) or enabled (1) 關閉或打開地址對齊檢查
o Bit 2 - Data cache turned off (0) or on (1) 數據cache打開或關閉
o Bit 3 - Write buffer turned off (0) or on (1)
o Bit 7 - Little-endian operation if 0, big-endian if 1 用來選擇大小端格式
o Bit 8 - System bit - controls the MMU permission system
o Bit 9 - ROM bit - controls the MMU permission system bit8(S bit ) and bit9(R bit)用來管理MMU訪問權限,第3部分會詳述
o Bit 12 - Instruction cache turned off (0) or on (1)” 指令cache打開或關閉
o Bit 13 - Base location of exception registers. 0x00000000(0) or 0xffff0000(1)上電啟動地址。
o Bit 14 - Round robin replacement ,random replacement(0) or round-robin replacement(1).不太懂這個
o Bit 15 ~ Bit29 reserved
o Bit 30 nF bit bit30 和 bit31共同用來決定總線模式。 iA:nF = 00 FastBus mode
o Bit 31 iA bit
Registe bits
Name
Function
Value
31
iA bit
Asynchronous clock select
30
nF bit
notFastBus select
29:15
Read = Unpredictable
Write = should be zero
14
RR bit
Round robin replacement
0 = Random replacement
1 = Round robin replacement
13
V bit
Base location of exception register(異常寄存器基地址)
0 = Low address = 0x0000 0000
1 = High address = 0xFFFF 0000
12
I bit
Instruction cache enable
0 = Instruction cache disable
1 = Instruction cache enable
11:10
Reserved
Read = 00
Write = 00
9
R
ROM protection
8
S
System protection
7
B
Big-endian/little-endian
0 = Little-endian operation
1 = Big-endian operation
6:3
Read = 1111
Write = 1111
2
C bit
Data cache enable
0 = data cache disable
1 = data cache enable
1
A bit
Alignment fault enable
Data address alignment fault checking
(地址對齊檢查)
0 =
1 =
0
M bit
MMU enable
0 = MMU disable
1 = MMU enable
下面是uboot中關閉mmu和cache的cpu_init_crit函數:
/* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit: /* * flush v4 I/D caches */ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) orr r0, r0, #0x00000002 @ set bit 2 (A) Align orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15, 0, r0, c1, c0, 0 /* * before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a lowlevel_init.S in your board directory. */ mov ip, lr bl lowlevel_init mov lr, ip mov pc, lr #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
清除完cache中的數據後,就可以關閉mmu和cache了。
接下來就是跳轉到lowlevel_init函數,進行其他的初始化。