U-BOOT小全(三):SPL框架

简介: U-BOOT小全(三):SPL框架

1、什么是SPL?

为了可以使已有的所有SPL的设计统一,也为了简化添加适用于新板子的设计,专门设计一个通用的SPL框架。在SPL框架下,一个板子的所有代码都能够被重用。代码复制和链接不再是必要的。

在uboot-2011的/doc/README.spl文件有简单的介绍:

Generic SPL framework
=====================
Overview
--------
To unify all existing implementations for a secondary program loader (SPL)
and to allow simply adding of new implementations this generic SPL framework
has been created. With this framework almost all source files for a board
can be reused. No code duplication or symlinking is necessary anymore.

两个点:1、为了统一所有现有实现第二段的程序加载程序(SPL-Secondary Program Loader)

2、允许简单地添加新的实现

(下面内容来自一位前辈的blog-链接在文末–感谢前辈分享)

BootROM是一级启动程序

BootROM 的代码除了去初始化硬件环境以外,还需要去外部存储器上面,将接下来可执行的程序读到内存来执行;

既然是读到内存执行,那么这个内存可以不可以是我们板载的 DDR 呢?

理论上是可以的,但是,SoC 厂家设计的 DDR 控制器呢,一般会支持很多种类型的 DDR 设备,并且会提供兼容性列表,SoC 厂家怎么可能知道用户 PCB 上到底用了哪种内存呢?

所以,直接把外部可执行程序读到 DDR 显然是不太友好的,一般来说呢,SoC 都会做一个内部的小容量的 SRAM (又是成本),BootROM 将外部的可执行程序从存储器中读出来,放到 SRAM 去执行;

那么 BootROM 从具体哪个存储器读出二进制文件呢?SoC 厂家一般会支持多种启动方式,比如从 eMMC 读取,从 SDCard 读取,从 Nand Flash 读取等等;上电的时候,需要告诉它,它需要从什么样的外设来读取后面的启动二进制文件;

一般的设计思路是,做一组 Bootstrap Pin,上电的时候呢?BootROM 去采集这几个 IO 的电平,来确认要从什么样的外部存储器来加载后续的可执行文件;

比如呢,2 个 IO,2’b00 表示从 Nand 启动,2’b01 表示从 eMMC 启动,2’b10 表示从 SDCard 启动等等;

当 BootROM 读到这些值后,就会去初始化对应的外设,然后来读取后面要执行的代码;这些 IO 一般来说,会做成板载的拨码开关,用于调整芯片的启动方式;

这里,多说一句,读取烧写的二进制的时候呢,需要注意一些细节,比如,SoC 厂家告诉你,你需要先把 SDCard 初始化称为某种文件系统,然后把东西放进去才有效,之类的;因为文件系统是组织文件的方式,并不是裸分区;你按照 A 文件系统的方式放进去,然后 SoC 的 BootROM 也按照 A 文件系统的方式读出来,才能够达成一致;

2、为什么需要SPL?

闪存技术是现在市场上最主要的非易失性存储技术之一。Intel于1988年首先开发出NOR Flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面。紧接着在1989年,东芝公司发表了NAND Flash结构,强调降低每比特的成本和更高的性能,并且像磁盘一样可以通过接口轻松升级。

NOR Flash的特点是带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节,因此支持芯片内执行(Execute In Place,XIP),这样应用程序可以直接在Flash闪存内运行,不必再把代码读到系统RAM中。NOR Flash的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。

而NAND Flash结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND Flash的困难在于其管理需要特殊的系统接口,因此NAND Flash并不支持XIP。在早期的设计中,经常有NOR Flash和NAND Flash混合使用的例子,最初的BootLoader存放在NOR Flash中,而后续的应用程序(比如内核和文件系统)放在高存储密度的NAND Flash中。

如果嵌入式系统仅仅使用NAND Flash,不再使用NOR Flash,也是有解决方法的,即使用芯片内的ROM或者其他机制加载固件到SRAM中。比如Samsung的s3c24xx系列和Allwinner的A20。s3c24xx有一块内部的4KB大小的SRAM,当采用NAND Flash方式启动时,独有的硬件机制会将位于NAND Flash最前4KB的数据自动加载到这块SRAM中,在这4KB的代码中完成NAND Flash接口的初始化,就可以实现从NAND Flash完成系统的启动了。而A20的NAND Flash采用另一种方式,使用内部的ROM。当A20从NAND Flash启动时,会显示内部ROM中代码输出的打印信息。

这种时候就需要SPL,因为SPL短小精悍,适用于4KB甚至更小的SRAM的环境。这时候的引导过程就变成:第一步由SPL引导U-Boot,第二步由U-Boot再引导系统内核。

在U-Boot源码的顶层目录下,有nand_spl目录和spl目录。如果对Samsung的s3c24xx和s3c64xx平台有一定了解的话,就明白使用nand_spl框架可以编译出基于NAND Flash启动的U-Boot。

而这里我们的A20使用最新的SPL框架。SPL框架是更加全面统一的框架。使用该框架,我们编译出u-boot-spl.bin和u-boot.bin。然后使用mksunxiboot工具将u-boot-spl.bin转换为sunxi-boot.bin,最后使用cat命令将sunxi-boot.bin和u-boot.bin拼接为u-boot-sunxi-with-spl.bin。

BootROM 会根据 Bootstrap Pin 去确定从某个存储器来读可执行的二进制文件到 SRAM 并执行;理论上来说,这个二进制文件就可以是我们的 u-boot.bin 文件了;也就是 BootROM 直接加载 u-boot.bin;

理论上是这样的,但是这里有一个问题,就是 SRAM 很贵,一般来说,SoC 的片上 SRAM 都不会太大,一般 4KB、8KB、16KB…256KB不等;但是呢,u-boot 编译出来,却很大,好几百KB,放不下!

放不下怎么办?有两种办法:

1、放不下就放不下呗,BootROM 加载多少算多少;
2、做一个小一点的 boot 程序,先让 BootROM 加载这个小的程序,后面再由这个小 boot 去加载 u-boot;

比如,我们的 u-boot 有 300KB,SRAM 有 8KB,外部 DDR 1GB:

如果使用第一种方案的话,u-boot 的前面 8K 被加载进入 SRAM 执行,u-boot 被截断,我们就需要保证在 u-boot 的前 8KB 代码,把板载的 DDR 初始化好,把整个 u-boot 拷贝到 DDR,然后跳转到 DDR 执行;

第二种方案的话,我们做一个小的 u-boot ,这个 u-boot 就叫做 spl,它很小很小(小于SRAM大小),它先被 BootROM 加载到 SRAM 运行,那么这个 spl 要做什么事情呢?最主要的就是要初始化 DDR Controller,然后将真正的大 u-boot 从外部存储器读取到 DDR 中,然后跳转到大 u-boot;

  • 0、上电后,BootROM 开始执行,初始化时钟,关闭看门狗,关 Cache,关中断等等,根据 Bootstrap Pin 来确定启动设备,初始化外设;
  • 1、使用外设驱动,从存储器读取 SPL;

---------------- 以上部分是 SoC 厂家的事情,下面是用户要做的事情 ----------------

2、SPL 被读到 SRAM 执行,此刻,控制权以及移交到我们的 SPL 了;

3、SPL 初始化外部 DDR;

4、SPL 使用驱动从外部存储器读取 u-boot 并放到 DDR;

5、跳转到 DDR 中的 u-boot 执行;

6、加载内核;

这下你应该知道这个SPL是干啥的了吧

(至于方案一,肯定是无效的,除非是UBOOT本身的前面的头部是负责加载初始化的代码,然后阶段的内容是完整可执行的,但是都和后面没有什么关联了,那还不是分开的。所以这里不用多做纠结)

这下回到起点:ROM->SPL->uboot.img,这个SPL架构将可以编译产生一个uboot-spl.bin。即BL1的代码。也就是说SPL结构其实做的工作就是uboot的BL1阶段的工作。

这里就不要把BL1和安全启动的BL1搞混淆,这是因为安全启动的粒度是更细的。

总结

ARM的启动流程:

RomBoot --> SPL --> u-boot --> Linux kernel --> file system --> start application

(RomBoot是固化在SoC内部的。)(RomBoot --》BootRom)

因为芯片厂商固化的ROM支持从nandflash, SDCARD等外部介质启动,所以RomBoot会根据硬件电路的启动模式选择读取对应介质一小段数据到内存。RomBoot读取多少才算合适呢?每个用户的需求不一样,大小也不能确定。很多芯片厂商干脆就只读4K/8K/16K等很小一段数据。这段数据你可以存放芯片初始化,读取介质数据到内存的工作是完全没有问题的。就这样在我们的软件界就产生了一个SPL概念,RomBoot读取这一小段代码就叫spl。

spl的作用:

SPL是uboot第一阶段执行的代码。 主要负责初始化芯片,搬移uboot第二阶段的代码到内存中运行。 SPL是由固化在芯片内部的ROM引导的。

(这个UBoot指的就是BoorRom后的整个引导kernel的过程)

所谓启动, 就是从这些外部介质中搬移一段固定大小(4K/8K/16K等)的代码到内部RAM中运行。 这里搬移的就是SPL. 在最新版本的uboot中, 可以看到SPL也支持nandflash, SDCARD等多种启动方式。 当SPL本身被搬移到内部RAM中运行时, 它会从nandflash, SDCARD等外部介质中搬移uboot第二阶段的代码到外部内存中。

切记SPL不能太大,不然RomBoot 无法读取完整,有些你写在spl功能无法读到内存,CPU执行不了,满足不了你的需求。

最后再重复一遍这个图

看这个图,脑子里梳理一下这个流程。


目录
相关文章
|
2月前
|
监控 Java 数据处理
Spring中的批处理:数据处理的瑞士军刀
Spring中的批处理:数据处理的瑞士军刀
83 0
|
3月前
|
存储 缓存 安全
U-BOOT小全(五):BootLoader源码(SPL-UBoot 2)
U-BOOT小全(五):BootLoader源码(SPL-UBoot 2)
35 0
|
3月前
|
Linux 编译器 C语言
U-BOOT小全(四):BootLoader源码(SPL-UBoot 1)
U-BOOT小全(四):BootLoader源码(SPL-UBoot 1)
47 0
|
6月前
|
关系型数据库 MySQL Go
Go语言微服务框架 - 8.Gormer迭代-定制专属的ORM代码生成工具
我们对比一下GORM库提供的`gorm.Model`,它在新增、修改时,会自动修改对应的时间,这个可以帮我们减少很多重复性的代码编写。这里,我就针对现有的gormer工具做一个示例性的迭代。
49 0
|
3月前
|
SQL Java 数据库连接
JAVAEE框架技术之7-myBatis ORM框架入门基础CRUD
JAVAEE框架技术之7-myBatis ORM框架入门基础CRUD
90 0
JAVAEE框架技术之7-myBatis ORM框架入门基础CRUD
|
3月前
|
网络协议 Unix Linux
U-BOOT小全(一)
U-BOOT小全(一)
43 0
|
3月前
|
存储 编译器 vr&ar
U-BOOT小全(二)
U-BOOT小全(二)
22 0
|
10月前
|
Go API 微服务
go-zero微服务框架代码生成神器goctl原理分析(一)
go-zero微服务框架代码生成神器goctl原理分析(一)
|
10月前
|
SQL 存储 关系型数据库
开源 Golang 微服务入门三:ORM 框架 GORM| 青训营笔记
GORM 是面向 Golang 语言的一种 ORM(持久层)框架,支持多种数据库的接入,此框架弱化了开发者对于 SQL 语言的掌握程度,使用提供的 API 进行底层数据库的访问。使用提供的 API 进
117 0
开源 Golang 微服务入门三:ORM 框架 GORM| 青训营笔记
|
SQL XML 存储
【框架】[Hibernate]构架知识点常见操作
【框架】[Hibernate]构架知识点常见操作
167 0