从这篇文章开始,我们就来分析uboot的源码,同时来做uboot的优化
首先我们先准备好uboot的反汇编码:
arm-linux-objdump -D u-boot > uboot.asm
1. 第一步分析链接文件arch/arm/cpu/u-boot.lds:
. = 0x00000000; //定义代码段的链接地址为0,考虑到后面代码重定位,可定义为0x34000000 - 0x20000 = 0x33fe0000, 0x20000的空间留给栈
. = ALIGN(4); //当前位置4字节对齐
.text :
{
*(.__image_copy_start) //代码段起始位放__image_copy_start,该变量定义在arch/arc/lib/sections.c
//char __image_copy_start[0] __attribute__((section(".__image_copy_start")));它只是个占位符,来确定中断向量表的起始位置,在此处定义为空数组,不占空间
*(.vectors) //中断向量表,定义在arch/arm/lib/vectors.S中,定义了异常、中断的处理
arch/arm/cpu/arm920t/start.o (.text*) //这里就是我们的第一个代码文件
*(.text*)
}
2. 分析第一个代码文件arch/arm/cpu/arm920t/start.S:
.globl reset
reset:
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0 //进入SVC32模式 ,可参考ARM920T的手册
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interrupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0] //关闭看门狗
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0] //屏蔽中断
# if defined(CONFIG_S3C2410) ||defined(CONFIG_JZ2440) //屏蔽子中断,这里增加对CONFIG_JZ2440的定义
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
ldr r0,=0x4C000014 //设置分频FCLK HCLK PCLK: 1:4:8
mov r1,#0x5 //将0x3改为0x5,我们预定义的时钟为FCLK HCLK PCLK:400:100:50M
str r1,[r0]
mrc p15,0,r0,c1,c0,0 //当HDIVN不为0时,必须改变总线为异步模式,增加左侧代码
orr r0,r0,#0xc0000000
mcr p15,0,r0,c1,c0,0
bl cpu_init_crit //执行cpu_init_crit函数,该函数就在start.S中
bl _main //执行_main函数
3. 分析cpu_init_crit函数:
cpu_init_crit:
mov r0, #0 //清空I/C cache
mcr p15, 0, r0, c7, c7, 0
mcr p15, 0, r0, c8, c7, 0
mrc p15, 0, r0, c1, c0, 0 //关闭mmu 和 I/C cache
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
mov ip, lr
bl lowlevel_init //调到lowlevel_init去执行,该函数在我们board/samsung/jz2440下的lowlevel_init.S中定义
mov lr, ip
mov pc, lr
4. 分析lowlevel_init函数
.globl lowlevel_init
lowlevel_init:
ldr r0, =SMRDATA //获取SMRDATA的地址放入r0,SMRDATA存放所有的2400内存控制器的所有配置
ldr r1, =CONFIG_SYS_TEXT_BASE //获取代码段的起始地址放入r1
sub r0, r0, r1 //将SMRDATA减去代码段的起始地址后放入r0,这里因为我们把代码烧到了NOR Flash中,及起始地址为0的地方,但是在链接文件中u-boot.lds,我们定义的地址为代码的运行地址, ldr r0, =SMRDATA获取到的是运行地址,所以要减去代码段的起始地址,才是SMRDATA在NOR Flash的实际位置
ldr r1, =BWSCON //将内存控制器的地址放入r1
add r2, r0, #13*4 //r2存入的是SMRDATA的结束地址,因为SMRDATA中有13个条目
0:
ldr r3, [r0], #4 //将r0存放的值及SMRDATA的首个条目放入r3,然后r0加4,即指向SMRDATA的下一个条目
str r3, [r1], #4 //将r3的值写入r1,即将SMRDATA的首个条目存入BWSCON寄存器,r1加4即指向下一个寄存器
cmp r2, r0 //循环写入直到SMRDATA的结束
bne 0b
mov pc, lr
.ltorg
/* the literal pools origin */
SMRDATA:
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0xb1
.word 0x30
.word 0x30
lowlevel_init的主要作用就是初始化JZ2440的内存控制器
这里可以根据我们的实际硬件进行优化,在JZ2440板子上,根据NOR的手册为了加快Nor的读取速度,需要将B0_Tacc的值从0x7调为0x5,及8个clk就可以了,另外,要将REFCNT从1113调至1269,因为我们的HCLK设置为了100M,由于我们的SDRAM只有64M,所以要将SMRDATA中的倒数第三个word调为0xb1