Chinaunix首页 | 论坛 | 博客
  • 博客访问: 516967
  • 博文数量: 87
  • 博客积分: 4086
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 15:55
文章分类

全部博文(87)

文章存档

2012年(3)

2010年(13)

2009年(7)

2008年(64)

我的朋友

分类: LINUX

2010-06-17 22:22:42

最近帮朋友搞一个2440的板子,到上次搞linux和U-Boot已经一年多了,很多东西不用确实是忘记的比较快,呵呵!朋友给我的板子上已经烧录好了一个U-Boot,但是自己编译了一下Linux内核,用这个烧录好的loader始终跑不起来kernel,没办法只好自己尝试着重新搞个Loader。
 
由于电脑没有并口,也没jlink等高级玩意来烧录loader到nand,所以打算用板子上烧录好的loader来启动一个新的loader,然后再用这个新启动的loader来启动linux内核。感觉比较复杂,但是没办法
 
于是就要涉及到从sdram启动loader的问题了,这个以前也搞过,但是这次做起来还是遇到一些问题,特记录下来供以后查阅。
 
由于以前对U-Boot-1.3.2版本比较熟悉,这次还是使用了该版本。首先下载下来,使用的模板还是smdk2410的。要修改的第一段代码当然还是start.S汇编文件,去掉一些9200的代码,然后就是关闭看门狗、禁止中断等操作,然后还涉及到一些频率设置等等问题,由于本篇主要讲的是如何从SDRAM启动,因此这些问题这里不做详细说明。
 
关键的地方来了,第一是要定义CONFIG_SKIP_LOWLEVEL_INIT宏,使代码不执行cpu_init_crit。记得上次写了一篇关于如何从SDRAM启动的问题,有博友问道为何不执行这段代码,我想是因为这段代码执行的是一些底层的初始化吧,因为从SDRAM启动,这些初始化已经完成,就不必执行了,而且,执行了的话貌似还会使新的loader无法从sdram启动,具体的原因我也不大清楚。
 
然后是今天要讲的重中之重,先看一段代码:
#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 */
    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
#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */

相信大家移植的时候都对这段代码比较熟悉,我在以前的博文中曾经说过从sdram启动时需要定义一个CONFIG_SKIP_RELOCATE_UBOOT宏,使代码不执行上面的这一段。但是这次我却使用了这段代码。

我们重点关注两行代码:

adr r0, _start

ldr r1, _TEXT_BASE

第一行中的_start是一个标号,定义在start.S的开头,系统复位或者刚上电时代码执行的地方;第二行中的_TEXT_BASE也是一个标号,这个标号地址处放的值是定义在board/xxxx/config.mk文件中的TEXT_BASE的值,我这里设置为0x33f00000,你可以根据自己的需要来进行调整。上面那段代码是比较这两个值,如果相同则不拷贝,直接执行;若不同,则把剩下的后面的代码拷贝到TEXT_BASE所表示的地址处,然后再执行。如果在这里我们看不出来这两行代码是什么意思,我们可以来看看反汇编后的代码,结果如下:

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:               /* relocate U-Boot to RAM       */
    adr r0, _start      /* r0 <- current position of code   */
33f000ec:   e24f00f4    sub r0, pc, #244    ; 0xf4
    ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */
33f000f0:   e51f10b8    ldr r1, [pc, #-184] ; 33f00040 <_TEXT_BASE>
    cmp     r0, r1                  /* don't reloc during debug         */
33f000f4:   e1500001    cmp r0, r1
    beq     stack_setup
33f000f8:   0a000007    beq 33f0011c

第一行被翻译成了sub r0, pc, #244,意思就是把当前pc中的值减去244,放入r0中。而当前pc的值,根据arm的流水线指令执行规则,pc在此处的值应该是在这行代码的前面8个Bytes处;第二行代码很好理解,还是以前一样的指令,表示把_TEXT_BASE这个地址处的值放入r1中,而_TEXT_BASE这个地址处的值由下列代码决定:

_TEXT_BASE:
    .word   TEXT_BASE

即这个地址处的值就是我刚才说到的在一个config.mk文件里面定义的,我这里为0x33f00000,而这个_TEXT_BASE的地址却不是由我们决定,它由编译器进行分配;但是我们并不需要关心它的地址,我们只需要关心这个地址处的值是多少就行了。

好了,现在假设我们把编译好的二进制文件下载到地址0x31000000处,然后开始执行这个loader,当运行到上面提到的第一行代码处时,pc的值应该是0x310000ec+8即为0x310000f4,然后用这个值减去244即为0x31000000,就是我们运行的新的loader开始的地址;而第二行程序中r1得到的值为0x33f00000,然后进行比较,结果当然是不同了,那么下面就会执行一段搬运代码的过程,将0x31000000处的代码搬运到TEXT_BASE指定的0x33f00000处,然后再执行下面的程序,最终会跳转到0x33f000000后面的地址中执行程序。

由上面的分析可知,如果我们本来就把待运行的loader下载到0x33f00000处,将不会执行那一段搬运过程。

因此可以得出结论:从sdram启动时,可以不屏蔽掉relocate这段代码。但是实际应用时要注意以下问题:一是待运行的loadr不能下载到现在的loader所使用的地址范围内;二是如果待运行的loader下载到的开始地址如果与运行的开始地址不同,要保证下载时loader的结尾处不能占到运行时loader的开始位置处。

下面是我一年多前写的一篇从sdram启动u-boot的博文,供大家参考:

http://blog.chinaunix.net/u1/57747/showart_1427202.html

阅读(2555) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~