重定位
——即把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 这就是循环的进行代码得复制