uboot-2012.04.01移植到mini2440(一)启动流程、内存分布及重定位初步分析

编译环境:ubuntu9.10

uboot版本:u-boot-2012.04.01

开发平台:mini2440

u-boot-2012.04.01启动流程:

1. 设置为管理模式

2. 关闭看门狗

3. 关中断

4. 设置时钟分频比

5. 跳转到cpu_init_crit执行

a. 禁止MMU、关闭caches

b. 跳入到lowlevel_init执行

*. 初始化内存控制器

6. 设置堆栈,为跳入board_init_f做准备

a. 跳入board_init_f执行

*. board_init_f函数中进行了各种初始化,并重新设置了堆栈,为重定位代码做准备

*. 调用relocate_code(addr_sp, id, addr)进行代码重定位

7. bss

8. 跳转到第二阶段board_init_r执行

自此,Uboot第一阶段执行完毕。

我们知道重定位代码是在board_init_f函数中调用relocate_code(addr_sp, id, addr)函数完成的。relocate_code是用汇编实现的,根据ATPCS约定addr_spidaddr分别存放在r0r1r2寄存器中。那么这个三个参数的值是多少呢?这需要分析在relocate_code之前的代码。board_init_f是用C语言编写的,从汇编中调用C函数,必须首先设置好堆栈。

/* Set stackpointer in internal RAM tocall board_init_f */

call_board_init_f:

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)//sp =CONFIG_SYS_INIT_SP_ADDR

bic sp, sp, #7//清除sp3位,也就是8字节对齐

ldr     r0, 0x00000000//r0 = 0

bl board_init_f

其中宏定义CONFIG_SYS_INIT_SP_ADDR于文件include/configs/smdk2410.h中定义,原型为:

#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE+ 0x1000 - \

GENERATED_GBL_DATA_SIZE)

#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1

#define PHYS_SDRAM_1 0x30000000 

GENERATED_GBL_DATA_SIZE暂时未找到定义处,但它是全局数据gd_t结构体的大小。

跳入board_init_f之前内存分布如下:

接下来需要找出addraddr_sp的值是什么,代码摘抄如下:

addr =CONFIG_SYS_SDRAM_BASE + gd->ram_size; // 1.  addr = 0x3400,0000 addr -= (4096 * 4); // 2.  16k保留给TLB, addr = 0x33ff,c000 addr &= ~(0x10000 - 1); // 3.  低16位清零,64k对齐,addr = 0x33ff,0000 addr &= ~(4096 - 1); // 4.  4k对齐,addr = 0x33ff,0000 addr -= gd->mon_len; // 5.  gd->mon_len = _bss_end_ofs, bss_end_ofs定义为__bss_end__ -_start,表示整 个Uboot代码大小 addr &= ~(4096 - 1); // 6.  4k对齐

addr_sp =addr - TOTAL_MALLOC_LEN;		// 7.  留出大小为TOTAL_MALLOC_LEN内存,分配给堆
addr_sp -= sizeof (bd_t);			// 8.  留出bd_t大小的内存
bd = (bd_t *) addr_sp;				// 9.  bd指向此时add_sp
addr_sp -= sizeof (gd_t);			// 10. 留出gd_t大小的内存
id = (gd_t *) addr_sp;				// 11. gd指向此时add_sp
addr_sp -= 12;					// 12. 留出12Bytes空间
addr_sp &= ~0x07;				// 13. addr_sp 8字节对齐

 
 

另外board_init_f代码后面有memcpy(id, (void *)gd, sizeof(gd_t)),该代码会把之前设置过的gd全局变量(保存在调用board_init_f之前设置的栈中,也就是上图所示红色SP所指位置)原原本本拷贝到id所指向的内存中。此外,gd全局变量还包含有指向bd变量的指针,代码为gd->bd = bd

知道addr_spidaddr三个参数的含义后,接下来分析relocate_code函数的具体过程。

relocate_code: mov  r4, r0 /* 保存addr_sp到r4 */ mov  r5, r1 /* 保存gd地址到r5,addr指向uboot在内存中的存放地址 */ mov  r6, r2 /* 保存addr地址到r6,即需要拷贝到的位置 */ /* Set up the stack */ stack_setup: mov  sp, r4  /* sp = addr_sp, 即栈指针 */ adr  r0, _start /* r0 = 0x0000,0000,即r0指向代码段起始地址 */ cmp  r0, r6 /* 判断代码是否需要拷贝 */ beq  clear_bss /* 不需要拷贝,则跳转到clear_bss */ mov  r1, r6 /* r1为uboot需要拷贝到的位置,即addr */ ldr  r3, _bss_start_ofs // r3为除bss段外的代码大小,或者称为偏移量,定义为__bss_start - _start  add  r2, r0, r3 /* r2等于拷贝前代码的结束地址 */ copy_loop: ldmia  r0!, {r9-r10} /* copy from source address [r0]    */ stmia  r1!, {r9-r10} /* copy to   target address [r1]    */ cmp    r0, r2 /* until source end address [r2]    */ blo    copy_loop   /* BLO指令:小于(无符号数) */

上面的汇编实现了把代码从nor flash(不支持nand flash,因为nand flash不能像内存一样读)中。该版本的uboot重定位和之前版本的重定位的区别是,该uboot的链接地址不是通过_TEXT_BASE指定的,而是根据编译后uboot文件大小来确定的。所以,在上面代码执行完毕后,实际重定位的工作并未全部完成,还需要重定位诸如.rel.dyn.dynsym等各种段,这部分留待下次分析。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值