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 |
下面是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函数,进行其他的初始化。
点击打开链接
点击打开链接
点击打开链接
点击打开链接