NOR Flash代码复制的过程如下主要如下:
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
/*关于这段代码的理解,我也是看了很多大牛的博客才搞明白是为什么
*首先明白_start的地址是什么,搞清楚了这个就知道基本的道理了。
*同时理解ldr这个指令什么时候是伪指令什么时候是真实的指令很重要
*LDR R1,=exp,=Number,这时为伪指令操作,而当LDR R1,[R2],LDR,R1,exp,则是真实指令
*两者的区别在于,伪指令时的是将该表达式或者数值作为地址给寄存器R1
*不是伪指令时是将该地址或者寄存器的内容加载给R1
*首先_start的实际地址是根据下载的方式决定的,当下载到Flash的时候,应该就是在0x00000000处,
而当下载到SDRAM中时
,_start的入口地址就是_TEXT_BASE中存储的值,_TEXT_BASE本身也是一个地址,里面存有数据,
这主要是实现调试的方便。
*/
relocate: /* relocate U-Boot to RAM */
/*根据_start和_TEXT_BASE的关系中内容的关系判断值是否相等*/
adr r0, _start /* r0 <- current position of code */
/*获得_start的地址,也就是找到入口地址,加载到r0,如果是Flash, r0 = 0,如果是
SDRAM,r0=TEXT_BASE*/
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
/*这里是加载_TEXT_BASE中的内容(TEXT_BASE)到r1 */
cmp r0, r1 /* don't reloc during debug */
/*比较两个数是否相等*/
beq stack_setup /*如果相等就不需要重定位,直接到堆栈设置*/
/*进行代码的复制操作,将Nor Flash中的数据复制到SDRAM中,然后在运行*/
/*确定数据的大小,由于是紧跟着_start,所以可以判断代码的大小,这个是通过相对地址实现*/
/*_armboot_start中的内容是_start,也就是一个地址值0x0(FLASH中),加载到r2*/
ldr r2, _armboot_start
/*_bss_start中的内容__bss_start,也是一个地址值,加载到r3*/
ldr r3, _bss_start
/*由于存储是连续的,因此两个段的地址差就是需要复制数据的大小*/
sub r2, r3, r2 /* r2 <- size of armboot */
/*计算代码段和读写数据段的大小,实际上只是一个相对的大小*/
add r2, r0, r2 /* r2 <- source end address */
/*将r2作为代码复制的结束地址,通过起始地址和相对大小相加获得实际的复制结束的地址*/
/*复制的过程,r0为开始地址(FLASH),r1为TEXT_BASE值的地址处(SDRAM)*/
copy_loop:
/*将FLASH中的32字节数据保存到r3-r10的寄存器中,同时r0的地址更新,上移32字节*/
ldmia r0!, {r3-r10} /* copy from source address [r0] */
/*将保存在r3-r10中内容保存到r1的值为起始地址的SDRAM中,同时更新r1,也就是使得目的
地址上移32字节*/
stmia r1!, {r3-r10} /* copy to target address [r1] */
/*比较是否复制完全*/
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
//以上的操作为第二阶段创建好了一个好的堆栈环境,能够实现C语言的操作了。
ldr pc, _start_armboot
_start_armboot: .word start_armboot//开始第二阶段的运行