U-Boot中的地址问题

今天仔细研究了一下U-Boot(版本1.3.2)启动问题中和地址相关的一些问题,写出来和大家分享。不对的地方大家提出来讨论,交流!

 
    大家都知道bootloader启动分为两个阶段,stage1和stage2,这里就不多说了,直入正题。
 
    首先是PXA270平台上。系统上电后运行的第一段程序在cpu/pxa/start.S中,我们来看看代码:
    第一步是使系统进入SVC模式(为什么要进入SVC模式,请参考 ARM Linux Kernel Boot Requirements

)。然后,执行了一个跳转指令

    bl cpu_init_crit

这就是我们今天要关注的重点了。

    请注意,对pxa270来说,上电以后运行的第一段代码是在Nor Flash中运行的,地址是0x00000000,然后执行一个BL跳转指令,跳转到什么地方了呢?我们看看反汇编后的代码:

                   bl cpu_init_crit /* we do sys-critical inits */

a3f00060: eb00001d bl a3f000dc <cpu_init_crit>

可以清楚地看到实际上是跳转到0xa3f000dc处了,再看看0xa3f000dc处是什么:

a3f000dc <cpu_init_crit>:

...................................................

可见,0xa3f000dc处的确就是cpu_init_crit了。看起来好像没什么问题,但是注意一下,0xa3f000dc这个地址是在SDRAM中,现在刚上电,SDRAM中能有什么呢?肯定不会有我们的可执行程序。所以,这里肯定不是真正地跳转到0xa3f000dc这个地址上去了。

看来还是要回到我们的汇编程序中去。看看ARM Instruction Set中关于BL指令的相关描述:

Branch instructions contain a signed 2’s complement 24 bit offset. This is shifted left two bits, sign extended to 32 bits, and added to the PC. The instruction can therefore specify a branch of +/- 32Mbytes.

即,把offset中的值左移两位,在加上当前PC的值,就是跳转的目的地址。所以,BL是一个相对寻址,只能寻址当前PC指针的+/-32M的位置。

现在再来看看上面的BL指令到底跳转到什么地方去了。看看刚才的BL指令的指令码:eb00001d,说明它的offset是0x1d。按照上面的说法,先将0x1d左移两位,那么就是0x74,再加上当前的PC指针(从反汇编文件上看是0xa3f00060+8,但是实际上是0x60+8,因为是在Flash中),那么就是0xdc了,所以,实际上跳转的目的地还是在Flash中,而并没有到SDRAM中去!

在接下来的几个地方,还用到了BL指令,如bl lowlevel_init,情况都和这个类似。接下来,看看程序是从什么地方跳转到SDRAM中执行的。

在stage1结束的时候,程序使用如下语句跳入stage2(用C语言实现的部分):

ldr pc, _start_armboot

这句的反汇编代码:

                   ldr pc, _start_armboot

a3f000c0: e51ff004 ldr pc, [pc, #-4] ; a3f000c4 <_start_armboot>
a3f000c4 <_start_armboot>: 
a3f000c4: a3f00988 mvnges r0, #2228224 ; 0x220000

ldr pc, [pc, #-4],就是把pc-4处的值放入PC中,然后跳转到PC中执行。可以看到,现在PC的值应该是(0xc0+8),那么再减去4以后就是0xc4;同样可以看到0xc4处放的值是0xa3f00988,而这个地址确实就是RAM的地址,这样就真正跳转到RAM中执行了。

下面就是0xa3f00988处的反汇编代码:

a3f00988 <start_armboot>:
a3f00988: e92d4070 stmdb {r4, r5, r6, lr}

......................................

正是我们的C语言反汇编的结果。

再来看看在S3C2410平台上从NAND启动的过程。

首先,从硬件上确定使用从NAND Flash启动。根据s3c2410的datasheet,从NAND Flash启动时,硬件会自动执行一下过程:

1. Reset is completed.
2. When the auto boot mode is enabled, the first 4 KBytes of NAND flash memory is copied onto Steppingstone 4-KB internal buffer.
3. The Steppingstone is mapped to nGCS0.
4. CPU starts to execute the boot code on the Steppingstone 4-KB internal buffer.

即,NAND Flash的前4KB内容被拷贝到一个叫Steppingstone的buffer中,然后Stppingstone被映射到nGCS0(地址就是0x00000000),然后CPU从地址0处开始执行程序。

所以,与前面的PXA270不同的地方只在执行程序前有个copy和映射的问题,这些都是硬件自动完成的,而不需要程序员干预。然后,后面的程序和在pxa270平台上执行都差不多了。

需要注意的是,在copy U-Boot的自身代码到SDRAM中时,pxa270平台和S3C2410平台上使用的方法是不一样的。但这不是我们今天讨论的重点。

综上所述,在U-Boot中,上电运行的第一段代码(汇编部分)是在Flash中运行,而C语言实现的stage2,则是在SDRAM中运行的。这其中涉及到了程序的跳转问题,汇编部分使用的相对跳转语句BL,只有到跳转到C语言的入口处,才使用了LDR PC语句,实现从Flash跳转到RAM中执行。

你可能感兴趣的:(c,汇编,Flash,语言,平台,branch)