程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> (6)uboot詳解——關閉緩存和mmu

(6)uboot詳解——關閉緩存和mmu

編輯:C++入門知識

(6)uboot詳解——關閉緩存和mmu


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

-

Reserved

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 bit

ROM protection

見圖1

8

S bit

System protection

見圖1

7

B bit

Big-endian/little-endian

0 = Little-endian operation

1 = Big-endian operation

6:3

-

Reserved

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


結合以上對c1寄存器的位定義的分析,我們來看看下面這個函數:
[cpp] view plaincopy
  1. void MMU_Init(void) {
  2. __asm{
  3. mov r0,#0x30000000; // r0=TTBase 即頁表的基地址 mcr p15,0,r0,c2,c0,0; // C2中存放地址轉換表基地址
  4. mvn r0, #0; // 數據取反傳送指令
  5. mcr p15,0,r0,c3,c0,0; // 訪問類型為管理者權限
  6. mrc p15,0,r0,c1,c0,0; // 讀出協處理器C1 orr r0,r0,#01; // 或操作,使最低位為1
  7. mcr p15,0,r0,c1,c0,0; // 給C1賦值 }
  8. }
函數中使用ARM寄存器r0作為和協處理器寄存器的接口。mcr p15,0,r0,c2,c0,0這句將r0中得值(0x30000000,這個是我們規劃的轉換表的基地址)放入(因此是mcr,所以是從ARM寄存器到p15協處理器寄存器)c2中。c2即是p15中的轉換表基址。
[cpp] view plaincopy
  1. mrc p15,0,r0,c1,c0,0; // 讀出協處理器C1 orr r0,r0,#01; // 或操作,使最低位為1
  2. mcr p15,0,r0,c1,c0,0; // 給C1賦值 典型的讀-改-寫三步操作,目的就是將c1寄存器的bit0置1而同時不影響其他位。根據上面的寄存器定義可知,c1的bit0為MMU enable or disable,因此該三句代碼實際上是打開了MMU。(注意MMU打開前後,地址空間發生了變化。MMU打開前程序是工作在物理地址空間的,而MMU打開後程序便工作在了虛擬地址空間)
c1中跟MMU有關的還有data cache和instruction cache的打開和關閉,S bit和 R bit聯合組成的訪問權限控制等位。另外,c1中還有其他一些我們可能會用到的信息位。
譬如:Bit7用來選擇大小端模式,bootloader中一般會有代碼,通過設置該位來告知CPU當前板子使用的是little endian or big endian。(因為該位上電默認是0,因此默認的模式為小端模式。); Bit13為上電啟動地址,也就是reset excetion復位異常的入口地址。上電默認也是0,因此默認的上電啟動地址為0x00000000。當我們使用mcr指令將該位置1時,便可以將reset exception設置到 0xffff0000,記得這個好像是為了WinCE的移植支持設計的。

 

下面是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之前,需要要做一件事,就是要將CACHE的原有的數據給清掉。因為有可能之前,裡面就有一些數據了,這個操作也是由CP15下的一個寄存器控制的。

清除完cache中的數據後,就可以關閉mmu和cache了。

接下來就是跳轉到lowlevel_init函數,進行其他的初始化。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved