|||
(7)关闭MMU,cache
接着往下看:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
cpu_init_crit这段代码在U-Boot正常启动时才需要执行,若将U-Boot从RAM中启动则应该注释掉这段代码。
下面分析一下cpu_init_crit到底做了什么:
320 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
321 cpu_init_crit:
322 /*
323 * 使数据cache与指令cache无效 */
324 */
325 mov r0, #0
326 mcr p15, 0, r0, c7, c7, 0 /* 向c7写入0将使ICache与DCache无效*/
327 mcr p15, 0, r0, c8, c7, 0 /* 向c8写入0将使TLB失效 */
328
329 /*
330 * disable MMU stuff and caches
331 */
332 mrc p15, 0, r0, c1, c0, 0 /* 读出控制寄存器到r0中 */
333 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
334 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
335 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
336 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
337 mcr p15, 0, r0, c1, c0, 0 /* 保存r0到控制寄存器 */
338
339 /*
340 * before relocating, we have to setup RAM timing
341 * because memory timing is board-dependend, you will
342 * find a lowlevel_init.S in your board directory.
343 */
344 mov ip, lr
345
346 bl lowlevel_init
347
348 mov lr, ip
349 mov pc, lr
350 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
代码中的c0,c1,c7,c8都是ARM920T的协处理器CP15的寄存器。其中c7是cache控制寄存器,c8是TLB控制寄存器。325~327行代码将0写入c7、c8,使Cache,TLB内容无效。
第332~337行代码关闭了MMU。这是通过修改CP15的c1寄存器来实现的,先看CP15的c1寄存器的格式(仅列出代码中用到的位):
表 2.3 CP15的c1寄存器格式(部分)
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
. | . | V | I | . | . | R | S | B | . | . | . | . | C | A | M |
各个位的意义如下:
V : 表示异常向量表所在的位置,0:异常向量在0x00000000;1:异常向量在 0xFFFF0000
I : 0 :关闭ICaches;1 :开启ICaches
R、S : 用来与页表中的描述符一起确定内存的访问权限
B : 0 :CPU为小字节序;1 : CPU为大字节序
C : 0:关闭DCaches;1:开启DCaches
A : 0:数据访问时不进行地址对齐检查;1:数据访问时进行地址对齐检查
M : 0:关闭MMU;1:开启MMU
332~337行代码将c1的 M位置零,关闭了MMU。
(8)初始化RAM控制寄存器
其中的lowlevel_init就完成了内存初始化的工作,由于内存初始化是依赖于开发板的,因此lowlevel_init的代码一般放在board下面相应的目录中。对于mini2440,lowlevel_init在board/samsung/mini2440/lowlevel_init.S中定义如下:
45 #define BWSCON 0x48000000 /* 13个存储控制器的开始地址 */
… …
129 _TEXT_BASE:
130 .word TEXT_BASE
131
132 .globl lowlevel_init
133 lowlevel_init:
134 /* memory control configuration */
135 /* make r0 relative the current location so that it */
136 /* reads SMRDATA out of FLASH rather than memory ! */
137 ldr r0, =SMRDATA
138 ldr r1, _TEXT_BASE
139 sub r0, r0, r1 /* SMRDATA减 _TEXT_BASE就是13个寄存器的偏移地址 */
140 ldr r1, =BWSCON /* Bus Width Status Controller */
141 add r2, r0, #13*4
142 0:
143 ldr r3, [r0], #4 /*将13个寄存器的值逐一赋值给对应的寄存器*/
144 str r3, [r1], #4
145 cmp r2, r0
146 bne 0b
147
148 /* everything is fine now */
149 mov pc, lr
150
151 .ltorg
152 /* the literal pools origin */
153
154 SMRDATA: /* 下面是13个寄存器的值 */
155 .word … …
156 .word … …
… …
lowlevel_init初始化了13个寄存器来实现RAM时钟的初始化。lowlevel_init函数对于U-Boot从NAND Flash或NOR Flash启动的情况都是有效的。
U-Boot.lds链接脚本有如下代码:
.text :
{
cpu/arm920t/start.o (.text)
board/samsung/mini2440/lowlevel_init.o (.text)
board/samsung/mini2440/nand_read.o (.text)
… …
}
board/samsung/mini2440/lowlevel_init.o将被链接到cpu/arm920t/start.o后面,因此board/samsung/mini2440/lowlevel_init.o也在U-Boot的前4KB的代码中。
U-Boot在NAND Flash启动时,lowlevel_init.o将自动被读取到CPU内部4KB的内部RAM中。因此第137~146行的代码将从CPU内部RAM中复制寄存器的值到相应的寄存器中。
对于U-Boot在NOR Flash启动的情况,由于U-Boot连接时确定的地址是U-Boot在内存中的地址,而此时U-Boot还在NOR Flash中,因此还需要在NOR Flash中读取数据到RAM中。
由于NOR Flash的开始地址是0,而U-Boot的加载到内存的起始地址是TEXT_BASE,SMRDATA标号在Flash的地址就是SMRDATA-TEXT_BASE。
综上所述,lowlevel_init的作用就是将SMRDATA开始的13个值复制给开始地址[BWSCON]的13个寄存器,从而完成了存储控制器的设置。