启动过程概览

bootRom –> SPL –> uboot –> kernel –> file system –> init

倒着分析

上面是 ARM SOC 的启动流程。不过,我们今天我们倒着讲,从后向前捋一捋为什么是这样的流程。

  1. init 进程

为什么需要 init进程?嵌入式的定义,第一句话就是:以应用为中心。所以,整个嵌入式系统的最终目的是运行应用,而这里所说的应用在 Linux 中就是指用户空间的进程。那么,用户空间的进程总得有人来创建吧,总得有人来 fork 生出新程序吧,单应用到底不容易实现较复杂的功能。init 就扛起了这面大旗,成为了所有用户空间进程的祖先进程。

  1. file system

为什么要有文件系统呢?上面我们讲到,嵌入式的最终目的是应用,也就是一个个应用程序。那么这些应用程序存放在哪呢?当然是磁盘上,如果我们不把磁盘格式化出文件系统,就直接以二进制数值的形式一字节一字节地存放在磁盘里,可行吗?当然是可行的,不过,这种存放方式对应用程序的存取、管理几乎是灾难。文件系统能够给读写、管理带来极大的便利,所以,文件系统的存在还是很有必要的。

  1. kernel

为什么要有 kernel 呢?直接运行用户程序不就行了?答案是直接运行用户程序较容易发生错误。当有多个用户程序同时运行时,如果同时有多个进程操作同一个硬件,很可能会导致硬件异常。最简单的是读写的例子,A 进程刚向 a 地址中写了一个数据,用作暂存,准备马上读走,很不幸的是,紧接着 B 又向 a 地址中写入了一个数据,导致 A 之前存放的数据就永远地消失了。。。所以,必须要让多个进程有所联系(调度也好,进程之间交流也好),保证同时只有一个进程操作硬件。操作系统就能提供这个环境,而 kernel 又是操作系统的核心。

  1. uboot

为什么要有 uboot 呢?芯片上电直接运行 kernel 不就行了?我们来看看可行不,刚上电时,CPU 只能从 ROM 或 SRAM 中读取数据,而 ROM 的存储空间较小,难以放下整个 kernel。flash 能够放下整个 kernel,但是这些 flash( SPI flash、nand flash)一般都需要相应的驱动,CPU 才能读取它们。看起来是无解了:CPU 能直接读取的介质存不下 kernel;能存储 kernel 的flash,刚上电时 CPU 又无法直接读取。这时候想出了一个办法,那就是使用 uboot,由 uboot 来提供硬件的驱动,从 flash 中读取 kernel 放入 RAM 中运行。

  1. bootRom、SPL

但是,虽然 uboot(一般几百K) 比 kernel 小不少,但是 ROM(一般十几K) 仍然存不下。这时候又想出了一个办法,在 ROM(称为 bootRom) 中存放一段固定的代码,这段代码的作用是将 flash 中的 uboot 拷贝到 SRAM 中运行,为什么不是拷贝到 DDR 中运行呢?因为 DDR 需要初始化才能使用,初始化之前无法使用。不过 uboot 虽小, SRAM 更小,存放不下整个 uboot。这个时候就采取了一种折中的做法,拷贝 uboot 的前面一段代码到 SRAM 中运行,这段代码赶紧将 DDR 初始化好,好让完整的 uboot 得以运行。

所以,最终就形成了这种局面:CPU 上电读取 bootRom 里面的代码并执行,这段代码负责读取 flash 的前面部分数据(uboot 的前半段,也称 SPL,一般 4K)到 SRAM,SPL 负责初始化 DDR,然后将 uboot 的后半段加载到 DDR RAM,执行 uboot,uboot 负责从 flash 读取 kernel 到 RAM,然后执行 kernel,kernel 最终执行 init 程序,从而 fork 出众多的用户进程。

SPL

Secondary Program Loader,第二阶段程序加载器。第一阶段是 bootRom。

参考

嵌入式Linux 启动流程,了解一下! 一级启动、二级启动

嵌入式Linux 系统启动过程

uboot 中的spl 简单认识

基于AM335x的U-Boot/SPL 的CCS 调试