U-Boot第一阶段关键代码理解

更新日期:2021-10-15

来源:纯净之家


系统大全为您提供
1.u-boot程序的入口地址
  要理解程序的入口地址,自然想到的是连接文件,首先看连接文件"/board/smdk2410/u-boot.lds"
  ENTRY(_start)
  SECTIONS
  {
  . = 0x00000000;
  . = ALIGN(4);
  .text :
  {
  cpu/arm920t/start.o (.text)
  *(.text)
  }
  . = ALIGN(4);
  .rodata : { *(.rodata) }
  . = ALIGN(4);
  .data : { *(.data) }
  . = ALIGN(4);
  .got : { *(.got) }
  __u_boot_cmd_start = .;
  .u_boot_cmd : { *(.u_boot_cmd) }
  __u_boot_cmd_end = .;
  . = ALIGN(4);
  __bss_start = .;
  .bss : { *(.bss) }
  _end = .;
  }
  (1) 从ENTRY(_start)可以看出u-boot的入口函数是_start
  (2) 从. = 0x00000000也许可以看出_start的地址是0x00000000,事实并不是这样的,这里的0x00000000无效,在连接的时候最终会被TETX_BASE所代替的,具体请参考u-boot根目录下的config.mk.
  (3) 网上很多说法是 _start=TEXT_BASE,我想这种说法也是正确的,实际上,不是TEXT_BASE这段代码映射到0x0的地方,其实编译器进行编译,是按照链接文件进行的。也就是说,编译的时候所有的地址都是相对于TEXT_BASE计算出来的。而这个地址是在连接文件里面指定的为0x338f0000,你可以看链接文件,可以看反汇编里面的地址,全是0x33f8XXXX的地址。
  1.1 cpu/arm920t/start.S部分代码释疑
  (1)
  [html] view plaincopy _TEXT_BASE:
  .word TEXT_BASE
  此处定义一汇编语言标签_TEXT_BASE,它的值就是 “.word TEXT_BASE” 这句代码所在的链接地址值; TEXT_BASE定义在boardsmdk2410config.mk文件中
  (即0x33F80000)。以后通过引用_TEXT_BASE即可得到TEXT_BASE的值。
  (2)
  [html] view plaincopy .globl _armboot_start
  _armboot_start:
  .word _start
  定义外部可以引用的变量_armboot_start,其值为代码“.word _start"所在的链接地址值。
  图1 u-boot.map

U-Boot第一阶段关键代码理解

 
 编译完成后,会生成u-boot.map 文件,如图1所示。图1显示_armboot_start 所指的地址值是0x33f80044。用UltraEdit打开u-boot.bin,定位到偏移0x44处(0x44由_armboot_start 所在地址0x33f80044-TEXT_BASE得到),如图2所示,此值就是_start 所指的链接地址的值 33 F8 00 00(小端模式)。
  图2 u-boot.bin

U-Boot第一阶段关键代码理解


(3)
  [html] view plaincopy .globl _bss_start
  _bss_start:
  .word __bss_start
  __bss_start 的值定义在board/smdk2410/u-boot.lds文件中:
  [html] view plaincopy . = ALIGN(4);
  __bss_start = .;
  .bss : { *(.bss) }
  _end = .;
  __bss_start = .; 表示__bss_start 值就是当前位置的值。当前位置是多少呢?从下面一句 .bss : { *(.ss) } 知道。紧接该位置后面马上就是放 bss 段数据了。所以,__bss_start 当然就是bss段的起始地址。_end 就是bss段的结束地址。
  bss是这个链接脚本的最后一个段。start.S 就是以这个段的起始地址来计算要搬运的 u-boot 代码的大小,即这个段前面的所有数据都将被搬到TEXT_BASE处,然后跳到start_armboot 处,即C语言的入口代码。__bss_start这个值是多少? 我编译后的值是0x33f979d4。可以u-boot.map文件中查到,如图3所示,bss段是从0x33f979d4开始分配的。

U-Boot第一阶段关键代码理解


由图1可知,_bss_start 所指的链接地址为0x33f80048, 该处即存储了bss段的起始地址。打开u-boot.bin,定位到偏移0x48处(0x48由_bss_start所在地址0x33f80048-TEXT_BASE得到)如图2所示,此值确为 33 F9 79 D4(小端模式)。
  2.SDRAM初始化,lowleverl_init.S
  _TEXT_BASE:
  .word TEXT_BASE
  .globl lowlevel_init
  lowlevel_init:
  /* memory control configuration */
  /* make r0 relative the current location so that it */
  /* reads SMRDATA out of FLASH rather than memory ! */
  ldr r0, =SMRDATA
  ldr r1, _TEXT_BASE
  sub r0, r0, r1
  ldr r1, =BWSCON /* Bus Width Status Controller */
  add r2, r0, #13*4
  不理解SMRDATA与_TEXT_BASE这两个地址相减之后,到底是一个什么值。为什么要相减呢?
  我们的程序是存放在Flash中的,这里面的地址称为加载地址,当然是从0x0这个地址开始,而程序中所用的标号编译时都是基于_TEXT_BASE地址,我们称为链接或运行地址。这时加载地址和运行地址不相同,所以要求我们的代码在还没有搬移到TEXT_BASE(0x33f80000)这个位置以前是不能使用这些标号。如果直接调用标号,程序就飞了,只有运行在SDRAM中才可以调用标号,因为0x33f80000在SDRAM中。所以只能找到一个相对于0x0的偏移地址出来,才能得到真正的SMRDATA定义数据,也就是说此部分代码与地址无关,是基于PC的偏移来进行的。下面来分析代码:
  ldr r0, =SMRDATA取得标号SMRDATA的绝对地址,它是大于_TEXT_BASE;ldr r1, _TEXT_BASE 取基地址(0x33f80000)。sub r0, r0, r1相减后得到SMRDATA相对于_TEXT_BASE偏移。
  3.UBOOT启动代码重定位
  #ifndef CONFIG_SKIP_RELOCATE_UBOOT
  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 */
  一直迷惑r0,r1什么时候才相等,什么时候才不等,看看adr与ldr伪指令区别
  adr是小范围的地址读取伪指令,指令将基于PC相对偏移的地址值读取到寄存器中;ldr是大范围的读取地址伪指令,用于加载32为立即数或一个地址到指定的寄存器中。
  _start的链接地址在链接的时候与各指令之间的偏移地址已经确定,与位置无关,该偏移地址是负值,因为_start始终是代码段的起始地址。假设PC所指指令的链接地址与_start之间的偏移量为x,该值为负,所以在执行adr r0,_start时,相当于ldr r0,=PC+x(x<0),这个时候r0中的值即为代码段的起始地址。因为PC中的地址是当前代码的加载地址,和它所指的指令的链接地址基于_start(代码的链接起始地址)的偏移相加后,就是代码所存储的起始地址,即加载起始地址。
在flash中运行时:r0 = PC+x = 0,这个时候r0 != r1,就需要搬运。
  在RAM中运行时:r0 = PC+x =TEXT_BASE=0x33f80000,这个时候r0 = r1,就不需要搬运.
  4.U-BOOT怎样从4Ksteppingstone跳到RAM中执行
  ldr pc, _start_armboot
  _start_armboot: .word start_armboot
  S3C2440的Nand Flash控制器会自动的把Nand Flash上的前4K数据搬移到4K内部RAM中,并把0x00000000设置内部RAM的起始地址,CPU从内部RAM的0x00000000位置开始运行。这个过程不需要程序干涉。程序员需要完成的工作,是把最核心的启动程序放在Nand Flash的前4K中。由于Nand Flash控制器从Nand Flash中搬移到内部RAM的代码是有限的,所以在启动代码的前4K里,我们必须完成S3C2410的核心配置以及把启动代码(U-BOOT)剩余部分搬到RAM中运行。
  在这之前的程序完成了核心配置及代码的拷贝,这两条语句,ldr pc, _start_armboot中start_armboot是一个函数地址,在编译的时候分配了一个绝对地址(大于0x33f80000),所以上面语句实际上是完成了一个绝对地址的跳转。跳转后进入c语言初始化。而为什么在start.S里面有很多BL,B跳转语句都没有跳出4Ksteppingstone,原因是他们都是相对于PC的偏移跳转,而不是绝对地址的跳转。
  跳转指令,arm有两种跳转方式。
  (1) mov pc <跳转地址〉
  这种向程序计数器PC直接写跳转地址,能在4GB连续空间内任意跳转。
  (2) 通过B BL BLX BX可以完成在当前指令向前或者向后32MB的地址空间的跳转(为什么是32MB呢?寄存器是32位的,此时的值是24位有符号数,所以32MB)。
  B是最简单的跳转指令。要注意的是,跳转指令的实际值不是绝对地址,而是相对地址——是相对当前PC值的一个偏移量,它的值由汇编器计算得出。BL非常常用。它在跳转之前会在寄存器LR(R14)中保存PC的当前内容。BL的经典用法如下:
  bl NEXT ; 跳转到NEXT
  ……
  NEXT:
  ……
  mov pc, lr ; 从子程序返回
  有了上面的基础在分析U-Boot源代码就简单多了!!!!!!!
  
  以上就是系统大全给大家介绍的如何使的方法都有一定的了解了吧,好了,如果大家还想了解更多的资讯,那就赶紧点击系统大全官网吧。 
 
本文来自系统大全http://www.win7cn.com/如需转载请注明!推荐:win7纯净版