嵌入式Linux引导过程之1.5——从BootRom到Xloader
--by FeCen
在开始看Xloader_Entry的代码之前,我想先总结一下从芯片上电到开始运行Xloader的代码的过程,这是我目前理解的一个过程,可能有所出入,待以后继续完善。
当系统上电之后,首先会将PC寄存器设置成BootRom里面的代码对应的一个地址。BootRom是芯片内部集成的一块很小的存储区,里面一般会固化一段启动代码。至于BootRom所占用的地址空间,每个芯片的定义可能会有所不同,具体的可以参考芯片的用户手册中的Memory Map部分的说明。在spearplus中,BootRom位于从0xFF000000到0xFFFFFFFF的16M大小的地址区间。当然,BootRom的大小不一定要那么大,这只是说,这些地方给你用了,具体你用了多少随你自己,够用就行。在spearplus里面是32k。
那么BootRom有那么大的一片地址区域可以用,具体系统上电的时候会跳转到哪一个地址去执行代码呢?这就取决于CPU的定义了。对于spearplus里面使用的ARM926EJS来说,它是这么定义的:Following reset, the ARM core starts to fetch instructions either from 0x00000000 or 0xFFFF0000 depending on the signal level of VINITHI* input signal to ARM core. If after reset VINITHI signal level is LOW then ARM core will start fetching code from address 0x00000000 otherwise ARM core will start fetching code from 0xFFFF0000. So there must be some executable code accessible from either of this address. In an embedded system, this requires some nonvolatile memory usually ROM or Flash to be present.
也就是说,ARM核在reset之后取得的第一条指令的地址取决于给ARM核输入的一个信号VINITHI,如果在设计的时候给ARM输入的VINITHI信号是低电平,那么ARM核将从0x00000000这个地址来获取它要执行的第一条指令,反之,如果给ARM输入的VINITHI信号是高电平,那么它将从0xFFFF0000地址处获取它要执行的第一条指令。
spearplus系统中(由于spearplus系统含有两个ARM核,而在系统初始启动的时候系统的控制权完全在ARM1上,此时的ARM2核是不可用的,因此在后面,我们所说的ARM核都是指ARM1核),在系统reset之后,输送给ARM核的VINITHI信号是一个高电平,因此,在我们的系统中,系统在上电之后将会去地址0xFFFF0000处获取它所要执行的第一条指令。
我们发现,0xFFFF0000正好位于上面所说的BootRom的地址区间之内,因此,我们BootRom中的第一条代码肯定是位于0xFFFF0000处的。这样在系统启动之后,就将从0xFFFF0000处取得所需要执行的第一条指令。之后就将按照BootRom预先定义好的过程往下走了。由于BootRom处的代码(我们称之为firmware,也就是在芯片出厂的时候就固化在芯片中的)我们是看不到的,因此我们只能根据文档中的描述来进行说明。
在spearplus的BootRom中,主要提供了三个功能(其他的板子或者芯片中的bootrom提供的功能应该也是类似的):
1、从NOR serial Flash引导系统
2、从NAND Flash引导系统
3、从USB引导或者更新系统
在这三个功能中,其中第3个功能我们暂且不说,因为这个是最主要使用来在最初的时候(除了BootRom之外既没有Xloader也没有U-Boot的情况时),用来将Xloader image或者uboot image烧写到相应的Flash中的。
我们这里关心的主要是第1个和第2个功能。而从本质上来说,从NAND Flash引导和从NOR serial Flash引导应该是没有差别的,最主要的是这两种Flash的读写方式不同(另外,它们之间还有一个很重要的区别那就是NOR可以按字节寻址,也就是可以直接在NOR上面运行程序,而不必拷贝到RAM中,但是NAND是按块寻址的,无法直接在其上运行程序。但是对于spearplus来说,不管是NOR还是NAND,它的做法都是先将相应的代码拷贝到RAM中),因此在将Flash中的内容加载到内存中的相应的地址中执行的时候的加载过程可能会有所区别。而对于我们的系统来说,使用的是NOR Flash,因此,这里重点分析从NOR serial Flash引导系统的情况。具体的NOR Flash和NAND Flash的差别可以参考文末的参考文章。
BootRom在开始执行程序的时候,如果被设置成从NOR引导(可以通过向spearplus芯片提供几个信号,这几个信号的组合能够指定BootRom的功能,具体参考芯片手册),那么BootRom会首先在flash的首个sector也就是第0号sector处检查是否有uboot存在,如果存在就直接跳转到uboot的代码处执行(因为在NOR上是可以直接运行程序的)。由此可见,我们甚至可以不需要Xloader,而直接就从BootRom跳转到uboot执行代码(方法是直接将uboot image烧写到flash的第0号sector)。但是我们没有这么做,我们在uboot之前又放置了一层Xloader,这么做能够提高系统的灵活性。
话说到这里,那么BootRom是怎么来判断到底在flash的第0号sector中有没有uboot image的呢?其实方法很简单,整个uboot image有两部分组成,一个部分就是由uboot源代码编译产生的目标文件(elf文件),另一部分就是一个64字节的image header,在这个image header中,有这个image的name属性、magic number属性、load address属性等等,具体的我们将在后续的文章中详细分析。这部分image header就是通过一个叫做mkimage的工具程序与之前编译链接产生的目标elf文件组合,最终生成uboot image的。而image header就位于这个uboot image的开头64个字节处,紧接着的就是elf目标文件。而BootRom就是通过这个64个字节大小的image header中的某个或者某几个字段来判断在某一个位置是否存在某一个image的。对于判断在flash的第0号sector,BootRom会首先读取头64个字节的内容,然后判断其中的name属性是不是约定的值("UBOO"或者"UBOOT"取决于实现时的约定),如果经判断确实是约定的值,那么说明在sector 0上存在uboot image,否则则认为不存在。
显然,在我们的实现方案中,是不存在uboot的,因为我们在其上还放置了一层Xloader。
因此,当BootRom发现在flash的sector 0中不存在uboot的时候,它会用同样的方法来判断其中是否存在Xloader image(同样,Xloader image也会有一个image header,事实上,Xloader image的image header的结构和uboot image的image header的结构是完全相同的),如果它判断存在Xloader image的时候,它就会将Xloader image加载到指定的SRAM的地址中(因为此时外部内存SDRAM还没有进行初始化,因此不可用,还记得我们之前分析的在Xloader中的ddr_init吗?对,SDRAM就是在那里初始化的,因此Xloader都还没有起来呢,SDRAM就更不可能被初始化了。由于每个人使用的SDRAM可能是不相同的,所以对SDRAM的初始化是不能够放在BootRom里面执行的。因此,此时只有芯片内部集成的8k的SRAM可用,因此Xloader代码必须非常短小),然后跳转到该地址执行,将控制权交给了Xloader。从这里开始,就开始执行Xloader的代码了,也就是我们最初分析的_start标号处的代码了。那么BootRom是如何知道Xloader image该加载到SRAM的哪个地址上的呢?又是如何在加载完之后跳转到这个地址的呢?问题的答案还是在那个image header身上,刚才我们说过,在header的属性里面,有一个叫做load address的属性,这个属性就是BootRom和Xloader约定的那个地址。BootRom在读取到Xloader header中的load address这个属性之后,就会将xloader elf部分加载到该地址,然后跳转到load address指定的地址上执行代码。而这个load address则是由Xloader指定的,具体体现在Xloader的Makefile中的TEXT_BASE这个参数,这个参数在Xloader使用ld进行链接的时候作为ld的参数将覆盖xloader.ldr文件中指定的代码运行起始地址,用以说明xloader指令的执行开始地址(通过ld的参数-T xloader.lds -Ttext $(TEXT_BASE)来指定),另外,这个TEXT_BASE同时还会传递给mkimage这个工具程序,使得在最作Xloader image的时候,能够正确的设置image header中的load address这个属性。这样,整个过程也就完美了。
当然,如果BootRom在flash的sector 0处没有找到xloader image,那么它就会试图从NAND flash引导(前提是在设置BootRom的功能模式的时候同时还设置了允许从NAND引导)。如果再找不到,那么系统就会进入一个死循环。
在将程序的控制权成功交给Xloader之后,就是我们现在正在分析的代码部分了。
后续部分我们将接着一步一步来分析。
参考文章:
NOR/NAND
http://blog.sina.com.cn/s/blog_53d5935e010006fl.html