今天仔细研究了一下U-Boot(版本1.3.2)启动问题中和地址相关的一些问题,写出来和大家分享。不对的地方大家提出来讨论,交流!
)。然后,执行了一个跳转指令
|
这就是我们今天要关注的重点了。
请注意,对pxa270来说,上电以后运行的第一段代码是在Nor Flash中运行的,地址是0x00000000,然后执行一个BL跳转指令,跳转到什么地方了呢?我们看看反汇编后的代码:
|
可以清楚地看到实际上是跳转到0xa3f000dc处了,再看看0xa3f000dc处是什么:
|
可见,0xa3f000dc处的确就是cpu_init_crit了。看起来好像没什么问题,但是注意一下,0xa3f000dc这个地址是在SDRAM中,现在刚上电,SDRAM中能有什么呢?肯定不会有我们的可执行程序。所以,这里肯定不是真正地跳转到0xa3f000dc这个地址上去了。
看来还是要回到我们的汇编程序中去。看看ARM Instruction Set中关于BL指令的相关描述:
|
即,把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, [pc, #-4],就是把pc-4处的值放入PC中,然后跳转到PC中执行。可以看到,现在PC的值应该是(0xc0+8),那么再减去4以后就是0xc4;同样可以看到0xc4处放的值是0xa3f00988,而这个地址确实就是RAM的地址,这样就真正跳转到RAM中执行了。
下面就是0xa3f00988处的反汇编代码:
|
正是我们的C语言反汇编的结果。
再来看看在S3C2410平台上从NAND启动的过程。
首先,从硬件上确定使用从NAND Flash启动。根据s3c2410的datasheet,从NAND Flash启动时,硬件会自动执行一下过程:
|
即,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中执行。