以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
前言与总结
这里说的SD卡启动方式,指的是uboot在SD卡中或者在inand里,且启动介质拨码开关选择SD卡启动方式(对于X210,是拨到远离电源键的一侧)。
uboot在SD卡的分布情况,通过将uboot烧写至SD卡的脚本可以大略知道,即uboot.bin的前16KB位于SD卡的扇区1~32,整个uboot.bin位于SD卡第49扇区开始的地方。
通过(利用fastboot将uboot镜像烧写到inand中的)操作可知,uboot在inand中仅有一个完整的镜像,不像uboot在SD卡中那样有两段且分开。我猜想,uboot也是放在inand的第1个扇区开始处。
但uboot在SD卡还是在inand中,本质应该没什么不同。因为无论uboot在SD卡还是在inand中,BL0都会从它们的第1扇区读取uboot的前16KB内容(也就是BL1)到SRAM中运行。而BL1会初始化DDR,DDR初始化之后,uboot在SD卡和在inand中,两者的区别才表现出来。当uboot位于SD卡时,BL1会从49扇区处将整个uboot拷贝至DDR中,然后利用ldr pc, =main这种远跳转方式,从SRAM中运行的BL1跳转到DDR中运行的BL2。当uboot位于inand中时,BL1是怎样操作的呢?这个应该需要了解uboot的启动过程,这里暂时不表。
1、三星推荐的启动方式
三星推荐将BL1放在SRAM中运行,将BL2也放在SRAM中运行,这意味着bootloader必须大于16KB且小于96KB。推荐即建议,但不一定要遵照。
三星推荐的启动过程
假定bootloader为80KB,则三星推荐的启动方式如下:
(1)开机上电后BL0运行,BL0会从外部启动设备(SD卡或者inand)的第1扇区处,读取bootloader的前16KB(也就是32个扇区)作为BL1加载到SRAM中运行。这是iROM中的BL0规定的,是写死的,第一步必须如此。
(2)BL1运行时,会将BL2(bootloader中80-16=64KB)加载到SRAM(SRAM中第16KB处)中运行。这是三星推荐的方法,但实际上我们没有遵循,而是在BL1中就完成DDR的初始化,并将BL2拷贝到DDR中,而不是拷贝到SRAM中,uboot就是如此。
(3)BL2运行时会初始化DDR,并且将OS搬运到DDR,然后去执行OS,启动完成。
这个过程示意图如下。
2、分散加载启动方式
分散加载的含义
如果文件大于16KB(只要大于16KB,哪怕是17KB,或者是700MB都是一样的),则需要将整个文件分割成两个独立的部分BL1和BL2,其中BL1小于等于16KB,BL2为任意大小,然后分别烧录到sd卡的不同扇区。注意,BL1在SD卡中必须从Block1开始(这个是三星官方规定的),我们定BL1为16KB(也就是32个block),则BL2理论上可以从33扇区开始,但实际上会留一些空扇区作为隔离,比如可以从45扇区开始,并根据BL2的大小来分配长度。
其中BL1在SRAM中运行,它负责将DDR初始化,然后将BL2从SD卡中加载到DDR中,然后在BL1最后(使用地址)强制跳转到BL2所在的地址,转而执行BL2。这种启动方式就叫做分散加载。
注意,DDR初始化好之后,整个DDR都可以使用了,这时在其中选择一段长度足够存储BL2的DDR空间即可,这里我们选0x23E00000,因为我们的BL1中只初始化了DDR1,地址空间范围是0x20000000~0x2FFFFFFF。
BL1和BL2其实是2个独立的程序,链接时也是独立分开链接的,因此不能使用ldr pc, =main这种通过链接地址的方式跳转到BL2。但是可以使用地址进行强制跳转,因为BL1知道BL2将被加载到哪个地址,所以BL1最后直接去执行这个地址即可。这种启动方式实现的例子,见在x210开发板上进行裸机开发的细节中第8点。
S5PV210内置的SD卡拷贝函数
因为BL0中的代码规定到SD卡第一扇区去读取BL1,所以BL1肯定得位于SD卡第一扇区开始的地方。BL2放在SD卡适当的扇区位置就好,因为(BL1将BL2从SD卡拷贝到DDR的)函数中,有一个参数表示BL2放在SD卡哪个扇区,另外一个参数表示读取多少个扇区,还有一个参数表示拷贝到DDR哪个位置,因此我们可以通过传参来设置BL1从SD卡哪个扇区读取BL2,读取多少扇区,读取到DDR哪个位置。并根据这些传参,我们可以修改(将uboot烧写至SD卡的脚本)write2sd文件烧写SD卡的哪个扇区,修改链接脚本中的链接地址。
那么BL1将BL2从SD卡拷贝到DDR的函数,是怎么来的呢?其实它是调用iROM中BL0内置的SD卡拷贝函数(通过函数指针方式来调用),这个函数的地址是0xD0037F98。当初BL0也是利用这个SD卡拷贝函数,将BL1从SD卡加载到SRAM中运行的。
分散加载的缺陷
第一,代码完全分2部分,完全独立,代码编写和组织上麻烦。
第二,无法让工程项目兼容SD卡启动和Nand启动、NorFlash启动等各种启动方式。
3、uboot的SD启动方式
uboot在sd卡的烧写情况
uboot一般大于200KB。将uboot烧录到SD卡时,先截取uboot.bin的前16KB(推荐截取这么大,因为这样就和三星推荐的一致,但实际脚本截取的是8KB)烧录到SD卡的扇区1~32(三星规定BL1必须烧写到SD卡的扇区1开始处),然后将整个uboot烧录到SD卡的某个扇区(比如49扇区)。
与分散加载的异同
由此可知,代码仍然分成BL1和BL2两部分,但是uboot是作为一个整体来组织。
这种方式能够兼容各种启动方式。
uboot的启动过程
(1)上电后BL0运行,BL0从SD卡扇区1开始读取16KB内容到SRAM中。尽管实际脚本截取8KB作为BL1烧写到SD卡,但我猜想,BL0还是会拷贝16KB到SRAM中,因为IROM中的BL0代码规定拷贝大小是16KB。
(2)BL1运行时会初始化DDR,然后从SD卡的49扇区开始拷贝整个uboot到DDR中,然后利用ldr pc, =main这种远跳转方式,从SRAM中运行的BL1跳转到DDR中运行的BL2。
(3)uboot启动后在uboot命令行中去启动OS。