uboot中start.S相关代码分析
重定位
——即把falsh中的代码复制到ram(sdram)中,本开发板复制到sdram中。
不管我们开发板是以什么方式启动(nor/nand)启动,都需要进行重定位
因为:
当nor启动时,因为nor的特性,只能读不能写,因此需要从定位,
当nand启动时,nand启动只把前4k代码复制到片内内存,uboot打印4k,因此需要重定位。相应继续执行4K以后的代码,就必须重定位,然后跳到重定位后的地址执行。
代码分析
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
/*这段代码是在start.S最开头*/
.globl _start
_start: b reset
解析:
1、ADR伪指令— 小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄
存器中。
在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通
常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一
条指令实现,则产生错误,编译失败。
- adr r0, _start的意思其实很简单,就是将_start(这个是代码最开始执行的)的地址赋值给r0.但是具体实现的方式就有点复杂了,对于用adr指令实现的话,说明_start这个地址,相对当前PC的偏移,应该是很小的,意思就是向前一段后者向后一段去找,肯定能找到_start这个标号地址的,此处,自己通过看代码也可以看到_start,就是在当前指令的前面,距离很近,编译后,对应汇编代码,也可以猜得出,应该是上面所说的,用sub来实现,即当前PC减去某个值,得到_start的值(在从Nor Flash启动时,对应的代码,也是在Nor Flash中,对应的物理地址是0x0,如果直接从链接地址运行时,该值就是链接地址),此时是0x0。
- cmp r0, r1 因此r0不等r1,beq不成立,所以不跳到stack_setup执行。
- ldr r2, _armboot_start //_armboot_start这个标号中的值_start赋给r2,实际就是链接地址
ldr r3, _bss_start //根据链接脚本可知这是代码段的结束地址,bss段的起始地址
sub r2, r3, r2 /计算出uboot的大小 /
add r2, r0, r2 /重定位的结束地址 / - copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
这就是循环的进行代码得复制