您的位置:首页 > 编程语言

uboot系列之-----代码重定位(源码)

2013-01-06 20:56 232 查看
从上一篇我们知道,board_init_f函数的最后返回到relocate_code,调用该函数的原型是

Relocate_code(addr_sp,id,addr),再讲一下三个参数的意义:

addr_sp是地址空间里面堆栈的首地址

id是存储gd_t类型全局参数的首地址

addr是uboot的重定位地址,也就是加载地址

这三个参数的值都是在board_init_f函数里面定义好了的(具体可以参看上一篇日志《uboot系列之-----板级初始化(源码)》)。

现在跳到arch/arm/cpu/armv7/start.s中的relocate_code代码标号处。



.globl relocate_code

relocate_code:


mov r4, r0 /*save addr_sp */


mov r5, r1 /*save addr of gd */


mov r6, r2 /*save addr of destination */

这里面r0,r1和r2分别对应上面所讲的三个参数

r0 – addr_sp

r1 – id

r2 – addr

/* Setup the stack*/

stack_setup:

mov sp,r4



设置堆栈指针

adr r0,_start

#ifndef CONFIG_PRELOADER

cmp r0,r6

beq clear_bss /*skip relocation*/



#endif

adr是小范围的地址读取伪指令,这条指令也可以理解成ldr r0,=PC+x,PC是该条指令的地址,x是PC与_start标号之间的偏移量(_start-PC),_start永远位于代码的最开始,当PC>_start时,x为负值,否则x为正值。所以当代码此时还在flash中时,_start为0(内部ram),PC+x(x<0)=PC+_start-PC
= _start=0,即r0=0,如果代码此时已经在SDRAM中了(即已经拷贝过了),_start
= TEXT_BASE,r0 = TEXT_BASE。所以接下来就比较r0与r6(r6存储的重定位地址),如果相等,就说明已经拷贝过了,就跳过重定位代码,否则,就要执行重定位代码。我们这里是需要重定位的。

mov r1,r6 /*r1<-scratch for copy_loop*/

ldr r2,_TEXT_BASE

ldr r3,_bss_start_ofs

add r2,r0,r3 /*r2<-source end address*/

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



_TEXT_BASE标号处存放的是CONFIG_SYS_TEXT_BAE,改变量定义在/board/samsung/smdk4212/config.mk
值为0xc3e0_0000,不过在这段程序中好像没什么用,addr r2,r0,r3
使得r2 =r3(因为r0=0),即BSS段的开始地址,也就是代码段的结束地址。整个copy_loop循环就是将uboot代码拷贝到重定位地址处(即addr指明的地址)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: